summaryrefslogtreecommitdiffstats
path: root/remote_cmds
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /remote_cmds
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'remote_cmds')
-rw-r--r--remote_cmds/APPLE_LICENSE370
-rw-r--r--remote_cmds/Makefile12
-rw-r--r--remote_cmds/logger.tproj/Makefile11
-rw-r--r--remote_cmds/logger.tproj/logger.1102
-rw-r--r--remote_cmds/logger.tproj/logger.c329
-rw-r--r--remote_cmds/talk.tproj/Makefile14
-rw-r--r--remote_cmds/talk.tproj/ctl.c128
-rw-r--r--remote_cmds/talk.tproj/ctl_transact.c125
-rw-r--r--remote_cmds/talk.tproj/display.c198
-rw-r--r--remote_cmds/talk.tproj/get_addrs.c71
-rw-r--r--remote_cmds/talk.tproj/get_iface.c103
-rw-r--r--remote_cmds/talk.tproj/get_names.c126
-rw-r--r--remote_cmds/talk.tproj/init_disp.c245
-rw-r--r--remote_cmds/talk.tproj/invite.c202
-rw-r--r--remote_cmds/talk.tproj/io.c188
-rw-r--r--remote_cmds/talk.tproj/look_up.c127
-rw-r--r--remote_cmds/talk.tproj/msgs.c87
-rw-r--r--remote_cmds/talk.tproj/talk.1172
-rw-r--r--remote_cmds/talk.tproj/talk.c92
-rw-r--r--remote_cmds/talk.tproj/talk.h97
-rw-r--r--remote_cmds/talk.tproj/talk_ctl.h43
-rw-r--r--remote_cmds/talkd.tproj/Makefile14
-rw-r--r--remote_cmds/talkd.tproj/announce.c179
-rw-r--r--remote_cmds/talkd.tproj/extern.h40
-rw-r--r--remote_cmds/talkd.tproj/ntalk.plist29
-rw-r--r--remote_cmds/talkd.tproj/ntalkd.898
-rw-r--r--remote_cmds/talkd.tproj/print.c96
-rw-r--r--remote_cmds/talkd.tproj/process.c279
-rw-r--r--remote_cmds/talkd.tproj/table.c241
-rw-r--r--remote_cmds/talkd.tproj/talkd.c145
-rw-r--r--remote_cmds/telnet.tproj/Makefile18
-rw-r--r--remote_cmds/telnet.tproj/authenc.c109
-rw-r--r--remote_cmds/telnet.tproj/commands.c3063
-rw-r--r--remote_cmds/telnet.tproj/defines.h56
-rw-r--r--remote_cmds/telnet.tproj/externs.h495
-rw-r--r--remote_cmds/telnet.tproj/fdset.h49
-rw-r--r--remote_cmds/telnet.tproj/general.h45
-rw-r--r--remote_cmds/telnet.tproj/krb4-proto.h230
-rw-r--r--remote_cmds/telnet.tproj/main.c379
-rw-r--r--remote_cmds/telnet.tproj/misc-proto.h80
-rw-r--r--remote_cmds/telnet.tproj/misc.h42
-rw-r--r--remote_cmds/telnet.tproj/network.c182
-rw-r--r--remote_cmds/telnet.tproj/ring.c322
-rw-r--r--remote_cmds/telnet.tproj/ring.h107
-rw-r--r--remote_cmds/telnet.tproj/sys_bsd.c1145
-rw-r--r--remote_cmds/telnet.tproj/telnet.11417
-rw-r--r--remote_cmds/telnet.tproj/telnet.c2418
-rw-r--r--remote_cmds/telnet.tproj/terminal.c242
-rw-r--r--remote_cmds/telnet.tproj/tn3270.c435
-rw-r--r--remote_cmds/telnet.tproj/types.h52
-rw-r--r--remote_cmds/telnet.tproj/utilities.c912
-rw-r--r--remote_cmds/telnetd.tproj/Makefile50
-rw-r--r--remote_cmds/telnetd.tproj/authenc.c87
-rw-r--r--remote_cmds/telnetd.tproj/defs.h258
-rw-r--r--remote_cmds/telnetd.tproj/entitlements.plist8
-rw-r--r--remote_cmds/telnetd.tproj/ext.h222
-rw-r--r--remote_cmds/telnetd.tproj/global.c52
-rw-r--r--remote_cmds/telnetd.tproj/pathnames.h56
-rw-r--r--remote_cmds/telnetd.tproj/slc.c484
-rw-r--r--remote_cmds/telnetd.tproj/state.c1631
-rw-r--r--remote_cmds/telnetd.tproj/strlcpy.c74
-rw-r--r--remote_cmds/telnetd.tproj/sys_term.c1410
-rw-r--r--remote_cmds/telnetd.tproj/telnet.plist35
-rw-r--r--remote_cmds/telnetd.tproj/telnetd.8607
-rw-r--r--remote_cmds/telnetd.tproj/telnetd.c1330
-rw-r--r--remote_cmds/telnetd.tproj/telnetd.h49
-rw-r--r--remote_cmds/telnetd.tproj/termstat.c632
-rw-r--r--remote_cmds/telnetd.tproj/utility.c1081
-rw-r--r--remote_cmds/telnetd.tproj/vasprintf.c66
-rw-r--r--remote_cmds/tftp.tproj/Makefile12
-rw-r--r--remote_cmds/tftp.tproj/extern.h38
-rw-r--r--remote_cmds/tftp.tproj/main.c920
-rw-r--r--remote_cmds/tftp.tproj/tftp.1243
-rw-r--r--remote_cmds/tftp.tproj/tftp.c742
-rw-r--r--remote_cmds/tftp.tproj/tftpsubs.c287
-rw-r--r--remote_cmds/tftp.tproj/tftpsubs.h54
-rw-r--r--remote_cmds/tftpd.tproj/DERIVED_FILES5
-rw-r--r--remote_cmds/tftpd.tproj/Makefile16
-rw-r--r--remote_cmds/tftpd.tproj/tftp.plist33
-rw-r--r--remote_cmds/tftpd.tproj/tftpd.8233
-rw-r--r--remote_cmds/tftpd.tproj/tftpd.c1238
-rw-r--r--remote_cmds/tftpd.tproj/tftpsubs.c285
-rw-r--r--remote_cmds/tftpd.tproj/tftpsubs.h48
-rw-r--r--remote_cmds/wall.tproj/Makefile16
-rw-r--r--remote_cmds/wall.tproj/ttymsg.c179
-rw-r--r--remote_cmds/wall.tproj/ttymsg.h3
-rw-r--r--remote_cmds/wall.tproj/wall.183
-rw-r--r--remote_cmds/wall.tproj/wall.c361
88 files changed, 28689 insertions, 0 deletions
diff --git a/remote_cmds/APPLE_LICENSE b/remote_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..e7aa7d0
--- /dev/null
+++ b/remote_cmds/APPLE_LICENSE
@@ -0,0 +1,370 @@
+ APPLE PUBLIC SOURCE LICENSE
+ Version 1.0 - March 16, 1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License. If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+ work which Apple Computer, Inc. ("Apple") publicly announces as
+ subject to this Apple Public Source License and which contains a
+ notice placed by Apple identifying such program or work as "Original
+ Code" and stating that it is subject to the terms of this Apple
+ Public Source License version 1.0 (or subsequent version thereof),
+ as it may be revised from time to time by Apple ("License"). As
+ used in this License:
+
+1.1 "Applicable Patents" mean: (a) in the case where Apple is the
+ grantor of rights, (i) patents or patent applications that are now
+ or hereafter acquired, owned by or assigned to Apple and (ii) whose
+ claims cover subject matter contained in the Original Code, but only
+ to the extent necessary to use, reproduce and/or distribute the
+ Original Code without infringement; and (b) in the case where You
+ are the grantor of rights, (i) patents and patent applications that
+ are now or hereafter acquired, owned by or assigned to You and (ii)
+ whose claims cover subject matter in Your Modifications, taken alone
+ or in combination with Original Code.
+
+1.2 "Covered Code" means the Original Code, Modifications, the
+ combination of Original Code and any Modifications, and/or any
+ respective portions thereof.
+
+1.3 "Deploy" means to use, sublicense or distribute Covered Code other
+ than for Your internal research and development (R&D), and includes
+ without limitation, any and all internal use or distribution of
+ Covered Code within Your business or organization except for R&D
+ use, as well as direct or indirect sublicensing or distribution of
+ Covered Code by You to any third party in any form or manner.
+
+1.4 "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+
+1.5 "Modifications" mean any addition to, deletion from, and/or change
+ to, the substance and/or structure of Covered Code. When code is
+ released as a series of files, a Modification is: (a) any addition
+ to or deletion from the contents of a file containing Covered Code;
+ and/or (b) any new file or other representation of computer program
+ statements that contains any part of Covered Code.
+
+1.6 "Original Code" means the Source Code of a program or other work
+ as originally made available by Apple under this License, including
+ the Source Code of any updates or upgrades to such programs or works
+ made available by Apple under this License, and that has been
+ expressly identified by Apple as such in the header file(s) of such
+ work.
+
+1.7 "Source Code" means the human readable form of a program or other
+ work that is suitable for making modifications to it, including all
+ modules it contains, plus any associated interface definition files,
+ scripts used to control compilation and installation of an
+ executable (object code).
+
+1.8 "You" or "Your" means an individual or a legal entity exercising
+ rights under this License. For legal entities, "You" or "Your"
+ includes any entity which controls, is controlled by, or is under
+ common control with, You, where "control" means (a) the power,
+ direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of fifty
+ percent (50%) or more of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+ and conditions of this License, Apple hereby grants You, effective
+ on the date You accept this License and download the Original Code,
+ a world-wide, royalty-free, non-exclusive license, to the extent of
+ Apple's Applicable Patents and copyrights covering the Original
+ Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+ without Modifications, solely for Your internal research and
+ development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+ instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6. You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) must notify Apple and other third parties of how to obtain Your
+Deployed Modifications by filling out and submitting the required
+information found at
+http://www.apple.com/publicsource/modifications.html; and
+
+(d) if you Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+ licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patents and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patents and other intellectual property rights owned or
+controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+ Code with other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In each such
+ instance, You must make sure the requirements of this License are
+ fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+ Section 2, no other patent rights, express or implied, are granted
+ by Apple herein. Modifications and/or Larger Works may require
+ additional patent licenses from Apple which Apple may grant in its
+ sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee
+ for, warranty, support, indemnity or liability obligations and/or
+ other rights consistent with the scope of the license granted herein
+ ("Additional Terms") to one or more recipients of Covered
+ Code. However, You may do so only on Your own behalf and as Your
+ sole responsibility, and not on behalf of Apple. You must obtain the
+ recipient's agreement that any such Additional Terms are offered by
+ You alone, and You hereby agree to indemnify, defend and hold Apple
+ harmless for any liability incurred by or claims asserted against
+ Apple by reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+ versions of this License from time to time. Each version will be
+ given a distinguishing version number. Once Original Code has been
+ published under a particular version of this License, You may
+ continue to use it under the terms of that version. You may also
+ choose to use such Original Code under the terms of any subsequent
+ version of this License published by Apple. No one other than Apple
+ has the right to modify the terms applicable to Covered Code created
+ under this License.
+
+8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or
+ in part pre-release, untested, or not fully tested works. The
+ Original Code may contain errors that could cause failures or loss
+ of data, and may be incomplete or contain inaccuracies. You
+ expressly acknowledge and agree that use of the Original Code, or
+ any portion thereof, is at Your sole and entire risk. THE ORIGINAL
+ CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT
+ OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF
+ SECTIONS 8 AND 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY
+ REFERRED TO AS "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR
+ CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY OR
+ SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT THAT
+ THE FUNCTIONS CONTAINED IN THE ORIGINAL CODE WILL MEET YOUR
+ REQUIREMENTS, OR THAT THE OPERATION OF THE ORIGINAL CODE WILL BE
+ UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE ORIGINAL CODE
+ WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN
+ BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A
+ WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. You
+ acknowledge that the Original Code is not intended for use in the
+ operation of nuclear facilities, aircraft navigation, communication
+ systems, or air traffic control machines in which case the failure
+ of the Original Code could lead to death, personal injury, or severe
+ physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement. If any of the Original Code becomes the subject of
+ a claim of infringement ("Affected Original Code"), Apple may, at
+ its sole discretion and option: (a) attempt to procure the rights
+ necessary for You to continue using the Affected Original Code; (b)
+ modify the Affected Original Code so that it is no longer
+ infringing; or (c) terminate Your rights to use the Affected
+ Original Code, effective immediately upon Apple's posting of a
+ notice to such effect on the Apple web site that is used for
+ implementation of this License.
+
+9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE
+ LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR
+ INABILITY TO USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER
+ UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE),
+ PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF
+ ESSENTIAL PURPOSE OF ANY REMEDY. In no event shall Apple's total
+ liability to You for all damages under this License exceed the
+ amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+ trademarks or trade names "Apple", "Apple Computer", "Mac OS X",
+ "Mac OS X Server" or any other trademarks or trade names belonging
+ to Apple (collectively "Apple Marks") and no Apple Marks may be
+ used to endorse or promote products derived from the Original Code
+ other than as permitted by and in strict compliance at all times
+ with Apple's third party trademark usage guidelines which are
+ posted at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Apple retains all rights, title and interest in and to
+ the Original Code and any Modifications made by or on behalf of
+ Apple ("Apple Modifications"), and such Apple Modifications will
+ not be automatically subject to this License. Apple may, at its
+ sole discretion, choose to license such Apple Modifications under
+ this License, or on different terms from those contained in this
+ License or may choose not to license them at all. Apple's
+ development, use, reproduction, modification, sublicensing and
+ distribution of Covered Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+ terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Sections 9.1 and/or 13.6(b); or (c)
+automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement
+against Apple.
+
+12.2 Effect of Termination. Upon termination, You agree to
+ immediately stop any further use, reproduction, modification and
+ distribution of the Covered Code, or Affected Original Code in the
+ case of termination under Section 9.1, and to destroy all copies of
+ the Covered Code or Affected Original Code (in the case of
+ termination under Section 9.1) that are in your possession or
+ control. All sublicenses to the Covered Code which have been
+ properly granted prior to termination shall survive any termination
+ of this License. Provisions which, by their nature, should remain
+ in effect beyond the termination of this License shall survive,
+ including but not limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and
+ 13. Neither party will be liable to the other for compensation,
+ indemnity or damages of any sort solely as a result of terminating
+ this License in accordance with its terms, and termination of this
+ License will be without prejudice to any other right or remedy of
+ either party.
+
+13. Miscellaneous.
+
+13.1 Export Law Assurances. You may not use or otherwise export or
+ re-export the Original Code except as authorized by United States
+ law and the laws of the jurisdiction in which the Original Code was
+ obtained. In particular, but without limitation, the Original Code
+ may not be exported or re-exported (a) into (or to a national or
+ resident of) any U.S. embargoed country or (b) to anyone on the
+ U.S. Treasury Department's list of Specially Designated Nationals
+ or the U.S. Department of Commerce's Table of Denial Orders. By
+ using the Original Code, You represent and warrant that You are not
+ located in, under control of, or a national or resident of any such
+ country or on any such list.
+
+13.2 Government End Users. The Covered Code is a "commercial item" as
+ defined in FAR 2.101. Government software and technical data
+ rights in the Covered Code include only those rights customarily
+ provided to the public as defined in this License. This customary
+ commercial license in technical data and software is provided in
+ accordance with FAR 12.211 (Technical Data) and 12.212 (Computer
+ Software) and, for Department of Defense purchases, DFAR
+ 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3
+ (Rights in Commercial Computer Software or Computer Software
+ Documentation). Accordingly, all U.S. Government End Users acquire
+ Covered Code with only those rights set forth herein.
+
+13.3 Relationship of Parties. This License will not be construed as
+ creating an agency, partnership, joint venture or any other form of
+ legal association between You and Apple, and You will not represent
+ to the contrary, whether expressly, by implication, appearance or
+ otherwise.
+
+13.4 Independent Development. Nothing in this License will impair
+ Apple's right to acquire, license, develop, have others develop for
+ it, market and/or distribute technology or products that perform
+ the same or similar functions as, or otherwise compete with,
+ Modifications, Larger Works, technology or products that You may
+ develop, produce, market or distribute.
+
+13.5 Waiver; Construction. Failure by Apple to enforce any provision
+ of this License will not be deemed a waiver of future enforcement
+ of that or any other provision. Any law or regulation which
+ provides that the language of a contract shall be construed against
+ the drafter will not apply to this License.
+
+13.6 Severability. (a) If for any reason a court of competent
+ jurisdiction finds any provision of this License, or portion
+ thereof, to be unenforceable, that provision of the License will be
+ enforced to the maximum extent permissible so as to effect the
+ economic benefits and intent of the parties, and the remainder of
+ this License will continue in full force and effect. (b)
+ Notwithstanding the foregoing, if applicable law prohibits or
+ restricts You from fully and/or specifically complying with
+ Sections 2 and/or 3 or prevents the enforceability of either of
+ those Sections, this License will immediately terminate and You
+ must immediately discontinue any use of the Covered Code and
+ destroy all copies of it that are in your possession or control.
+
+13.7 Dispute Resolution. Any litigation or other dispute resolution
+ between You and Apple relating to this License shall take place in
+ the Northern District of California, and You and Apple hereby
+ consent to the personal jurisdiction of, and venue in, the state
+ and federal courts within that District with respect to this
+ License. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly
+ excluded.
+
+13.8 Entire Agreement; Governing Law. This License constitutes the
+ entire agreement between the parties with respect to the subject
+ matter hereof. This License shall be governed by the laws of the
+ United States and the State of California, except that body of
+ California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+Reserved. This file contains Original Code and/or Modifications of
+Original Code as defined in and that are subject to the Apple Public
+Source License Version 1.0 (the 'License'). You may not use this file
+except in compliance with the License. Please obtain a copy of the
+License at http://www.apple.com/publicsource and read it before using
+this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+License for the specific language governing rights and limitations
+under the License."
diff --git a/remote_cmds/Makefile b/remote_cmds/Makefile
new file mode 100644
index 0000000..7347ea8
--- /dev/null
+++ b/remote_cmds/Makefile
@@ -0,0 +1,12 @@
+Project = remote_cmds
+
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+SubProjects = telnetd.tproj
+else
+SubProjects = \
+ logger.tproj\
+ talk.tproj talkd.tproj telnet.tproj telnetd.tproj tftp.tproj\
+ tftpd.tproj wall.tproj
+endif
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/logger.tproj/Makefile b/remote_cmds/logger.tproj/Makefile
new file mode 100644
index 0000000..002cb56
--- /dev/null
+++ b/remote_cmds/logger.tproj/Makefile
@@ -0,0 +1,11 @@
+Project = logger
+Install_Dir = /usr/bin
+
+CFILES = logger.c
+MANPAGES = logger.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/logger.tproj/logger.1 b/remote_cmds/logger.tproj/logger.1
new file mode 100644
index 0000000..3a942e8
--- /dev/null
+++ b/remote_cmds/logger.tproj/logger.1
@@ -0,0 +1,102 @@
+.\" $OpenBSD: logger.1,v 1.2 1996/06/26 05:35:58 deraadt Exp $
+.\" $NetBSD: logger.1,v 1.4 1994/12/22 06:26:59 jtc Exp $
+.\"
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)logger.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LOGGER 1
+.Os BSD 4.3
+.Sh NAME
+.Nm logger
+.Nd make entries in the system log
+.Sh SYNOPSIS
+.Nm logger
+.Op Fl is
+.Op Fl f Ar file
+.Op Fl p Ar pri
+.Op Fl t Ar tag
+.Op Ar message ...
+.Sh DESCRIPTION
+.Nm Logger
+provides a shell command interface to the
+.Xr syslog 3
+system log module.
+.Pp
+Options:
+.Pp
+.Bl -tag -width "message"
+.It Fl i
+Log the process id of the logger process
+with each line.
+.It Fl s
+Log the message to standard error, as well as the system log.
+.It Fl f Ar file
+Log the specified file.
+.It Fl p Ar pri
+Enter the message with the specified priority.
+The priority may be specified numerically or as a ``facility.level''
+pair.
+For example, ``\-p local3.info'' logs the message(s) as
+.Ar info Ns rmational
+level in the
+.Ar local3
+facility.
+The default is ``user.notice.''
+.It Fl t Ar tag
+Mark every line in the log with the specified
+.Ar tag .
+.It Ar message
+Write the message to log; if not specified, and the
+.Fl f
+flag is not
+provided, standard input is logged.
+.El
+.Pp
+The
+.Nm logger
+utility exits 0 on success, and >0 if an error occurs.
+.Sh EXAMPLES
+.Bd -literal -offset indent -compact
+logger System rebooted
+
+logger \-p local0.notice \-t HOSTIDM \-f /dev/idmc
+.Ed
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr syslogd 8
+.Sh STANDARDS
+The
+.Nm logger
+utility conforms to
+.St -p1003.2-92 .
diff --git a/remote_cmds/logger.tproj/logger.c b/remote_cmds/logger.tproj/logger.c
new file mode 100644
index 0000000..e3d9203
--- /dev/null
+++ b/remote_cmds/logger.tproj/logger.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/logger/logger.c,v 1.17 2008/02/05 17:34:44 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SYSLOG_NAMES
+#include <syslog.h>
+
+int decode(char *, CODE *);
+int pencode(char *);
+#ifndef __APPLE__
+static void logmessage(int, const char *, const char *, const char *);
+#endif
+static void usage(void);
+
+struct socks {
+ int sock;
+ int addrlen;
+ struct sockaddr_storage addr;
+};
+
+#ifdef INET6
+int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
+#else
+int family = PF_INET; /* protocol family (IPv4 only) */
+#endif
+int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */
+
+/*
+ * logger -- read and log utility
+ *
+ * Reads from an input and arranges to write the result on the system
+ * log.
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch, logflags, pri;
+ char *tag, *host, buf[1024];
+ const char *svcname;
+
+ tag = NULL;
+ host = NULL;
+ svcname = "syslog";
+ pri = LOG_USER | LOG_NOTICE;
+ logflags = 0;
+ unsetenv("TZ");
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "f:ip:st:")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "46Af:h:iP:p:st:")) != -1)
+#endif
+ switch((char)ch) {
+#ifndef __APPLE__
+ case '4':
+ family = PF_INET;
+ break;
+#ifdef INET6
+ case '6':
+ family = PF_INET6;
+ break;
+#endif
+ case 'A':
+ send_to_all++;
+ break;
+#endif /* __APPLE__ */
+ case 'f': /* file to log */
+ if (freopen(optarg, "r", stdin) == NULL)
+ err(1, "%s", optarg);
+ break;
+#ifndef __APPLE__
+ case 'h': /* hostname to deliver to */
+ host = optarg;
+ break;
+#endif /* __APPLE__ */
+ case 'i': /* log process id also */
+ logflags |= LOG_PID;
+ break;
+#ifndef __APPLE__
+ case 'P': /* service name or port number */
+ svcname = optarg;
+ break;
+#endif /* __APPLE__ */
+ case 'p': /* priority */
+ pri = pencode(optarg);
+ break;
+ case 's': /* log to standard error */
+ logflags |= LOG_PERROR;
+ break;
+ case 't': /* tag */
+ tag = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* setup for logging */
+ openlog(tag ? tag : getlogin(), logflags, 0);
+ (void) fclose(stdout);
+
+ /* log input line if appropriate */
+ if (argc > 0) {
+ char *p, *endp;
+ size_t len;
+
+ for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
+ len = strlen(*argv);
+ if (p + len > endp && p > buf) {
+#ifdef __APPLE__
+ syslog(pri, "%s", buf);
+#else
+ logmessage(pri, host, svcname, buf);
+#endif
+ p = buf;
+ }
+ if (len > sizeof(buf) - 1)
+#ifdef __APPLE__
+ syslog(pri, "%s", *argv++);
+#else
+ logmessage(pri, host, svcname, *argv++);
+#endif
+ else {
+ if (p != buf)
+ *p++ = ' ';
+ bcopy(*argv++, p, len);
+ *(p += len) = '\0';
+ }
+ }
+ if (p != buf)
+#ifdef __APPLE__
+ syslog(pri, "%s", buf);
+#else
+ logmessage(pri, host, svcname, buf);
+#endif
+ } else
+ while (fgets(buf, sizeof(buf), stdin) != NULL)
+#ifdef __APPLE__
+ syslog(pri, "%s", buf);
+#else
+ logmessage(pri, host, svcname, buf);
+#endif
+ exit(0);
+}
+
+#ifndef __APPLE__
+/*
+ * Send the message to syslog, either on the local host, or on a remote host
+ */
+void
+logmessage(int pri, const char *host, const char *svcname, const char *buf)
+{
+ static struct socks *socks;
+ static int nsock = 0;
+ struct addrinfo hints, *res, *r;
+ char *line;
+ int maxs, len, sock, error, i, lsent;
+
+ if (host == NULL) {
+ syslog(pri, "%s", buf);
+ return;
+ }
+
+ if (nsock <= 0) { /* set up socket stuff */
+ /* resolve hostname */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo(host, svcname, &hints, &res);
+ if (error == EAI_SERVICE) {
+ warnx("%s/udp: unknown service", svcname);
+ error = getaddrinfo(host, "514", &hints, &res);
+ }
+ if (error)
+ errx(1, "%s: %s", gai_strerror(error), host);
+ /* count max number of sockets we may open */
+ for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
+ socks = malloc(maxs * sizeof(struct socks));
+ if (!socks)
+ errx(1, "couldn't allocate memory for sockets");
+ for (r = res; r; r = r->ai_next) {
+ sock = socket(r->ai_family, r->ai_socktype,
+ r->ai_protocol);
+ if (sock < 0)
+ continue;
+ memcpy(&socks[nsock].addr, r->ai_addr, r->ai_addrlen);
+ socks[nsock].addrlen = r->ai_addrlen;
+ socks[nsock++].sock = sock;
+ }
+ freeaddrinfo(res);
+ if (nsock <= 0)
+ errx(1, "socket");
+ }
+
+ if ((len = asprintf(&line, "<%d>%s", pri, buf)) == -1)
+ errx(1, "asprintf");
+
+ lsent = -1;
+ for (i = 0; i < nsock; ++i) {
+ lsent = sendto(socks[i].sock, line, len, 0,
+ (struct sockaddr *)&socks[i].addr,
+ socks[i].addrlen);
+ if (lsent == len && !send_to_all)
+ break;
+ }
+ if (lsent != len) {
+ if (lsent == -1)
+ warn ("sendto");
+ else
+ warnx ("sendto: short send - %d bytes", lsent);
+ }
+
+ free(line);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Decode a symbolic name to a numeric value
+ */
+int
+pencode(char *s)
+{
+ char *save;
+ int fac, lev;
+
+ for (save = s; *s && *s != '.'; ++s);
+ if (*s) {
+ *s = '\0';
+ fac = decode(save, facilitynames);
+ if (fac < 0)
+ errx(1, "unknown facility name: %s", save);
+ *s++ = '.';
+ }
+ else {
+ fac = 0;
+ s = save;
+ }
+ lev = decode(s, prioritynames);
+ if (lev < 0)
+ errx(1, "unknown priority name: %s", save);
+ return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
+}
+
+int
+decode(char *name, CODE *codetab)
+{
+ CODE *c;
+
+ if (isdigit(*name))
+ return (atoi(name));
+
+ for (c = codetab; c->c_name; c++)
+ if (!strcasecmp(name, c->c_name))
+ return (c->c_val);
+
+ return (-1);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: %s\n",
+#ifdef __APPLE__
+ "logger [-is] [-f file] [-p pri] [-t tag]\n"
+#else
+ "logger [-46Ais] [-f file] [-h host] [-P port] [-p pri] [-t tag]\n"
+#endif
+ " [message ...]"
+ );
+ exit(1);
+}
diff --git a/remote_cmds/talk.tproj/Makefile b/remote_cmds/talk.tproj/Makefile
new file mode 100644
index 0000000..47e3631
--- /dev/null
+++ b/remote_cmds/talk.tproj/Makefile
@@ -0,0 +1,14 @@
+Project = talk
+Install_Dir = /usr/bin
+
+HFILES = talk.h talk_ctl.h
+CFILES = ctl.c ctl_transact.c display.c get_addrs.c get_names.c\
+ get_iface.c init_disp.c invite.c io.c look_up.c msgs.c talk.c
+MANPAGES = talk.1
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_LD_Libraries = -lcurses
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/talk.tproj/ctl.c b/remote_cmds/talk.tproj/ctl.c
new file mode 100644
index 0000000..a5b42cc
--- /dev/null
+++ b/remote_cmds/talk.tproj/ctl.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/ctl.c,v 1.10 2005/02/09 09:13:36 stefanf Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)ctl.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * This file handles haggling with the various talk daemons to
+ * get a socket to talk to. sockt is opened and connected in
+ * the progress
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include "talk.h"
+
+struct sockaddr_in daemon_addr = { sizeof(daemon_addr), AF_INET };
+struct sockaddr_in ctl_addr = { sizeof(ctl_addr), AF_INET };
+struct sockaddr_in my_addr = { sizeof(my_addr), AF_INET };
+
+ /* inet addresses of the two machines */
+struct in_addr my_machine_addr;
+struct in_addr his_machine_addr;
+
+u_short daemon_port; /* port number of the talk daemon */
+
+int ctl_sockt;
+int sockt;
+int invitation_waiting = 0;
+
+CTL_MSG msg;
+
+void
+open_sockt()
+{
+ socklen_t length;
+
+ (void)memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_len = sizeof(my_addr);
+ my_addr.sin_addr = my_machine_addr;
+ my_addr.sin_port = 0;
+ sockt = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockt == -1)
+ p_error("Bad socket");
+ if (bind(sockt, (struct sockaddr *)&my_addr, sizeof(my_addr)) != 0)
+ p_error("Binding local socket");
+ length = sizeof(my_addr);
+ if (getsockname(sockt, (struct sockaddr *)&my_addr, &length) == -1)
+ p_error("Bad address for socket");
+}
+
+/* open the ctl socket */
+void
+open_ctl()
+{
+ socklen_t length;
+
+ (void)memset(&ctl_addr, 0, sizeof(ctl_addr));
+ ctl_addr.sin_family = AF_INET;
+ ctl_addr.sin_len = sizeof(my_addr);
+ ctl_addr.sin_port = 0;
+ ctl_addr.sin_addr = my_machine_addr;
+ ctl_sockt = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctl_sockt == -1)
+ p_error("Bad socket");
+ if (bind(ctl_sockt,
+ (struct sockaddr *)&ctl_addr, sizeof(ctl_addr)) != 0)
+ p_error("Couldn't bind to control socket");
+ length = sizeof(ctl_addr);
+ if (getsockname(ctl_sockt,
+ (struct sockaddr *)&ctl_addr, &length) == -1)
+ p_error("Bad address for ctl socket");
+}
+
+/* print_addr is a debug print routine */
+void
+print_addr(addr)
+ struct sockaddr_in addr;
+{
+ int i;
+
+ printf("addr = %lx, port = %o, family = %o zero = ",
+ (u_long)addr.sin_addr.s_addr, addr.sin_port, addr.sin_family);
+ for (i = 0; i<8;i++)
+ printf("%o ", (int)addr.sin_zero[i]);
+ putchar('\n');
+}
diff --git a/remote_cmds/talk.tproj/ctl_transact.c b/remote_cmds/talk.tproj/ctl_transact.c
new file mode 100644
index 0000000..1679250
--- /dev/null
+++ b/remote_cmds/talk.tproj/ctl_transact.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/ctl_transact.c,v 1.7 2002/02/18 20:35:26 mike Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)ctl_transact.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "talk.h"
+#include "talk_ctl.h"
+
+#define CTL_WAIT 2 /* time to wait for a response, in seconds */
+
+/*
+ * SOCKDGRAM is unreliable, so we must repeat messages if we have
+ * not recieved an acknowledgement within a reasonable amount
+ * of time
+ */
+void
+ctl_transact(target, lmsg, type, rp)
+ struct in_addr target;
+ CTL_MSG lmsg;
+ int type;
+ CTL_RESPONSE *rp;
+{
+ fd_set read_mask, ctl_mask;
+ int nready = 0, cc;
+ struct timeval wait;
+
+ lmsg.type = type;
+ daemon_addr.sin_addr = target;
+ daemon_addr.sin_port = daemon_port;
+ FD_ZERO(&ctl_mask);
+ FD_SET(ctl_sockt, &ctl_mask);
+
+ /*
+ * Keep sending the message until a response of
+ * the proper type is obtained.
+ */
+ do {
+ wait.tv_sec = CTL_WAIT;
+ wait.tv_usec = 0;
+ /* resend message until a response is obtained */
+ do {
+ cc = sendto(ctl_sockt, (char *)&lmsg, sizeof (lmsg), 0,
+ (struct sockaddr *)&daemon_addr,
+ sizeof (daemon_addr));
+ if (cc != sizeof (lmsg)) {
+ if (errno == EINTR)
+ continue;
+ p_error("Error on write to talk daemon");
+ }
+ read_mask = ctl_mask;
+ nready = select(ctl_sockt + 1, &read_mask, 0, 0, &wait);
+ if (nready < 0) {
+ if (errno == EINTR)
+ continue;
+ p_error("Error waiting for daemon response");
+ }
+ } while (nready == 0);
+ /*
+ * Keep reading while there are queued messages
+ * (this is not necessary, it just saves extra
+ * request/acknowledgements being sent)
+ */
+ do {
+ cc = recv(ctl_sockt, (char *)rp, sizeof (*rp), 0);
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ p_error("Error on read from talk daemon");
+ }
+ read_mask = ctl_mask;
+ /* an immediate poll */
+ timerclear(&wait);
+ nready = select(ctl_sockt + 1, &read_mask, 0, 0, &wait);
+ } while (nready > 0 && (rp->vers != TALK_VERSION ||
+ rp->type != type));
+ } while (rp->vers != TALK_VERSION || rp->type != type);
+ rp->id_num = ntohl(rp->id_num);
+ rp->addr.sa_family = ntohs(rp->addr.sa_family);
+}
diff --git a/remote_cmds/talk.tproj/display.c b/remote_cmds/talk.tproj/display.c
new file mode 100644
index 0000000..2815ec1
--- /dev/null
+++ b/remote_cmds/talk.tproj/display.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/display.c,v 1.11 2003/07/04 20:44:25 luigi Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * The window 'manager', initializes curses and handles the actual
+ * displaying of text
+ */
+#include <ctype.h>
+
+#include "talk.h"
+
+xwin_t my_win;
+xwin_t his_win;
+WINDOW *line_win;
+
+int curses_initialized = 0;
+
+/*
+ * max HAS to be a function, it is called with
+ * an argument of the form --foo at least once.
+ */
+int
+max(a,b)
+ int a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+/*
+ * Display some text on somebody's window, processing some control
+ * characters while we are at it.
+ */
+void
+display(win, text, size)
+ xwin_t *win;
+ char *text;
+ int size;
+{
+ int i;
+ char cch;
+
+ for (i = 0; i < size; i++) {
+ if (*text == '\n' || *text == '\r') {
+ waddch(win->x_win, '\n');
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ if (*text == 004 && win == &my_win) {
+ /* control-D clears the screen */
+ werase(my_win.x_win);
+ getyx(my_win.x_win, my_win.x_line, my_win.x_col);
+ wrefresh(my_win.x_win);
+ werase(his_win.x_win);
+ getyx(his_win.x_win, his_win.x_line, his_win.x_col);
+ wrefresh(his_win.x_win);
+ text++;
+ continue;
+ }
+
+ /* erase character */
+ if ( *text == win->cerase
+ || *text == 010 /* BS */
+ || *text == 0177 /* DEL */
+ ) {
+ wmove(win->x_win, win->x_line, max(--win->x_col, 0));
+ getyx(win->x_win, win->x_line, win->x_col);
+ waddch(win->x_win, ' ');
+ wmove(win->x_win, win->x_line, win->x_col);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ /*
+ * On word erase search backwards until we find
+ * the beginning of a word or the beginning of
+ * the line.
+ */
+ if ( *text == win->werase
+ || *text == 027 /* ^W */
+ ) {
+ int endcol, xcol, ii, c;
+
+ endcol = win->x_col;
+ xcol = endcol - 1;
+ while (xcol >= 0) {
+ c = readwin(win->x_win, win->x_line, xcol);
+ if (c != ' ')
+ break;
+ xcol--;
+ }
+ while (xcol >= 0) {
+ c = readwin(win->x_win, win->x_line, xcol);
+ if (c == ' ')
+ break;
+ xcol--;
+ }
+ wmove(win->x_win, win->x_line, xcol + 1);
+ for (ii = xcol + 1; ii < endcol; ii++)
+ waddch(win->x_win, ' ');
+ wmove(win->x_win, win->x_line, xcol + 1);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ /* line kill */
+ if ( *text == win->kill
+ || *text == 025 /* ^U */
+ ) {
+ wmove(win->x_win, win->x_line, 0);
+ wclrtoeol(win->x_win);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ if (*text == '\f') {
+ if (win == &my_win)
+ wrefresh(curscr);
+ text++;
+ continue;
+ }
+ if (*text == '\7') {
+ write(STDOUT_FILENO, text, 1);
+ text++;
+ continue;
+ }
+ if (!isprint((unsigned char)*text) && *text != '\t') {
+ waddch(win->x_win, '^');
+ getyx(win->x_win, win->x_line, win->x_col);
+ cch = (*text & 63) + 64;
+ waddch(win->x_win, cch);
+ } else
+ waddch(win->x_win, (unsigned char)*text);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ }
+ wrefresh(win->x_win);
+}
+
+/*
+ * Read the character at the indicated position in win
+ */
+int
+readwin(win, line, col)
+ WINDOW *win;
+ int line;
+ int col;
+{
+ int oldline, oldcol;
+ int c;
+
+ getyx(win, oldline, oldcol);
+ wmove(win, line, col);
+ c = winch(win);
+ wmove(win, oldline, oldcol);
+ return (c);
+}
diff --git a/remote_cmds/talk.tproj/get_addrs.c b/remote_cmds/talk.tproj/get_addrs.c
new file mode 100644
index 0000000..e5a71ac
--- /dev/null
+++ b/remote_cmds/talk.tproj/get_addrs.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/get_addrs.c,v 1.5 2001/12/11 23:51:14 markm Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)get_addrs.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <err.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "talk.h"
+#include "talk_ctl.h"
+
+void
+get_addrs(my_machine_name, his_machine_name)
+ char *my_machine_name __unused, *his_machine_name;
+{
+ struct hostent *hp;
+ struct servent *sp;
+
+ msg.pid = htonl(getpid());
+
+ hp = gethostbyname(his_machine_name);
+ if (hp == NULL)
+ errx(1, "%s: %s", his_machine_name, hstrerror(h_errno));
+ bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length);
+ if (get_iface(&his_machine_addr, &my_machine_addr) == -1)
+ err(1, "failed to find my interface address");
+ /* find the server's port */
+ sp = getservbyname("ntalk", "udp");
+ if (sp == 0)
+ errx(1, "ntalk/udp: service is not registered");
+ daemon_port = sp->s_port;
+}
diff --git a/remote_cmds/talk.tproj/get_iface.c b/remote_cmds/talk.tproj/get_iface.c
new file mode 100644
index 0000000..79b7d30
--- /dev/null
+++ b/remote_cmds/talk.tproj/get_iface.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 1994, 1995 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that both the above copyright notice and this
+ * permission notice appear in all copies, that both the above
+ * copyright notice and this permission notice appear in all
+ * supporting documentation, and that the name of M.I.T. not be used
+ * in advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission. M.I.T. makes
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
+ * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
+ * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/get_iface.c,v 1.10 2005/03/11 14:17:12 stefanf Exp $");
+#endif
+
+/*
+ * From:
+ * Id: find_interface.c,v 1.1 1995/08/14 16:08:39 wollman Exp
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "talk.h"
+
+/*
+ * Try to find the interface address that is used to route an IP
+ * packet to a remote peer.
+ */
+
+int
+get_iface(dst, iface)
+ struct in_addr *dst;
+ struct in_addr *iface;
+{
+ static struct sockaddr_in local;
+ struct sockaddr_in remote;
+ socklen_t namelen;
+ int s, rv;
+
+ memcpy(&remote.sin_addr, dst, sizeof remote.sin_addr);
+ remote.sin_port = htons(60000);
+ remote.sin_family = AF_INET;
+ remote.sin_len = sizeof remote;
+
+ local.sin_addr.s_addr = htonl(INADDR_ANY);
+ local.sin_port = htons(60000);
+ local.sin_family = AF_INET;
+ local.sin_len = sizeof local;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return -1;
+
+ do {
+ rv = bind(s, (struct sockaddr *)&local, sizeof local);
+ local.sin_port = htons(ntohs(local.sin_port) + 1);
+ } while(rv < 0 && errno == EADDRINUSE);
+
+ if (rv < 0) {
+ close(s);
+ return -1;
+ }
+
+ do {
+ rv = connect(s, (struct sockaddr *)&remote, sizeof remote);
+ remote.sin_port = htons(ntohs(remote.sin_port) + 1);
+ } while(rv < 0 && errno == EADDRINUSE);
+
+ if (rv < 0) {
+ close(s);
+ return -1;
+ }
+
+ namelen = sizeof local;
+ rv = getsockname(s, (struct sockaddr *)&local, &namelen);
+ close(s);
+ if (rv < 0)
+ return -1;
+
+ memcpy(iface, &local.sin_addr, sizeof local.sin_addr);
+ return 0;
+}
diff --git a/remote_cmds/talk.tproj/get_names.c b/remote_cmds/talk.tproj/get_names.c
new file mode 100644
index 0000000..24acab1
--- /dev/null
+++ b/remote_cmds/talk.tproj/get_names.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/get_names.c,v 1.9 2004/06/14 22:34:13 bms Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)get_names.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "talk.h"
+
+extern CTL_MSG msg;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: talk person [ttyname]\n");
+ exit(1);
+}
+
+/*
+ * Determine the local and remote user, tty, and machines
+ */
+void
+get_names(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char hostname[MAXHOSTNAMELEN];
+ char *his_name, *my_name;
+ char *my_machine_name, *his_machine_name;
+ const char *his_tty;
+ char *cp;
+
+ if (argc < 2 )
+ usage();
+ if (!isatty(0))
+ errx(1, "standard input must be a tty, not a pipe or a file");
+ if ((my_name = getlogin()) == NULL) {
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) == NULL)
+ errx(1, "you don't exist. Go away");
+ my_name = pw->pw_name;
+ }
+ gethostname(hostname, sizeof (hostname));
+ my_machine_name = hostname;
+ /* check for, and strip out, the machine name of the target */
+ for (cp = argv[1]; *cp && !index("@:!", *cp); cp++)
+ ;
+ if (*cp == '\0') {
+ /* this is a local to local talk */
+ his_name = argv[1];
+ my_machine_name = his_machine_name = "localhost";
+ } else {
+ if (*cp++ == '@') {
+ /* user@host */
+ his_name = argv[1];
+ his_machine_name = cp;
+ } else {
+ /* host!user or host:user */
+ his_name = cp;
+ his_machine_name = argv[1];
+ }
+ *--cp = '\0';
+ }
+ if (argc > 2)
+ his_tty = argv[2]; /* tty name is arg 2 */
+ else
+ his_tty = "";
+ get_addrs(my_machine_name, his_machine_name);
+ /*
+ * Initialize the message template.
+ */
+ msg.vers = TALK_VERSION;
+ msg.addr.sa_family = htons(AF_INET);
+ msg.ctl_addr.sa_family = htons(AF_INET);
+ msg.id_num = htonl(0);
+ strncpy(msg.l_name, my_name, NAME_SIZE);
+ msg.l_name[NAME_SIZE - 1] = '\0';
+ strncpy(msg.r_name, his_name, NAME_SIZE);
+ msg.r_name[NAME_SIZE - 1] = '\0';
+ strncpy(msg.r_tty, his_tty, TTY_SIZE);
+ msg.r_tty[TTY_SIZE - 1] = '\0';
+}
diff --git a/remote_cmds/talk.tproj/init_disp.c b/remote_cmds/talk.tproj/init_disp.c
new file mode 100644
index 0000000..c6a02ef
--- /dev/null
+++ b/remote_cmds/talk.tproj/init_disp.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/init_disp.c,v 1.14 2004/04/19 21:37:28 cognet Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)init_disp.c 8.2 (Berkeley) 2/16/94";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * Initialization code for the display package,
+ * as well as the signal handling routines.
+ */
+
+#include <sys/stat.h>
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+
+#include <err.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+
+#include "talk.h"
+
+extern volatile sig_atomic_t gotwinch;
+
+/*
+ * Make sure the callee can write to the screen
+ */
+void
+check_writeable()
+{
+ char *tty;
+ struct stat sb;
+
+ if ((tty = ttyname(STDERR_FILENO)) == NULL)
+ err(1, "ttyname");
+ if (stat(tty, &sb) < 0)
+ err(1, "%s", tty);
+ if (!(sb.st_mode & S_IWGRP))
+ errx(1, "The callee cannot write to this terminal, use \"mesg y\".");
+}
+
+/*
+ * Set up curses, catch the appropriate signals,
+ * and build the various windows.
+ */
+void
+init_display()
+{
+ struct sigaction sa;
+
+ if (initscr() == NULL)
+ errx(1, "Terminal type unset or lacking necessary features.");
+ (void) sigaction(SIGTSTP, (struct sigaction *)0, &sa);
+ sigaddset(&sa.sa_mask, SIGALRM);
+ (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
+ curses_initialized = 1;
+ clear();
+ refresh();
+ noecho();
+ crmode();
+ signal(SIGINT, sig_sent);
+ signal(SIGPIPE, sig_sent);
+ signal(SIGWINCH, sig_winch);
+ /* curses takes care of ^Z */
+ my_win.x_nlines = LINES / 2;
+ my_win.x_ncols = COLS;
+ my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0);
+ idlok(my_win.x_win, TRUE);
+ scrollok(my_win.x_win, TRUE);
+ wclear(my_win.x_win);
+
+ his_win.x_nlines = LINES / 2 - 1;
+ his_win.x_ncols = COLS;
+ his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols,
+ my_win.x_nlines+1, 0);
+ idlok(my_win.x_win, TRUE);
+ scrollok(his_win.x_win, TRUE);
+ wclear(his_win.x_win);
+
+ line_win = newwin(1, COLS, my_win.x_nlines, 0);
+#if defined(hline) || defined(whline) || defined(NCURSES_VERSION)
+ whline(line_win, 0, COLS);
+#else
+ box(line_win, '-', '-');
+#endif
+ wrefresh(line_win);
+ /* let them know we are working on it */
+ current_state = "No connection yet";
+}
+
+/*
+ * Trade edit characters with the other talk. By agreement
+ * the first three characters each talk transmits after
+ * connection are the three edit characters.
+ */
+void
+set_edit_chars()
+{
+ char buf[3];
+ int cc;
+ struct termios tio;
+
+ tcgetattr(0, &tio);
+ my_win.cerase = tio.c_cc[VERASE];
+ my_win.kill = tio.c_cc[VKILL];
+ my_win.werase = tio.c_cc[VWERASE];
+ if (my_win.cerase == (char)_POSIX_VDISABLE)
+ my_win.kill = CERASE;
+ if (my_win.kill == (char)_POSIX_VDISABLE)
+ my_win.kill = CKILL;
+ if (my_win.werase == (char)_POSIX_VDISABLE)
+ my_win.werase = CWERASE;
+ buf[0] = my_win.cerase;
+ buf[1] = my_win.kill;
+ buf[2] = my_win.werase;
+ cc = write(sockt, buf, sizeof(buf));
+ if (cc != sizeof(buf) )
+ p_error("Lost the connection");
+ cc = read(sockt, buf, sizeof(buf));
+ if (cc != sizeof(buf) )
+ p_error("Lost the connection");
+ his_win.cerase = buf[0];
+ his_win.kill = buf[1];
+ his_win.werase = buf[2];
+}
+
+/* ARGSUSED */
+void
+sig_sent(signo)
+ int signo __unused;
+{
+
+ message("Connection closing. Exiting");
+ quit();
+}
+
+void
+sig_winch(int dummy)
+{
+
+ gotwinch = 1;
+}
+
+/*
+ * All done talking...hang up the phone and reset terminal thingy's
+ */
+void
+quit()
+{
+
+ if (curses_initialized) {
+ wmove(his_win.x_win, his_win.x_nlines-1, 0);
+ wclrtoeol(his_win.x_win);
+ wrefresh(his_win.x_win);
+ endwin();
+ }
+ if (invitation_waiting)
+ send_delete();
+ exit(0);
+}
+
+/*
+ * If we get SIGWINCH, recompute both window sizes and refresh things.
+ */
+void
+resize_display(void)
+{
+ struct winsize ws;
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0 ||
+ (ws.ws_row == LINES && ws.ws_col == COLS))
+ return;
+
+ /* Update curses' internal state with new window size. */
+ resizeterm(ws.ws_row, ws.ws_col);
+
+ /*
+ * Resize each window but wait to refresh the screen until
+ * everything has been drawn so the cursor is in the right spot.
+ */
+ my_win.x_nlines = LINES / 2;
+ my_win.x_ncols = COLS;
+ wresize(my_win.x_win, my_win.x_nlines, my_win.x_ncols);
+ mvwin(my_win.x_win, 0, 0);
+ clearok(my_win.x_win, TRUE);
+
+ his_win.x_nlines = LINES / 2 - 1;
+ his_win.x_ncols = COLS;
+ wresize(his_win.x_win, his_win.x_nlines, his_win.x_ncols);
+ mvwin(his_win.x_win, my_win.x_nlines + 1, 0);
+ clearok(his_win.x_win, TRUE);
+
+ wresize(line_win, 1, COLS);
+ mvwin(line_win, my_win.x_nlines, 0);
+#if defined(NCURSES_VERSION) || defined(whline)
+ whline(line_win, '-', COLS);
+#else
+ wmove(line_win, my_win.x_nlines, 0);
+ box(line_win, '-', '-');
+#endif
+
+ /* Now redraw the screen. */
+ wrefresh(his_win.x_win);
+ wrefresh(line_win);
+ wrefresh(my_win.x_win);
+}
diff --git a/remote_cmds/talk.tproj/invite.c b/remote_cmds/talk.tproj/invite.c
new file mode 100644
index 0000000..b8562b2
--- /dev/null
+++ b/remote_cmds/talk.tproj/invite.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/invite.c,v 1.9 2003/01/01 18:49:00 schweikh Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)invite.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <protocols/talkd.h>
+
+#include <err.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+
+#include "talk_ctl.h"
+#include "talk.h"
+
+/*
+ * There wasn't an invitation waiting, so send a request containing
+ * our sockt address to the remote talk daemon so it can invite
+ * him
+ */
+
+/*
+ * The msg.id's for the invitations
+ * on the local and remote machines.
+ * These are used to delete the
+ * invitations.
+ */
+int local_id, remote_id;
+jmp_buf invitebuf;
+
+void
+invite_remote()
+{
+ int new_sockt;
+ struct itimerval itimer;
+ CTL_RESPONSE response;
+
+ itimer.it_value.tv_sec = RING_WAIT;
+ itimer.it_value.tv_usec = 0;
+ itimer.it_interval = itimer.it_value;
+ if (listen(sockt, 5) != 0)
+ p_error("Error on attempt to listen for caller");
+#ifdef MSG_EOR
+ /* copy new style sockaddr to old, swap family (short in old) */
+ msg.addr = *(struct osockaddr *)&my_addr; /* XXX new to old style*/
+ msg.addr.sa_family = htons(my_addr.sin_family);
+#else
+ msg.addr = *(struct sockaddr *)&my_addr;
+#endif
+ msg.id_num = htonl(-1); /* an impossible id_num */
+ invitation_waiting = 1;
+ announce_invite();
+ /*
+ * Shut off the automatic messages for a while,
+ * so we can use the interupt timer to resend the invitation
+ */
+ end_msgs();
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+ message("Waiting for your party to respond");
+ signal(SIGALRM, re_invite);
+ (void) setjmp(invitebuf);
+ while ((new_sockt = accept(sockt, 0, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ p_error("Unable to connect with your party");
+ }
+ close(sockt);
+ sockt = new_sockt;
+
+ /*
+ * Have the daemons delete the invitations now that we
+ * have connected.
+ */
+ current_state = "Waiting for your party to respond";
+ start_msgs();
+
+ msg.id_num = htonl(local_id);
+ ctl_transact(my_machine_addr, msg, DELETE, &response);
+ msg.id_num = htonl(remote_id);
+ ctl_transact(his_machine_addr, msg, DELETE, &response);
+ invitation_waiting = 0;
+}
+
+/*
+ * Routine called on interupt to re-invite the callee
+ */
+/* ARGSUSED */
+void
+re_invite(signo)
+ int signo __unused;
+{
+
+ message("Ringing your party again");
+ waddch(my_win.x_win, '\n');
+ if (current_line < my_win.x_nlines - 1)
+ current_line++;
+ /* force a re-announce */
+ msg.id_num = htonl(remote_id + 1);
+ announce_invite();
+ longjmp(invitebuf, 1);
+}
+
+static const char *answers[] = {
+ "answer #0", /* SUCCESS */
+ "Your party is not logged on", /* NOT_HERE */
+ "Target machine is too confused to talk to us", /* FAILED */
+ "Target machine does not recognize us", /* MACHINE_UNKNOWN */
+ "Your party is refusing messages", /* PERMISSION_REFUSED */
+ "Target machine can not handle remote talk", /* UNKNOWN_REQUEST */
+ "Target machine indicates protocol mismatch", /* BADVERSION */
+ "Target machine indicates protocol botch (addr)",/* BADADDR */
+ "Target machine indicates protocol botch (ctl_addr)",/* BADCTLADDR */
+};
+#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
+
+/*
+ * Transmit the invitation and process the response
+ */
+void
+announce_invite()
+{
+ CTL_RESPONSE response;
+
+ current_state = "Trying to connect to your party's talk daemon";
+ ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
+ remote_id = response.id_num;
+ if (response.answer != SUCCESS) {
+ if (response.answer < NANSWERS)
+ message(answers[response.answer]);
+ quit();
+ }
+ /* leave the actual invitation on my talk daemon */
+ current_state = "Trying to connect to local talk daemon";
+ ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response);
+ local_id = response.id_num;
+}
+
+/*
+ * Tell the daemon to remove your invitation
+ */
+void
+send_delete()
+{
+
+ msg.type = DELETE;
+ /*
+ * This is just an extra clean up, so just send it
+ * and don't wait for an answer
+ */
+ msg.id_num = htonl(remote_id);
+ daemon_addr.sin_addr = his_machine_addr;
+ if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
+ (struct sockaddr *)&daemon_addr,
+ sizeof (daemon_addr)) != sizeof(msg))
+ warn("send_delete (remote)");
+ msg.id_num = htonl(local_id);
+ daemon_addr.sin_addr = my_machine_addr;
+ if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
+ (struct sockaddr *)&daemon_addr,
+ sizeof (daemon_addr)) != sizeof (msg))
+ warn("send_delete (local)");
+}
diff --git a/remote_cmds/talk.tproj/io.c b/remote_cmds/talk.tproj/io.c
new file mode 100644
index 0000000..644c28b
--- /dev/null
+++ b/remote_cmds/talk.tproj/io.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/io.c,v 1.16 2004/05/10 15:52:16 cognet Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * This file contains the I/O handling and the exchange of
+ * edit characters. This connection itself is established in
+ * ctl.c
+ */
+
+#include <sys/filio.h>
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "talk.h"
+#include "talk_ctl.h"
+
+#define A_LONG_TIME 10000000
+
+volatile sig_atomic_t gotwinch = 0;
+
+/*
+ * The routine to do the actual talking
+ */
+void
+talk()
+{
+ struct hostent *hp, *hp2;
+ int nb;
+ fd_set read_set, read_template;
+ char buf[BUFSIZ], **addr, *his_machine_name;
+ struct timeval wait;
+
+ his_machine_name = NULL;
+ hp = gethostbyaddr((const char *)&his_machine_addr.s_addr,
+ sizeof(his_machine_addr.s_addr), AF_INET);
+ if (hp != NULL) {
+ hp2 = gethostbyname(hp->h_name);
+ if (hp2 != NULL && hp2->h_addrtype == AF_INET &&
+ hp2->h_length == sizeof(his_machine_addr))
+ for (addr = hp2->h_addr_list; *addr != NULL; addr++)
+ if (memcmp(*addr, &his_machine_addr,
+ sizeof(his_machine_addr)) == 0) {
+ his_machine_name = strdup(hp->h_name);
+ break;
+ }
+ }
+ if (his_machine_name == NULL)
+ his_machine_name = strdup(inet_ntoa(his_machine_addr));
+ snprintf(buf, sizeof(buf), "Connection established with %s@%s.",
+ msg.r_name, his_machine_name);
+ free(his_machine_name);
+ message(buf);
+ write(STDOUT_FILENO, "\007\007\007", 3);
+
+ current_line = 0;
+
+ /*
+ * Wait on both the other process (sockt_mask) and
+ * standard input ( STDIN_MASK )
+ */
+ FD_ZERO(&read_template);
+ FD_SET(sockt, &read_template);
+ FD_SET(fileno(stdin), &read_template);
+ for (;;) {
+ read_set = read_template;
+ wait.tv_sec = A_LONG_TIME;
+ wait.tv_usec = 0;
+ nb = select(sockt + 1, &read_set, 0, 0, &wait);
+ if (gotwinch) {
+ resize_display();
+ gotwinch = 0;
+ }
+ if (nb <= 0) {
+ if (errno == EINTR) {
+ read_set = read_template;
+ continue;
+ }
+ /* panic, we don't know what happened */
+ p_error("Unexpected error from select");
+ quit();
+ }
+ if (FD_ISSET(sockt, &read_set)) {
+ /* There is data on sockt */
+ nb = read(sockt, buf, sizeof buf);
+ if (nb <= 0) {
+ message("Connection closed. Exiting");
+ quit();
+ }
+ display(&his_win, buf, nb);
+ }
+ if (FD_ISSET(fileno(stdin), &read_set)) {
+ /*
+ * We can't make the tty non_blocking, because
+ * curses's output routines would screw up
+ */
+ int i;
+ ioctl(0, FIONREAD, (void *) &nb);
+ if (nb > sizeof buf)
+ nb = sizeof buf;
+ nb = read(STDIN_FILENO, buf, nb);
+ display(&my_win, buf, nb);
+ /* might lose data here because sockt is non-blocking */
+ for (i = 0; i < nb; ++i)
+ if (buf[i] == '\r')
+ buf[i] = '\n';
+ write(sockt, buf, nb);
+ }
+ }
+}
+
+/*
+ * p_error prints the system error message on the standard location
+ * on the screen and then exits. (i.e. a curses version of perror)
+ */
+void
+p_error(string)
+ const char *string;
+{
+ wmove(my_win.x_win, current_line, 0);
+ wprintw(my_win.x_win, "[%s : %s (%d)]\n",
+ string, strerror(errno), errno);
+ wrefresh(my_win.x_win);
+ move(LINES-1, 0);
+ refresh();
+ quit();
+}
+
+/*
+ * Display string in the standard location
+ */
+void
+message(string)
+ const char *string;
+{
+ wmove(my_win.x_win, current_line, 0);
+ wprintw(my_win.x_win, "[%s]\n", string);
+ if (current_line < my_win.x_nlines - 1)
+ current_line++;
+ wrefresh(my_win.x_win);
+}
diff --git a/remote_cmds/talk.tproj/look_up.c b/remote_cmds/talk.tproj/look_up.c
new file mode 100644
index 0000000..3fd003f
--- /dev/null
+++ b/remote_cmds/talk.tproj/look_up.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/look_up.c,v 1.8 2005/02/09 09:13:36 stefanf Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)look_up.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <protocols/talkd.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "talk_ctl.h"
+#include "talk.h"
+
+/*
+ * See if the local daemon has an invitation for us.
+ */
+int
+check_local()
+{
+ CTL_RESPONSE response;
+ CTL_RESPONSE *rp = &response;
+ struct sockaddr addr;
+
+ /* the rest of msg was set up in get_names */
+#ifdef MSG_EOR
+ /* copy new style sockaddr to old, swap family (short in old) */
+ msg.ctl_addr = *(struct osockaddr *)&ctl_addr;
+ msg.ctl_addr.sa_family = htons(ctl_addr.sin_family);
+#else
+ msg.ctl_addr = *(struct sockaddr *)&ctl_addr;
+#endif
+ /* must be initiating a talk */
+ if (!look_for_invite(rp))
+ return (0);
+ /*
+ * There was an invitation waiting for us,
+ * so connect with the other (hopefully waiting) party
+ */
+ current_state = "Waiting to connect with caller";
+ do {
+ if (rp->addr.sa_family != AF_INET)
+ p_error("Response uses invalid network address");
+ (void)memcpy(&addr, &rp->addr.sa_family, sizeof(addr));
+ addr.sa_family = rp->addr.sa_family;
+ addr.sa_len = sizeof(addr);
+ errno = 0;
+ if (connect(sockt, &addr, sizeof(addr)) != -1)
+ return (1);
+ } while (errno == EINTR);
+ if (errno == ECONNREFUSED) {
+ /*
+ * The caller gave up, but his invitation somehow
+ * was not cleared. Clear it and initiate an
+ * invitation. (We know there are no newer invitations,
+ * the talkd works LIFO.)
+ */
+ ctl_transact(his_machine_addr, msg, DELETE, rp);
+ close(sockt);
+ open_sockt();
+ return (0);
+ }
+ p_error("Unable to connect with initiator");
+ /*NOTREACHED*/
+ return (0);
+}
+
+/*
+ * Look for an invitation on 'machine'
+ */
+int
+look_for_invite(rp)
+ CTL_RESPONSE *rp;
+{
+ current_state = "Checking for invitation on caller's machine";
+ ctl_transact(his_machine_addr, msg, LOOK_UP, rp);
+ /* the switch is for later options, such as multiple invitations */
+ switch (rp->answer) {
+
+ case SUCCESS:
+ msg.id_num = htonl(rp->id_num);
+ return (1);
+
+ default:
+ /* there wasn't an invitation waiting for us */
+ return (0);
+ }
+}
diff --git a/remote_cmds/talk.tproj/msgs.c b/remote_cmds/talk.tproj/msgs.c
new file mode 100644
index 0000000..f8cb59a
--- /dev/null
+++ b/remote_cmds/talk.tproj/msgs.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/msgs.c,v 1.6 2001/12/11 23:51:14 markm Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * A package to display what is happening every MSG_INTERVAL seconds
+ * if we are slow connecting.
+ */
+
+#include <signal.h>
+
+#include "talk.h"
+
+#define MSG_INTERVAL 4
+
+const char *current_state;
+int current_line = 0;
+
+/* ARGSUSED */
+void
+disp_msg(signo)
+ int signo __unused;
+{
+ message(current_state);
+}
+
+void
+start_msgs()
+{
+ struct itimerval itimer;
+
+ message(current_state);
+ signal(SIGALRM, disp_msg);
+ itimer.it_value.tv_sec = itimer.it_interval.tv_sec = MSG_INTERVAL;
+ itimer.it_value.tv_usec = itimer.it_interval.tv_usec = 0;
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+}
+
+void
+end_msgs()
+{
+ struct itimerval itimer;
+
+ timerclear(&itimer.it_value);
+ timerclear(&itimer.it_interval);
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+ signal(SIGALRM, SIG_DFL);
+}
diff --git a/remote_cmds/talk.tproj/talk.1 b/remote_cmds/talk.tproj/talk.1
new file mode 100644
index 0000000..bf105bb
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk.1
@@ -0,0 +1,172 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)talk.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/talk/talk.1,v 1.20 2005/02/13 22:25:24 ru Exp $
+.\"
+.Dd August 21, 2008
+.Dt TALK 1
+.Os
+.Sh NAME
+.Nm talk
+.Nd talk to another user
+.Sh SYNOPSIS
+.Nm
+.Ar person
+.Op Ar ttyname
+.Sh DESCRIPTION
+The
+.Nm
+utility is a visual communication program which copies lines from your
+terminal to that of another user.
+.Pp
+Options available:
+.Bl -tag -width ttyname
+.It Ar person
+If you wish to talk to someone on your own machine, then
+.Ar person
+is just the person's login name.
+If you wish to talk to a user on
+another host, then
+.Ar person
+is of the form
+.Ql user@host
+or
+.Ql host!user
+or
+.Ql host:user .
+.It Ar ttyname
+If you wish to talk to a user who is logged in more than once, the
+.Ar ttyname
+argument may be used to indicate the appropriate terminal
+name, where
+.Ar ttyname
+is of the form
+.Ql ttyXX .
+.El
+.Pp
+When first called,
+.Nm
+sends the message
+.Bd -literal -offset indent -compact
+Message from TalkDaemon@his_machine...
+talk: connection requested by your_name@your_machine.
+talk: respond with: talk your_name@your_machine
+.Ed
+.Pp
+to the user you wish to talk to.
+At this point, the recipient
+of the message should reply by typing
+.Pp
+.Dl talk \ your_name@your_machine
+.Pp
+It does not matter from which machine the recipient replies, as
+long as his login-name is the same.
+Once communication is established,
+the two parties may type simultaneously, with their output appearing
+in separate windows.
+Typing control-L
+.Ql ^L
+will cause the screen to
+be reprinted.
+Typing control-D
+.Ql ^D
+will clear both parts of your screen to be cleared, while
+the control-D character will be sent to the remote side
+(and just displayed by this
+.Nm
+client).
+Your erase, kill, and word kill characters will
+behave normally.
+To exit, just type your interrupt character;
+.Nm
+then moves the cursor to the bottom of the screen and restores the
+terminal to its previous state.
+.Pp
+Permission to talk may be denied or granted by use of the
+.Xr mesg 1
+command.
+At the outset talking is allowed.
+.Sh CONFIGURATION
+The
+.Nm
+utility relies on the
+.Nm talkd
+system daemon. See
+.Xr talkd 8
+for information about enabling
+.Nm talkd .
+.Sh FILES
+.Bl -tag -width /var/run/utmpx -compact
+.It Pa /etc/hosts
+to find the recipient's machine
+.It Pa /var/run/utmpx
+to find the recipient's tty
+.El
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr mesg 1 ,
+.Xr wall 1 ,
+.Xr who 1 ,
+.Xr write 1 ,
+.Xr talkd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+In
+.Fx 5.3 ,
+the default behaviour of
+.Nm
+was changed to treat local-to-local talk requests as originating
+and terminating at
+.Em localhost .
+Before this change, it was required that the hostname (as per
+.Xr gethostname 3 )
+resolved to a valid IPv4 address (via
+.Xr gethostbyname 3 ) ,
+making
+.Nm
+unsuitable for use in configurations where
+.Xr talkd 8
+was bound to the loopback interface (normally for security reasons).
+.Sh BUGS
+The version of
+.Nm
+released with
+.Bx 4.3
+uses a protocol that
+is incompatible with the protocol used in the version released with
+.Bx 4.2 .
+.Pp
+Multibyte characters are not recognized.
diff --git a/remote_cmds/talk.tproj/talk.c b/remote_cmds/talk.tproj/talk.c
new file mode 100644
index 0000000..d86e770
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/talk.c,v 1.11 2002/08/19 03:07:56 jmallett Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)talk.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#include <locale.h>
+
+#include "talk.h"
+
+/*
+ * talk: A visual form of write. Using sockets, a two way
+ * connection is set up between the two people talking.
+ * With the aid of curses, the screen is split into two
+ * windows, and each users text is added to the window,
+ * one character at a time...
+ *
+ * Written by Kipp Hickman
+ *
+ * Modified to run under 4.1a by Clem Cole and Peter Moore
+ * Modified to run between hosts by Peter Moore, 8/19/82
+ * Modified to run under 4.1c by Peter Moore 3/17/83
+ * Fixed to not run with unwriteable terminals MRVM 28/12/94
+ */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ (void) setlocale(LC_CTYPE, "");
+
+ get_names(argc, argv);
+#ifndef __APPLE__
+ setproctitle("");
+#endif
+ check_writeable();
+ init_display();
+ open_ctl();
+ open_sockt();
+ start_msgs();
+ if (!check_local())
+ invite_remote();
+ end_msgs();
+ set_edit_chars();
+ talk();
+ return 0;
+}
diff --git a/remote_cmds/talk.tproj/talk.h b/remote_cmds/talk.tproj/talk.h
new file mode 100644
index 0000000..7f3bcf4
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)talk.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/talk/talk.h,v 1.5 2004/04/19 21:37:29 cognet Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <protocols/talkd.h>
+#include <curses.h>
+#include <unistd.h>
+
+extern int sockt;
+extern int curses_initialized;
+extern int invitation_waiting;
+
+extern const char *current_state;
+extern int current_line;
+
+typedef struct xwin {
+ WINDOW *x_win;
+ int x_nlines;
+ int x_ncols;
+ int x_line;
+ int x_col;
+ char kill;
+ char cerase;
+ char werase;
+} xwin_t;
+
+extern xwin_t my_win;
+extern xwin_t his_win;
+extern WINDOW *line_win;
+
+extern void announce_invite(void);
+extern int check_local(void);
+extern void check_writeable(void);
+extern void ctl_transact(struct in_addr,CTL_MSG,int,CTL_RESPONSE *);
+extern void disp_msg(int);
+extern void display(xwin_t *, char *, int);
+extern void end_msgs(void);
+extern void get_addrs(char *, char *);
+extern int get_iface(struct in_addr *, struct in_addr *);
+extern void get_names(int, char **);
+extern void init_display(void);
+extern void invite_remote(void);
+extern int look_for_invite(CTL_RESPONSE *);
+extern int max(int, int);
+extern void message(const char *);
+extern void open_ctl(void);
+extern void open_sockt(void);
+extern void p_error(const char *);
+extern void print_addr(struct sockaddr_in);
+extern void quit(void);
+extern int readwin(WINDOW *, int, int);
+extern void re_invite(int);
+extern void send_delete(void);
+extern void set_edit_chars(void);
+extern void sig_sent(int);
+extern void sig_winch(int);
+extern void start_msgs(void);
+extern void talk(void);
+extern void resize_display(void);
diff --git a/remote_cmds/talk.tproj/talk_ctl.h b/remote_cmds/talk.tproj/talk_ctl.h
new file mode 100644
index 0000000..91c75d0
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk_ctl.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)talk_ctl.h 8.1 (Berkeley) 6/6/93
+ */
+
+extern struct sockaddr_in daemon_addr;
+extern struct sockaddr_in ctl_addr;
+extern struct sockaddr_in my_addr;
+extern struct in_addr my_machine_addr;
+extern struct in_addr his_machine_addr;
+extern u_short daemon_port;
+extern int ctl_sockt;
+extern CTL_MSG msg;
diff --git a/remote_cmds/talkd.tproj/Makefile b/remote_cmds/talkd.tproj/Makefile
new file mode 100644
index 0000000..f67b40b
--- /dev/null
+++ b/remote_cmds/talkd.tproj/Makefile
@@ -0,0 +1,14 @@
+Project = ntalkd
+Install_Dir = /usr/libexec
+
+HFILES = talkd.h
+CFILES = announce.c print.c process.c table.c talkd.c ../wall.tproj/ttymsg.c
+MANPAGES = ntalkd.8
+LAUNCHD_PLISTS = ntalk.plist
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_CC_Flags += -D__FBSDID=__RCSID
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/talkd.tproj/announce.c b/remote_cmds/talkd.tproj/announce.c
new file mode 100644
index 0000000..5091513
--- /dev/null
+++ b/remote_cmds/talkd.tproj/announce.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)announce.c 8.3 (Berkeley) 4/28/95";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/announce.c,v 1.16 2003/04/03 05:13:27 jmallett Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+#include <protocols/talkd.h>
+
+#include <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <vis.h>
+
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include "ttymsg.h"
+#endif
+#include "extern.h"
+
+extern char hostname[];
+
+/*
+ * Announce an invitation to talk.
+ */
+
+/*
+ * See if the user is accepting messages. If so, announce that
+ * a talk is requested.
+ */
+int
+announce(CTL_MSG *request, const char *remote_machine)
+{
+ char full_tty[32];
+ struct stat stbuf;
+
+ (void)snprintf(full_tty, sizeof(full_tty),
+ "%s%s", _PATH_DEV, request->r_tty);
+ if (stat(full_tty, &stbuf) < 0 || (stbuf.st_mode&020) == 0)
+ return (PERMISSION_DENIED);
+ return (print_mesg(request->r_tty, request, remote_machine));
+}
+
+#define max(a,b) ( (a) > (b) ? (a) : (b) )
+#define N_LINES 5
+#define N_CHARS 256
+
+/*
+ * Build a block of characters containing the message.
+ * It is sent blank filled and in a single block to
+ * try to keep the message in one piece if the recipient
+ * in in vi at the time
+ */
+int
+print_mesg(const char *tty, CTL_MSG *request,
+ const char *remote_machine)
+{
+ struct timeval now;
+ time_t clock_sec;
+ struct timezone zone;
+ struct tm *localclock;
+ struct iovec iovec;
+ char line_buf[N_LINES][N_CHARS];
+ int sizes[N_LINES];
+ char big_buf[N_LINES*N_CHARS];
+ char *bptr, *lptr, *vis_user;
+ int i, j, max_size;
+
+ i = 0;
+ max_size = 0;
+ gettimeofday(&now, &zone);
+ clock_sec = now.tv_sec;
+ localclock = localtime(&clock_sec);
+ (void)snprintf(line_buf[i], N_CHARS, " ");
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ (void)snprintf(line_buf[i], N_CHARS,
+ "Message from Talk_Daemon@%s at %d:%02d on %d/%.2d/%.2d ...",
+ hostname, localclock->tm_hour , localclock->tm_min,
+ localclock->tm_year + 1900, localclock->tm_mon + 1,
+ localclock->tm_mday);
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+
+ vis_user = malloc(strlen(request->l_name) * 4 + 1);
+ strvis(vis_user, request->l_name, VIS_CSTYLE);
+ (void)snprintf(line_buf[i], N_CHARS,
+ "talk: connection requested by %s@%s", vis_user, remote_machine);
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ (void)snprintf(line_buf[i], N_CHARS, "talk: respond with: talk %s@%s",
+ vis_user, remote_machine);
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ (void)snprintf(line_buf[i], N_CHARS, " ");
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ bptr = big_buf;
+ *bptr++ = '\007'; /* send something to wake them up */
+ *bptr++ = '\r'; /* add a \r in case of raw mode */
+ *bptr++ = '\n';
+ for (i = 0; i < N_LINES; i++) {
+ /* copy the line into the big buffer */
+ lptr = line_buf[i];
+ while (*lptr != '\0')
+ *(bptr++) = *(lptr++);
+ /* pad out the rest of the lines with blanks */
+ for (j = sizes[i]; j < max_size + 2; j++)
+ *(bptr++) = ' ';
+ *(bptr++) = '\r'; /* add a \r in case of raw mode */
+ *(bptr++) = '\n';
+ }
+ *bptr = '\0';
+ iovec.iov_base = big_buf;
+ iovec.iov_len = bptr - big_buf;
+ /*
+ * we choose a timeout of RING_WAIT-5 seconds so that we don't
+ * stack up processes trying to write messages to a tty
+ * that is permanently blocked.
+ */
+ if (ttymsg(&iovec, 1, tty, RING_WAIT - 5) != NULL)
+ return (FAILED);
+
+ return (SUCCESS);
+}
diff --git a/remote_cmds/talkd.tproj/extern.h b/remote_cmds/talkd.tproj/extern.h
new file mode 100644
index 0000000..3b73236
--- /dev/null
+++ b/remote_cmds/talkd.tproj/extern.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002 M. Warner Losh. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/libexec/talkd/extern.h,v 1.3 2003/04/03 05:13:27 jmallett Exp $
+ */
+
+int announce(CTL_MSG *, const char *);
+int delete_invite(u_int32_t);
+void do_announce(CTL_MSG *, CTL_RESPONSE *);
+CTL_MSG *find_match(CTL_MSG *request);
+CTL_MSG *find_request(CTL_MSG *request);
+int find_user(const char *name, char *tty);
+void insert_table(CTL_MSG *, CTL_RESPONSE *);
+int new_id(void);
+int print_mesg(const char *, CTL_MSG *, const char *);
+void print_request(const char *, CTL_MSG *);
+void print_response(const char *, CTL_RESPONSE *);
+void process_request(CTL_MSG *mp, CTL_RESPONSE *rp);
+void timeout(int sig);
diff --git a/remote_cmds/talkd.tproj/ntalk.plist b/remote_cmds/talkd.tproj/ntalk.plist
new file mode 100644
index 0000000..2e63da2
--- /dev/null
+++ b/remote_cmds/talkd.tproj/ntalk.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.ntalkd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/ntalkd</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>ntalk</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/remote_cmds/talkd.tproj/ntalkd.8 b/remote_cmds/talkd.tproj/ntalkd.8
new file mode 100644
index 0000000..7fe81a5
--- /dev/null
+++ b/remote_cmds/talkd.tproj/ntalkd.8
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)talkd.8 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD: src/libexec/talkd/talkd.8,v 1.7 2003/09/08 19:57:18 ru Exp $
+.\"
+.Dd August 21, 2008
+.Dt TALKD 8
+.Os
+.Sh NAME
+.Nm talkd
+.Nd remote user communication server
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility
+is the server that notifies a user that someone else wants to
+initiate a conversation.
+It acts as a repository of invitations, responding to requests
+by clients wishing to rendezvous to hold a conversation.
+In normal operation, a client, the caller,
+initiates a rendezvous by sending a
+.Tn CTL_MSG
+to the server of
+type
+.Tn LOOK_UP
+(see
+.In protocols/talkd.h ) .
+This causes the server to search its invitation
+tables to check if an invitation currently exists for the caller
+(to speak to the callee specified in the message).
+.Pp
+If the lookup fails,
+the caller then sends an
+.Tn ANNOUNCE
+message causing the server to
+broadcast an announcement on the callee's login ports requesting contact.
+.Pp
+When the callee responds, the local server uses the
+recorded invitation to respond with the appropriate rendezvous
+address and the caller and callee client programs establish a
+stream connection through which the conversation takes place.
+.Sh CONFIGURATION
+The
+.Nm
+utility is managed by
+.Xr launchd 8
+as specified in the
+.Pa ntalk.plist
+property list.
+By default the property list contains the
+.Em Disabled
+key set to true, so
+.Nm
+is never invoked.
+.Pp
+Execute the following command as root to enable
+.Nm talkd :
+.Dl "launchctl load -w /System/Library/LaunchDaemons/ntalk.plist"
+.Pp
+.Sh SEE ALSO
+.Xr talk 1 ,
+.Xr write 1
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 .
diff --git a/remote_cmds/talkd.tproj/print.c b/remote_cmds/talkd.tproj/print.c
new file mode 100644
index 0000000..add853c
--- /dev/null
+++ b/remote_cmds/talkd.tproj/print.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/print.c,v 1.12 2003/04/03 05:13:27 jmallett Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/* debug print routines */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <protocols/talkd.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "extern.h"
+
+static const char *types[] =
+ { "leave_invite", "look_up", "delete", "announce" };
+#define NTYPES (sizeof (types) / sizeof (types[0]))
+static const char *answers[] =
+ { "success", "not_here", "failed", "machine_unknown", "permission_denied",
+ "unknown_request", "badversion", "badaddr", "badctladdr" };
+#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
+
+void
+print_request(const char *cp, CTL_MSG *mp)
+{
+ const char *tp;
+ char tbuf[80];
+
+ if (mp->type > NTYPES) {
+ (void)snprintf(tbuf, sizeof(tbuf), "type %d", mp->type);
+ tp = tbuf;
+ } else
+ tp = types[mp->type];
+ syslog(LOG_DEBUG, "%s: %s: id %lu, l_user %s, r_user %s, r_tty %s",
+ cp, tp, (long)mp->id_num, mp->l_name, mp->r_name, mp->r_tty);
+}
+
+void
+print_response(const char *cp, CTL_RESPONSE *rp)
+{
+ const char *tp, *ap;
+ char tbuf[80], abuf[80];
+
+ if (rp->type > NTYPES) {
+ (void)snprintf(tbuf, sizeof(tbuf), "type %d", rp->type);
+ tp = tbuf;
+ } else
+ tp = types[rp->type];
+ if (rp->answer > NANSWERS) {
+ (void)snprintf(abuf, sizeof(abuf), "answer %d", rp->answer);
+ ap = abuf;
+ } else
+ ap = answers[rp->answer];
+ syslog(LOG_DEBUG, "%s: %s: %s, id %d", cp, tp, ap, ntohl(rp->id_num));
+}
diff --git a/remote_cmds/talkd.tproj/process.c b/remote_cmds/talkd.tproj/process.c
new file mode 100644
index 0000000..e17d69e
--- /dev/null
+++ b/remote_cmds/talkd.tproj/process.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)process.c 8.2 (Berkeley) 11/16/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/process.c,v 1.11 2005/05/06 15:28:54 delphij Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * process.c handles the requests, which can be of three types:
+ * ANNOUNCE - announce to a user that a talk is wanted
+ * LEAVE_INVITE - insert the request into the table
+ * LOOK_UP - look up to see if a request is waiting in
+ * in the table for the local user
+ * DELETE - delete invitation
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/talkd.h>
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "extern.h"
+
+extern int debug;
+
+void
+process_request(CTL_MSG *mp, CTL_RESPONSE *rp)
+{
+ CTL_MSG *ptr;
+ char *s;
+
+ rp->vers = TALK_VERSION;
+ rp->type = mp->type;
+ rp->id_num = htonl(0);
+ if (mp->vers != TALK_VERSION) {
+ syslog(LOG_WARNING, "bad protocol version %d", mp->vers);
+ rp->answer = BADVERSION;
+ return;
+ }
+ mp->id_num = ntohl(mp->id_num);
+ mp->addr.sa_family = ntohs(mp->addr.sa_family);
+ if (mp->addr.sa_family != AF_INET) {
+ syslog(LOG_WARNING, "bad address, family %d",
+ mp->addr.sa_family);
+ rp->answer = BADADDR;
+ return;
+ }
+ mp->ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
+ if (mp->ctl_addr.sa_family != AF_INET) {
+ syslog(LOG_WARNING, "bad control address, family %d",
+ mp->ctl_addr.sa_family);
+ rp->answer = BADCTLADDR;
+ return;
+ }
+ for (s = mp->l_name; *s; s++)
+ if (!isprint(*s)) {
+ syslog(LOG_NOTICE, "illegal user name. Aborting");
+ rp->answer = FAILED;
+ return;
+ }
+ mp->pid = ntohl(mp->pid);
+ if (debug)
+ print_request("process_request", mp);
+ switch (mp->type) {
+
+ case ANNOUNCE:
+ do_announce(mp, rp);
+ break;
+
+ case LEAVE_INVITE:
+ ptr = find_request(mp);
+ if (ptr != (CTL_MSG *)0) {
+ rp->id_num = htonl(ptr->id_num);
+ rp->answer = SUCCESS;
+ } else
+ insert_table(mp, rp);
+ break;
+
+ case LOOK_UP:
+ ptr = find_match(mp);
+ if (ptr != (CTL_MSG *)0) {
+ rp->id_num = htonl(ptr->id_num);
+ rp->addr = ptr->addr;
+ rp->addr.sa_family = htons(ptr->addr.sa_family);
+ rp->answer = SUCCESS;
+ } else
+ rp->answer = NOT_HERE;
+ break;
+
+ case DELETE:
+ rp->answer = delete_invite(mp->id_num);
+ break;
+
+ default:
+ rp->answer = UNKNOWN_REQUEST;
+ break;
+ }
+ if (debug)
+ print_response("process_request", rp);
+}
+
+void
+do_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
+{
+ struct hostent *hp;
+ CTL_MSG *ptr;
+ int result;
+
+ /* see if the user is logged */
+ result = find_user(mp->r_name, mp->r_tty);
+ if (result != SUCCESS) {
+ rp->answer = result;
+ return;
+ }
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ hp = gethostbyaddr((char *)&satosin(&mp->ctl_addr)->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ if (hp == (struct hostent *)0) {
+ rp->answer = MACHINE_UNKNOWN;
+ return;
+ }
+ ptr = find_request(mp);
+ if (ptr == (CTL_MSG *) 0) {
+ insert_table(mp, rp);
+ rp->answer = announce(mp, hp->h_name);
+ return;
+ }
+ if (mp->id_num > ptr->id_num) {
+ /*
+ * This is an explicit re-announce, so update the id_num
+ * field to avoid duplicates and re-announce the talk.
+ */
+ ptr->id_num = new_id();
+ rp->id_num = htonl(ptr->id_num);
+ rp->answer = announce(mp, hp->h_name);
+ } else {
+ /* a duplicated request, so ignore it */
+ rp->id_num = htonl(ptr->id_num);
+ rp->answer = SUCCESS;
+ }
+}
+
+#ifdef __APPLE__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+
+/*
+ * Search utmp for the local user
+ */
+int
+find_user(const char *name, char *tty)
+{
+#ifdef __APPLE__
+ struct utmpx *u;
+ int status;
+ struct stat statb;
+
+ char line[sizeof(u->ut_line) + 1];
+ char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
+
+ setutxent();
+#define SCMPN(a, b) strncmp(a, b, sizeof (a))
+ status = NOT_HERE;
+ (void) strcpy(ftty, _PATH_DEV);
+ while ((u = getutxent()) != NULL)
+ if (u->ut_type == USER_PROCESS && SCMPN(u->ut_user, name) == 0) {
+ strncpy(line, u->ut_line, sizeof(u->ut_line));
+ line[sizeof(u->ut_line)] = '\0';
+ if (*tty == '\0') {
+ status = PERMISSION_DENIED;
+ /* no particular tty was requested */
+ (void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
+ line);
+ if (stat(ftty, &statb) == 0) {
+ if (!(statb.st_mode & 020))
+ continue;
+ (void) strcpy(tty, line);
+ status = SUCCESS;
+ break;
+ }
+ }
+ if (strcmp(line, tty) == 0) {
+ status = SUCCESS;
+ break;
+ }
+ }
+ endutxent();
+#else
+ struct utmp ubuf;
+ int status;
+ FILE *fd;
+ struct stat statb;
+ time_t best = 0;
+ char line[sizeof(ubuf.ut_line) + 1];
+ char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
+
+ if ((fd = fopen(_PATH_UTMP, "r")) == NULL) {
+ warnx("can't read %s", _PATH_UTMP);
+ return (FAILED);
+ }
+#define SCMPN(a, b) strncmp(a, b, sizeof (a))
+ status = NOT_HERE;
+ (void) strcpy(ftty, _PATH_DEV);
+ while (fread((char *) &ubuf, sizeof ubuf, 1, fd) == 1)
+ if (SCMPN(ubuf.ut_name, name) == 0) {
+ strncpy(line, ubuf.ut_line, sizeof(ubuf.ut_line));
+ line[sizeof(ubuf.ut_line)] = '\0';
+ if (*tty == '\0' || best != 0) {
+ if (best == 0)
+ status = PERMISSION_DENIED;
+ /* no particular tty was requested */
+ (void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
+ line);
+ if (stat(ftty, &statb) == 0) {
+ if (!(statb.st_mode & 020))
+ continue;
+ if (statb.st_atime > best) {
+ best = statb.st_atime;
+ (void) strcpy(tty, line);
+ status = SUCCESS;
+ continue;
+ }
+ }
+ }
+ if (strcmp(line, tty) == 0) {
+ status = SUCCESS;
+ break;
+ }
+ }
+ fclose(fd);
+#endif
+ return (status);
+}
diff --git a/remote_cmds/talkd.tproj/table.c b/remote_cmds/talkd.tproj/table.c
new file mode 100644
index 0000000..77c7d33
--- /dev/null
+++ b/remote_cmds/talkd.tproj/table.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)table.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/table.c,v 1.9 2003/04/03 05:13:27 jmallett Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Routines to handle insertion, deletion, etc on the table
+ * of requests kept by the daemon. Nothing fancy here, linear
+ * search on a double-linked list. A time is kept with each
+ * entry so that overly old invitations can be eliminated.
+ *
+ * Consider this a mis-guided attempt at modularity
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/talkd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define MAX_ID 16000 /* << 2^15 so I don't have sign troubles */
+
+#define NIL ((TABLE_ENTRY *)0)
+
+extern int debug;
+struct timeval tp;
+struct timezone txp;
+
+typedef struct table_entry TABLE_ENTRY;
+
+struct table_entry {
+ CTL_MSG request;
+ long time;
+ TABLE_ENTRY *next;
+ TABLE_ENTRY *last;
+};
+
+static void delete(TABLE_ENTRY *);
+
+TABLE_ENTRY *table = NIL;
+
+/*
+ * Look in the table for an invitation that matches the current
+ * request looking for an invitation
+ */
+CTL_MSG *
+find_match(CTL_MSG *request)
+{
+ TABLE_ENTRY *ptr;
+ time_t current_time;
+
+ gettimeofday(&tp, &txp);
+ current_time = tp.tv_sec;
+ if (debug)
+ print_request("find_match", request);
+ for (ptr = table; ptr != NIL; ptr = ptr->next) {
+ if ((ptr->time - current_time) > MAX_LIFE) {
+ /* the entry is too old */
+ if (debug)
+ print_request("deleting expired entry",
+ &ptr->request);
+ delete(ptr);
+ continue;
+ }
+ if (debug)
+ print_request("", &ptr->request);
+ if (strcmp(request->l_name, ptr->request.r_name) == 0 &&
+ strcmp(request->r_name, ptr->request.l_name) == 0 &&
+ ptr->request.type == LEAVE_INVITE)
+ return (&ptr->request);
+ }
+ return ((CTL_MSG *)0);
+}
+
+/*
+ * Look for an identical request, as opposed to a complimentary
+ * one as find_match does
+ */
+CTL_MSG *
+find_request(CTL_MSG *request)
+{
+ TABLE_ENTRY *ptr;
+ time_t current_time;
+
+ gettimeofday(&tp, &txp);
+ current_time = tp.tv_sec;
+ /*
+ * See if this is a repeated message, and check for
+ * out of date entries in the table while we are it.
+ */
+ if (debug)
+ print_request("find_request", request);
+ for (ptr = table; ptr != NIL; ptr = ptr->next) {
+ if ((ptr->time - current_time) > MAX_LIFE) {
+ /* the entry is too old */
+ if (debug)
+ print_request("deleting expired entry",
+ &ptr->request);
+ delete(ptr);
+ continue;
+ }
+ if (debug)
+ print_request("", &ptr->request);
+ if (strcmp(request->r_name, ptr->request.r_name) == 0 &&
+ strcmp(request->l_name, ptr->request.l_name) == 0 &&
+ request->type == ptr->request.type &&
+ request->pid == ptr->request.pid) {
+ /* update the time if we 'touch' it */
+ ptr->time = current_time;
+ return (&ptr->request);
+ }
+ }
+ return ((CTL_MSG *)0);
+}
+
+void
+insert_table(CTL_MSG *request, CTL_RESPONSE *response)
+{
+ TABLE_ENTRY *ptr;
+ time_t current_time;
+
+ gettimeofday(&tp, &txp);
+ current_time = tp.tv_sec;
+ request->id_num = new_id();
+ response->id_num = htonl(request->id_num);
+ /* insert a new entry into the top of the list */
+ ptr = (TABLE_ENTRY *)malloc(sizeof(TABLE_ENTRY));
+ if (ptr == NIL) {
+ syslog(LOG_ERR, "insert_table: Out of memory");
+ _exit(1);
+ }
+ ptr->time = current_time;
+ ptr->request = *request;
+ ptr->next = table;
+ if (ptr->next != NIL)
+ ptr->next->last = ptr;
+ ptr->last = NIL;
+ table = ptr;
+}
+
+/*
+ * Generate a unique non-zero sequence number
+ */
+int
+new_id(void)
+{
+ static int current_id = 0;
+
+ current_id = (current_id + 1) % MAX_ID;
+ /* 0 is reserved, helps to pick up bugs */
+ if (current_id == 0)
+ current_id = 1;
+ return (current_id);
+}
+
+/*
+ * Delete the invitation with id 'id_num'
+ */
+int
+delete_invite(u_int32_t id_num)
+{
+ TABLE_ENTRY *ptr;
+
+ ptr = table;
+ if (debug)
+ syslog(LOG_DEBUG, "delete_invite(%d)", id_num);
+ for (ptr = table; ptr != NIL; ptr = ptr->next) {
+ if (ptr->request.id_num == id_num)
+ break;
+ if (debug)
+ print_request("", &ptr->request);
+ }
+ if (ptr != NIL) {
+ delete(ptr);
+ return (SUCCESS);
+ }
+ return (NOT_HERE);
+}
+
+/*
+ * Classic delete from a double-linked list
+ */
+static void
+delete(TABLE_ENTRY *ptr)
+{
+
+ if (debug)
+ print_request("delete", &ptr->request);
+ if (table == ptr)
+ table = ptr->next;
+ else if (ptr->last != NIL)
+ ptr->last->next = ptr->next;
+ if (ptr->next != NIL)
+ ptr->next->last = ptr->last;
+ free((char *)ptr);
+}
diff --git a/remote_cmds/talkd.tproj/talkd.c b/remote_cmds/talkd.tproj/talkd.c
new file mode 100644
index 0000000..1f28cb8
--- /dev/null
+++ b/remote_cmds/talkd.tproj/talkd.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)talkd.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/talkd.c,v 1.17 2004/06/14 22:44:13 bms Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * The top level of the daemon, the format is heavily borrowed
+ * from rwhod.c. Basically: find out who and where you are;
+ * disconnect all descriptors and ttys, and then endless
+ * loop on waiting for and processing requests
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <protocols/talkd.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+CTL_MSG request;
+CTL_RESPONSE response;
+
+int debug = 0;
+long lastmsgtime;
+
+char hostname[MAXHOSTNAMELEN + 1];
+
+#define TIMEOUT 30
+#define MAXIDLE 120
+
+int
+main(int argc, char *argv[])
+{
+ register CTL_MSG *mp = &request;
+ int cc;
+ struct sockaddr ctl_addr;
+
+ /*
+ * removed so ntalkd can run in tty sandbox
+ */
+ if (getuid())
+ errx(1, "getuid: not super-user");
+
+ openlog("talkd", LOG_PID, LOG_DAEMON);
+ if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
+ syslog(LOG_ERR, "gethostname: %m");
+ _exit(1);
+ }
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (chdir(_PATH_DEV) < 0) {
+ syslog(LOG_ERR, "chdir: %s: %m", _PATH_DEV);
+ _exit(1);
+ }
+ if (argc > 1 && strcmp(argv[1], "-d") == 0)
+ debug = 1;
+ signal(SIGALRM, timeout);
+ alarm(TIMEOUT);
+ for (;;) {
+ cc = recv(0, (char *)mp, sizeof(*mp), 0);
+ if (cc != sizeof (*mp)) {
+ if (cc < 0 && errno != EINTR)
+ syslog(LOG_WARNING, "recv: %m");
+ continue;
+ }
+ lastmsgtime = time(0);
+ (void)memcpy(&ctl_addr, &mp->ctl_addr, sizeof(ctl_addr));
+ ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
+ ctl_addr.sa_len = sizeof(ctl_addr);
+ process_request(mp, &response);
+ /* can block here, is this what I want? */
+ cc = sendto(STDIN_FILENO, (char *)&response,
+ sizeof(response), 0, &ctl_addr, sizeof(ctl_addr));
+ if (cc != sizeof (response))
+ syslog(LOG_WARNING, "sendto: %m");
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+void
+timeout(int sig __unused)
+{
+ int save_errno = errno;
+
+ if (time(0) - lastmsgtime >= MAXIDLE)
+ _exit(0);
+ alarm(TIMEOUT);
+ errno = save_errno;
+}
diff --git a/remote_cmds/telnet.tproj/Makefile b/remote_cmds/telnet.tproj/Makefile
new file mode 100644
index 0000000..dc8569b
--- /dev/null
+++ b/remote_cmds/telnet.tproj/Makefile
@@ -0,0 +1,18 @@
+Project = telnet
+Install_Dir = /usr/local/bin
+
+HFILES = externs.h fdset.h general.h krb4-proto.h ring.h types.h\
+ defines.h misc.h misc-proto.h
+CFILES = authenc.c commands.c main.c network.c ring.c sys_bsd.c\
+ telnet.c terminal.c tn3270.c utilities.c
+
+Extra_CC_Flags = -Wall -Werror -Wno-string-plus-int -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_CC_Flags += -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK \
+ -DAUTHENTICATION -DKRB5 -DSKEY -DIPSEC -DINET6 -DFORWARD
+ # -DENCRYPTION -DKRB4
+Extra_LD_Libraries = -lcurses -lkrb4 -lkrb5 -lipsec -ltelnet
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/telnet.tproj/authenc.c b/remote_cmds/telnet.tproj/authenc.c
new file mode 100644
index 0000000..258a013
--- /dev/null
+++ b/remote_cmds/telnet.tproj/authenc.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/authenc.c,v 1.6 2003/05/04 02:54:48 obrien Exp $");
+
+#ifdef AUTHENTICATION
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <libtelnet/encrypt.h>
+#include <libtelnet/misc.h>
+
+#include "general.h"
+#include "ring.h"
+#include "externs.h"
+#include "defines.h"
+#include "types.h"
+
+int
+net_write(unsigned char *str, int len)
+{
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, str, len);
+ if (str[0] == IAC && str[1] == SE)
+ printsub('>', &str[2], len-2);
+ return(len);
+ }
+ return(0);
+}
+
+void
+net_encrypt(void)
+{
+#ifdef ENCRYPTION
+ if (encrypt_output)
+ ring_encrypt(&netoring, encrypt_output);
+ else
+ ring_clearto(&netoring);
+#endif /* ENCRYPTION */
+}
+
+int
+telnet_spin(void)
+{
+ return(-1);
+}
+
+char *
+telnet_getenv(char *val)
+{
+ return((char *)env_getvalue((unsigned char *)val));
+}
+
+char *
+telnet_gets(const char *prom, char *result, int length, int echo)
+{
+ extern int globalmode;
+ int om = globalmode;
+ char *res;
+
+ TerminalNewMode(-1);
+ if (echo) {
+ printf("%s", prom);
+ res = fgets(result, length, stdin);
+ } else if ((res = getpass(prom))) {
+ strncpy(result, res, length);
+ res = result;
+ }
+ TerminalNewMode(om);
+ return(res);
+}
+#endif /* AUTHENTICATION */
diff --git a/remote_cmds/telnet.tproj/commands.c b/remote_cmds/telnet.tproj/commands.c
new file mode 100644
index 0000000..56a0794
--- /dev/null
+++ b/remote_cmds/telnet.tproj/commands.c
@@ -0,0 +1,3063 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/commands.c,v 1.35 2005/02/28 12:46:52 tobez Exp $");
+
+/* Use RFC 2292 constants in <netinet6/in6.h> */
+#define __APPLE_USE_RFC_2292
+
+#include <sys/param.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/telnet.h>
+#include <arpa/inet.h>
+
+#include "general.h"
+
+#include "ring.h"
+
+#include "externs.h"
+#include "defines.h"
+#include "types.h"
+#include "misc.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+typedef int (*intrtn_t)(int, char **);
+
+#ifdef AUTHENTICATION
+extern int auth_togdebug(int);
+#endif
+#ifdef ENCRYPTION
+extern int EncryptAutoEnc(int);
+extern int EncryptAutoDec(int);
+extern int EncryptDebug(int);
+extern int EncryptVerbose(int);
+#endif /* ENCRYPTION */
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+int tos = -1;
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
+
+char *hostname;
+static char _hostname[MAXHOSTNAMELEN];
+
+static int help(int, char **);
+static int call(intrtn_t, ...);
+static void cmdrc(char *, char *);
+#ifdef INET6
+static int switch_af(struct addrinfo **);
+#endif
+static int togglehelp(void);
+static int send_tncmd(void (*)(int, int), const char *, char *);
+static int setmod(int);
+static int clearmode(int);
+static int modehelp(void);
+#ifndef __APPLE__
+static int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *);
+#endif
+
+typedef struct {
+ const char *name; /* command name */
+ const char *help; /* help string (NULL for no help) */
+ int (*handler)(int, char **); /* routine which executes command */
+ int needconnect; /* Do we need to be connected to execute? */
+} Command;
+
+static char line[256];
+static char saveline[256];
+static int margc;
+static char *margv[20];
+
+#ifdef OPIE
+#include <sys/wait.h>
+#define PATH_OPIEKEY "/usr/bin/opiekey"
+static int
+opie_calc(int argc, char *argv[])
+{
+ int status;
+
+ if(argc != 3) {
+ printf("%s sequence challenge\n", argv[0]);
+ return (0);
+ }
+
+ switch(fork()) {
+ case 0:
+ execv(PATH_OPIEKEY, argv);
+ exit (1);
+ case -1:
+ perror("fork");
+ break;
+ default:
+ (void) wait(&status);
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ }
+ return (0);
+}
+#endif
+
+static void
+makeargv(void)
+{
+ char *cp, *cp2, c;
+ char **argp = margv;
+
+ margc = 0;
+ cp = line;
+ if (*cp == '!') { /* Special case shell escape */
+ strcpy(saveline, line); /* save for shell command */
+ *argp++ = strdup("!"); /* No room in string to get this */
+ margc++;
+ cp++;
+ }
+ while ((c = *cp)) {
+ int inquote = 0;
+ while (isspace(c))
+ c = *++cp;
+ if (c == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ for (cp2 = cp; c != '\0'; c = *++cp) {
+ if (inquote) {
+ if (c == inquote) {
+ inquote = 0;
+ continue;
+ }
+ } else {
+ if (c == '\\') {
+ if ((c = *++cp) == '\0')
+ break;
+ } else if (c == '"') {
+ inquote = '"';
+ continue;
+ } else if (c == '\'') {
+ inquote = '\'';
+ continue;
+ } else if (isspace(c))
+ break;
+ }
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+ if (c == '\0')
+ break;
+ cp++;
+ }
+ *argp++ = 0;
+}
+
+/*
+ * Make a character string into a number.
+ *
+ * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
+ */
+
+static int
+special(char *s)
+{
+ char c;
+ char b;
+
+ switch (*s) {
+ case '^':
+ b = *++s;
+ if (b == '?') {
+ c = b | 0x40; /* DEL */
+ } else {
+ c = b & 0x1f;
+ }
+ break;
+ default:
+ c = *s;
+ break;
+ }
+ return c;
+}
+
+/*
+ * Construct a control character sequence
+ * for a special character.
+ */
+static const char *
+control(cc_t c)
+{
+ static char buf[5];
+ /*
+ * The only way I could get the Sun 3.5 compiler
+ * to shut up about
+ * if ((unsigned int)c >= 0x80)
+ * was to assign "c" to an unsigned int variable...
+ * Arggg....
+ */
+ unsigned int uic = (unsigned int)c;
+
+ if (uic == 0x7f)
+ return ("^?");
+ if (c == (cc_t)_POSIX_VDISABLE) {
+ return "off";
+ }
+ if (uic >= 0x80) {
+ buf[0] = '\\';
+ buf[1] = ((c>>6)&07) + '0';
+ buf[2] = ((c>>3)&07) + '0';
+ buf[3] = (c&07) + '0';
+ buf[4] = 0;
+ } else if (uic >= 0x20) {
+ buf[0] = c;
+ buf[1] = 0;
+ } else {
+ buf[0] = '^';
+ buf[1] = '@'+c;
+ buf[2] = 0;
+ }
+ return (buf);
+}
+
+/*
+ * The following are data structures and routines for
+ * the "send" command.
+ *
+ */
+
+struct sendlist {
+ const char *name; /* How user refers to it (case independent) */
+ const char *help; /* Help information (0 ==> no help) */
+ int needconnect; /* Need to be connected */
+ int narg; /* Number of arguments */
+ int (*handler)(char *, ...); /* Routine to perform (for special ops) */
+ int nbyte; /* Number of bytes to send this command */
+ int what; /* Character to be sent (<0 ==> special) */
+};
+
+
+static int
+ send_esc(void),
+ send_help(void),
+ send_docmd(char *),
+ send_dontcmd(char *),
+ send_willcmd(char *),
+ send_wontcmd(char *);
+
+static struct sendlist Sendlist[] = {
+ { "ao", "Send Telnet Abort output", 1, 0, NULL, 2, AO },
+ { "ayt", "Send Telnet 'Are You There'", 1, 0, NULL, 2, AYT },
+ { "brk", "Send Telnet Break", 1, 0, NULL, 2, BREAK },
+ { "break", NULL, 1, 0, NULL, 2, BREAK },
+ { "ec", "Send Telnet Erase Character", 1, 0, NULL, 2, EC },
+ { "el", "Send Telnet Erase Line", 1, 0, NULL, 2, EL },
+ { "escape", "Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 },
+ { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA },
+ { "ip", "Send Telnet Interrupt Process",1, 0, NULL, 2, IP },
+ { "intp", NULL, 1, 0, NULL, 2, IP },
+ { "interrupt", NULL, 1, 0, NULL, 2, IP },
+ { "intr", NULL, 1, 0, NULL, 2, IP },
+ { "nop", "Send Telnet 'No operation'", 1, 0, NULL, 2, NOP },
+ { "eor", "Send Telnet 'End of Record'", 1, 0, NULL, 2, EOR },
+ { "abort", "Send Telnet 'Abort Process'", 1, 0, NULL, 2, ABORT },
+ { "susp", "Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP },
+ { "eof", "Send Telnet End of File Character", 1, 0, NULL, 2, xEOF },
+ { "synch", "Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 },
+ { "getstatus", "Send request for STATUS", 1, 0, (int (*)(char *, ...))get_status, 6, 0 },
+ { "?", "Display send options", 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
+ { "help", NULL, 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
+ { "do", NULL, 0, 1, (int (*)(char *, ...))send_docmd, 3, 0 },
+ { "dont", NULL, 0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 },
+ { "will", NULL, 0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 },
+ { "wont", NULL, 0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 },
+ { NULL, NULL, 0, 0, NULL, 0, 0 }
+};
+
+#define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
+ sizeof(struct sendlist)))
+
+static int
+sendcmd(int argc, char *argv[])
+{
+ int count; /* how many bytes we are going to need to send */
+ int i;
+ struct sendlist *s; /* pointer to current command */
+ int success = 0;
+ int needconnect = 0;
+
+ if (argc < 2) {
+ printf("need at least one argument for 'send' command\n");
+ printf("'send ?' for help\n");
+ return 0;
+ }
+ /*
+ * First, validate all the send arguments.
+ * In addition, we see how much space we are going to need, and
+ * whether or not we will be doing a "SYNCH" operation (which
+ * flushes the network queue).
+ */
+ count = 0;
+ for (i = 1; i < argc; i++) {
+ s = GETSEND(argv[i]);
+ if (s == 0) {
+ printf("Unknown send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return 0;
+ } else if (Ambiguous((void *)s)) {
+ printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return 0;
+ }
+ if (i + s->narg >= argc) {
+ fprintf(stderr,
+ "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
+ s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
+ return 0;
+ }
+ count += s->nbyte;
+ if ((void *)s->handler == (void *)send_help) {
+ send_help();
+ return 0;
+ }
+
+ i += s->narg;
+ needconnect += s->needconnect;
+ }
+ if (!connected && needconnect) {
+ printf("?Need to be connected first.\n");
+ printf("'send ?' for help\n");
+ return 0;
+ }
+ /* Now, do we have enough room? */
+ if (NETROOM() < count) {
+ printf("There is not enough room in the buffer TO the network\n");
+ printf("to process your request. Nothing will be done.\n");
+ printf("('send synch' will throw away most data in the network\n");
+ printf("buffer, if this might help.)\n");
+ return 0;
+ }
+ /* OK, they are all OK, now go through again and actually send */
+ count = 0;
+ for (i = 1; i < argc; i++) {
+ if ((s = GETSEND(argv[i])) == 0) {
+ fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
+ quit();
+ /*NOTREACHED*/
+ }
+ if (s->handler) {
+ count++;
+ success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
+ (s->narg > 1) ? argv[i+2] : 0);
+ i += s->narg;
+ } else {
+ NET2ADD(IAC, s->what);
+ printoption("SENT", IAC, s->what);
+ }
+ }
+ return (count == success);
+}
+
+static int
+send_esc(void)
+{
+ NETADD(escape);
+ return 1;
+}
+
+static int
+send_docmd(char *name)
+{
+ return(send_tncmd(send_do, "do", name));
+}
+
+static int
+send_dontcmd(name)
+ char *name;
+{
+ return(send_tncmd(send_dont, "dont", name));
+}
+
+static int
+send_willcmd(char *name)
+{
+ return(send_tncmd(send_will, "will", name));
+}
+
+static int
+send_wontcmd(char *name)
+{
+ return(send_tncmd(send_wont, "wont", name));
+}
+
+static int
+send_tncmd(void (*func)(int, int), const char *cmd, char *name)
+{
+ char **cpp;
+ extern char *telopts[];
+ int val = 0;
+
+ if (isprefix(name, "help") || isprefix(name, "?")) {
+ int col, len;
+
+ printf("usage: send %s <value|option>\n", cmd);
+ printf("\"value\" must be from 0 to 255\n");
+ printf("Valid options are:\n\t");
+
+ col = 8;
+ for (cpp = telopts; *cpp; cpp++) {
+ len = strlen(*cpp) + 3;
+ if (col + len > 65) {
+ printf("\n\t");
+ col = 8;
+ }
+ printf(" \"%s\"", *cpp);
+ col += len;
+ }
+ printf("\n");
+ return 0;
+ }
+ cpp = (char **)genget(name, telopts, sizeof(char *));
+ if (Ambiguous(cpp)) {
+ fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
+ name, cmd);
+ return 0;
+ }
+ if (cpp) {
+ val = cpp - telopts;
+ } else {
+ char *cp = name;
+
+ while (*cp >= '0' && *cp <= '9') {
+ val *= 10;
+ val += *cp - '0';
+ cp++;
+ }
+ if (*cp != 0) {
+ fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
+ name, cmd);
+ return 0;
+ } else if (val < 0 || val > 255) {
+ fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
+ name, cmd);
+ return 0;
+ }
+ }
+ if (!connected) {
+ printf("?Need to be connected first.\n");
+ return 0;
+ }
+ (*func)(val, 1);
+ return 1;
+}
+
+static int
+send_help(void)
+{
+ struct sendlist *s; /* pointer to current command */
+ for (s = Sendlist; s->name; s++) {
+ if (s->help)
+ printf("%-15s %s\n", s->name, s->help);
+ }
+ return(0);
+}
+
+/*
+ * The following are the routines and data structures referred
+ * to by the arguments to the "toggle" command.
+ */
+
+static int
+lclchars(void)
+{
+ donelclchars = 1;
+ return 1;
+}
+
+static int
+togdebug(void)
+{
+#ifndef NOT43
+ if (net > 0 &&
+ (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
+ perror("setsockopt (SO_DEBUG)");
+ }
+#else /* NOT43 */
+ if (telnet_debug) {
+ if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
+ perror("setsockopt (SO_DEBUG)");
+ } else
+ printf("Cannot turn off socket debugging\n");
+#endif /* NOT43 */
+ return 1;
+}
+
+
+static int
+togcrlf(void)
+{
+ if (crlf) {
+ printf("Will send carriage returns as telnet <CR><LF>.\n");
+ } else {
+ printf("Will send carriage returns as telnet <CR><NUL>.\n");
+ }
+ return 1;
+}
+
+int binmode;
+
+static int
+togbinary(int val)
+{
+ donebinarytoggle = 1;
+
+ if (val >= 0) {
+ binmode = val;
+ } else {
+ if (my_want_state_is_will(TELOPT_BINARY) &&
+ my_want_state_is_do(TELOPT_BINARY)) {
+ binmode = 1;
+ } else if (my_want_state_is_wont(TELOPT_BINARY) &&
+ my_want_state_is_dont(TELOPT_BINARY)) {
+ binmode = 0;
+ }
+ val = binmode ? 0 : 1;
+ }
+
+ if (val == 1) {
+ if (my_want_state_is_will(TELOPT_BINARY) &&
+ my_want_state_is_do(TELOPT_BINARY)) {
+ printf("Already operating in binary mode with remote host.\n");
+ } else {
+ printf("Negotiating binary mode with remote host.\n");
+ tel_enter_binary(3);
+ }
+ } else {
+ if (my_want_state_is_wont(TELOPT_BINARY) &&
+ my_want_state_is_dont(TELOPT_BINARY)) {
+ printf("Already in network ascii mode with remote host.\n");
+ } else {
+ printf("Negotiating network ascii mode with remote host.\n");
+ tel_leave_binary(3);
+ }
+ }
+ return 1;
+}
+
+static int
+togrbinary(int val)
+{
+ donebinarytoggle = 1;
+
+ if (val == -1)
+ val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
+
+ if (val == 1) {
+ if (my_want_state_is_do(TELOPT_BINARY)) {
+ printf("Already receiving in binary mode.\n");
+ } else {
+ printf("Negotiating binary mode on input.\n");
+ tel_enter_binary(1);
+ }
+ } else {
+ if (my_want_state_is_dont(TELOPT_BINARY)) {
+ printf("Already receiving in network ascii mode.\n");
+ } else {
+ printf("Negotiating network ascii mode on input.\n");
+ tel_leave_binary(1);
+ }
+ }
+ return 1;
+}
+
+static int
+togxbinary(int val)
+{
+ donebinarytoggle = 1;
+
+ if (val == -1)
+ val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
+
+ if (val == 1) {
+ if (my_want_state_is_will(TELOPT_BINARY)) {
+ printf("Already transmitting in binary mode.\n");
+ } else {
+ printf("Negotiating binary mode on output.\n");
+ tel_enter_binary(2);
+ }
+ } else {
+ if (my_want_state_is_wont(TELOPT_BINARY)) {
+ printf("Already transmitting in network ascii mode.\n");
+ } else {
+ printf("Negotiating network ascii mode on output.\n");
+ tel_leave_binary(2);
+ }
+ }
+ return 1;
+}
+
+struct togglelist {
+ const char *name; /* name of toggle */
+ const char *help; /* help message */
+ int (*handler)(int); /* routine to do actual setting */
+ int *variable;
+ const char *actionexplanation;
+};
+
+static struct togglelist Togglelist[] = {
+ { "autoflush",
+ "flushing of output when sending interrupt characters",
+ 0,
+ &autoflush,
+ "flush output when sending interrupt characters" },
+ { "autosynch",
+ "automatic sending of interrupt characters in urgent mode",
+ 0,
+ &autosynch,
+ "send interrupt characters in urgent mode" },
+#ifdef AUTHENTICATION
+ { "autologin",
+ "automatic sending of login and/or authentication info",
+ 0,
+ &autologin,
+ "send login name and/or authentication information" },
+ { "authdebug",
+ "Toggle authentication debugging",
+ auth_togdebug,
+ 0,
+ "print authentication debugging information" },
+#endif
+#ifdef ENCRYPTION
+ { "autoencrypt",
+ "automatic encryption of data stream",
+ EncryptAutoEnc,
+ 0,
+ "automatically encrypt output" },
+ { "autodecrypt",
+ "automatic decryption of data stream",
+ EncryptAutoDec,
+ 0,
+ "automatically decrypt input" },
+ { "verbose_encrypt",
+ "Toggle verbose encryption output",
+ EncryptVerbose,
+ 0,
+ "print verbose encryption output" },
+ { "encdebug",
+ "Toggle encryption debugging",
+ EncryptDebug,
+ 0,
+ "print encryption debugging information" },
+#endif /* ENCRYPTION */
+ { "skiprc",
+ "don't read ~/.telnetrc file",
+ 0,
+ &skiprc,
+ "skip reading of ~/.telnetrc file" },
+ { "binary",
+ "sending and receiving of binary data",
+ togbinary,
+ 0,
+ 0 },
+ { "inbinary",
+ "receiving of binary data",
+ togrbinary,
+ 0,
+ 0 },
+ { "outbinary",
+ "sending of binary data",
+ togxbinary,
+ 0,
+ 0 },
+ { "crlf",
+ "sending carriage returns as telnet <CR><LF>",
+ (int (*)(int))togcrlf,
+ &crlf,
+ 0 },
+ { "crmod",
+ "mapping of received carriage returns",
+ 0,
+ &crmod,
+ "map carriage return on output" },
+ { "localchars",
+ "local recognition of certain control characters",
+ (int (*)(int))lclchars,
+ &localchars,
+ "recognize certain control characters" },
+ { " ", "", NULL, NULL, NULL }, /* empty line */
+ { "debug",
+ "debugging",
+ (int (*)(int))togdebug,
+ &telnet_debug,
+ "turn on socket level debugging" },
+ { "netdata",
+ "printing of hexadecimal network data (debugging)",
+ 0,
+ &netdata,
+ "print hexadecimal representation of network traffic" },
+ { "prettydump",
+ "output of \"netdata\" to user readable format (debugging)",
+ 0,
+ &prettydump,
+ "print user readable output for \"netdata\"" },
+ { "options",
+ "viewing of options processing (debugging)",
+ 0,
+ &showoptions,
+ "show option processing" },
+ { "termdata",
+ "(debugging) toggle printing of hexadecimal terminal data",
+ 0,
+ &termdata,
+ "print hexadecimal representation of terminal traffic" },
+ { "?",
+ NULL,
+ (int (*)(int))togglehelp,
+ NULL,
+ NULL },
+ { NULL, NULL, NULL, NULL, NULL },
+ { "help",
+ NULL,
+ (int (*)(int))togglehelp,
+ NULL,
+ NULL },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+static int
+togglehelp(void)
+{
+ struct togglelist *c;
+
+ for (c = Togglelist; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s toggle %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+ printf("\n");
+ printf("%-15s %s\n", "?", "display help information");
+ return 0;
+}
+
+static void
+settogglehelp(int set)
+{
+ struct togglelist *c;
+
+ for (c = Togglelist; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
+ c->help);
+ else
+ printf("\n");
+ }
+ }
+}
+
+#define GETTOGGLE(name) (struct togglelist *) \
+ genget(name, (char **) Togglelist, sizeof(struct togglelist))
+
+static int
+toggle(int argc, char *argv[])
+{
+ int retval = 1;
+ char *name;
+ struct togglelist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
+ return 0;
+ }
+ argc--;
+ argv++;
+ while (argc--) {
+ name = *argv++;
+ c = GETTOGGLE(name);
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
+ name);
+ return 0;
+ } else if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
+ name);
+ return 0;
+ } else {
+ if (c->variable) {
+ *c->variable = !*c->variable; /* invert it */
+ if (c->actionexplanation) {
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ }
+ if (c->handler) {
+ retval &= (*c->handler)(-1);
+ }
+ }
+ }
+ return retval;
+}
+
+/*
+ * The following perform the "set" command.
+ */
+
+#ifdef USE_TERMIO
+struct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 };
+#endif
+
+struct setlist {
+ const char *name; /* name */
+ const char *help; /* help information */
+ void (*handler)(char *);
+ cc_t *charp; /* where it is located at */
+};
+
+static struct setlist Setlist[] = {
+#ifdef KLUDGELINEMODE
+ { "echo", "character to toggle local echoing on/off", NULL, &echoc },
+#endif
+ { "escape", "character to escape back to telnet command mode", NULL, &escape },
+ { "rlogin", "rlogin escape character", 0, &rlogin },
+ { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
+ { " ", "", NULL, NULL },
+ { " ", "The following need 'localchars' to be toggled true", NULL, NULL },
+ { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp },
+ { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp },
+ { "quit", "character to cause an Abort process", NULL, termQuitCharp },
+ { "eof", "character to cause an EOF ", NULL, termEofCharp },
+ { " ", "", NULL, NULL },
+ { " ", "The following are for local editing in linemode", NULL, NULL },
+ { "erase", "character to use to erase a character", NULL, termEraseCharp },
+ { "kill", "character to use to erase a line", NULL, termKillCharp },
+ { "lnext", "character to use for literal next", NULL, termLiteralNextCharp },
+ { "susp", "character to cause a Suspend Process", NULL, termSuspCharp },
+ { "reprint", "character to use for line reprint", NULL, termRprntCharp },
+ { "worderase", "character to use to erase a word", NULL, termWerasCharp },
+ { "start", "character to use for XON", NULL, termStartCharp },
+ { "stop", "character to use for XOFF", NULL, termStopCharp },
+ { "forw1", "alternate end of line character", NULL, termForw1Charp },
+ { "forw2", "alternate end of line character", NULL, termForw2Charp },
+ { "ayt", "alternate AYT character", NULL, termAytCharp },
+ { NULL, NULL, NULL, NULL }
+};
+
+static struct setlist *
+getset(char *name)
+{
+ return (struct setlist *)
+ genget(name, (char **) Setlist, sizeof(struct setlist));
+}
+
+void
+set_escape_char(char *s)
+{
+ if (rlogin != _POSIX_VDISABLE) {
+ rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
+ printf("Telnet rlogin escape character is '%s'.\n",
+ control(rlogin));
+ } else {
+ escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
+ printf("Telnet escape character is '%s'.\n", control(escape));
+ }
+}
+
+static int
+setcmd(int argc, char *argv[])
+{
+ int value;
+ struct setlist *ct;
+ struct togglelist *c;
+
+ if (argc < 2 || argc > 3) {
+ printf("Format is 'set Name Value'\n'set ?' for help.\n");
+ return 0;
+ }
+ if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
+ for (ct = Setlist; ct->name; ct++)
+ printf("%-15s %s\n", ct->name, ct->help);
+ printf("\n");
+ settogglehelp(1);
+ printf("%-15s %s\n", "?", "display help information");
+ return 0;
+ }
+
+ ct = getset(argv[1]);
+ if (ct == 0) {
+ c = GETTOGGLE(argv[1]);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ } else if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (c->variable) {
+ if ((argc == 2) || (strcmp("on", argv[2]) == 0))
+ *c->variable = 1;
+ else if (strcmp("off", argv[2]) == 0)
+ *c->variable = 0;
+ else {
+ printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
+ return 0;
+ }
+ if (c->actionexplanation) {
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ }
+ if (c->handler)
+ (*c->handler)(1);
+ } else if (argc != 3) {
+ printf("Format is 'set Name Value'\n'set ?' for help.\n");
+ return 0;
+ } else if (Ambiguous((void *)ct)) {
+ fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ } else if (ct->handler) {
+ (*ct->handler)(argv[2]);
+ printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
+ } else {
+ if (strcmp("off", argv[2])) {
+ value = special(argv[2]);
+ } else {
+ value = _POSIX_VDISABLE;
+ }
+ *(ct->charp) = (cc_t)value;
+ printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
+ }
+ slc_check();
+ return 1;
+}
+
+static int
+unsetcmd(int argc, char *argv[])
+{
+ struct setlist *ct;
+ struct togglelist *c;
+ char *name;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'unset' command. 'unset ?' for help.\n");
+ return 0;
+ }
+ if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
+ for (ct = Setlist; ct->name; ct++)
+ printf("%-15s %s\n", ct->name, ct->help);
+ printf("\n");
+ settogglehelp(0);
+ printf("%-15s %s\n", "?", "display help information");
+ return 0;
+ }
+
+ argc--;
+ argv++;
+ while (argc--) {
+ name = *argv++;
+ ct = getset(name);
+ if (ct == 0) {
+ c = GETTOGGLE(name);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
+ name);
+ return 0;
+ } else if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
+ name);
+ return 0;
+ }
+ if (c->variable) {
+ *c->variable = 0;
+ if (c->actionexplanation) {
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ }
+ if (c->handler)
+ (*c->handler)(0);
+ } else if (Ambiguous((void *)ct)) {
+ fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
+ name);
+ return 0;
+ } else if (ct->handler) {
+ (*ct->handler)(0);
+ printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
+ } else {
+ *(ct->charp) = _POSIX_VDISABLE;
+ printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
+ }
+ }
+ return 1;
+}
+
+/*
+ * The following are the data structures and routines for the
+ * 'mode' command.
+ */
+#ifdef KLUDGELINEMODE
+extern int kludgelinemode;
+
+static int
+dokludgemode(void)
+{
+ kludgelinemode = 1;
+ send_wont(TELOPT_LINEMODE, 1);
+ send_dont(TELOPT_SGA, 1);
+ send_dont(TELOPT_ECHO, 1);
+ return 1;
+}
+#endif
+
+static int
+dolinemode(void)
+{
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ send_dont(TELOPT_SGA, 1);
+#endif
+ send_will(TELOPT_LINEMODE, 1);
+ send_dont(TELOPT_ECHO, 1);
+ return 1;
+}
+
+static int
+docharmode(void)
+{
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ send_do(TELOPT_SGA, 1);
+ else
+#endif
+ send_wont(TELOPT_LINEMODE, 1);
+ send_do(TELOPT_ECHO, 1);
+ return 1;
+}
+
+static int
+dolmmode(int bit, int on)
+{
+ unsigned char c;
+ extern int linemode;
+
+ if (my_want_state_is_wont(TELOPT_LINEMODE)) {
+ printf("?Need to have LINEMODE option enabled first.\n");
+ printf("'mode ?' for help.\n");
+ return 0;
+ }
+
+ if (on)
+ c = (linemode | bit);
+ else
+ c = (linemode & ~bit);
+ lm_mode(&c, 1, 1);
+ return 1;
+}
+
+static int
+setmod(int bit)
+{
+ return dolmmode(bit, 1);
+}
+
+static int
+clearmode(int bit)
+{
+ return dolmmode(bit, 0);
+}
+
+struct modelist {
+ const char *name; /* command name */
+ const char *help; /* help string */
+ int (*handler)(int);/* routine which executes command */
+ int needconnect; /* Do we need to be connected to execute? */
+ int arg1;
+};
+
+static struct modelist ModeList[] = {
+ { "character", "Disable LINEMODE option", (int (*)(int))docharmode, 1, 0 },
+#ifdef KLUDGELINEMODE
+ { "", "(or disable obsolete line-by-line mode)", NULL, 0, 0 },
+#endif
+ { "line", "Enable LINEMODE option", (int (*)(int))dolinemode, 1, 0 },
+#ifdef KLUDGELINEMODE
+ { "", "(or enable obsolete line-by-line mode)", NULL, 0, 0 },
+#endif
+ { "", "", NULL, 0, 0 },
+ { "", "These require the LINEMODE option to be enabled", NULL, 0, 0 },
+ { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG },
+ { "+isig", 0, setmod, 1, MODE_TRAPSIG },
+ { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
+ { "edit", "Enable character editing", setmod, 1, MODE_EDIT },
+ { "+edit", 0, setmod, 1, MODE_EDIT },
+ { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
+ { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB },
+ { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB },
+ { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB },
+ { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
+ { "+litecho", 0, setmod, 1, MODE_LIT_ECHO },
+ { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
+ { "help", 0, (int (*)(int))modehelp, 0, 0 },
+#ifdef KLUDGELINEMODE
+ { "kludgeline", 0, (int (*)(int))dokludgemode, 1, 0 },
+#endif
+ { "", "", NULL, 0, 0 },
+ { "?", "Print help information", (int (*)(int))modehelp, 0, 0 },
+ { NULL, NULL, NULL, 0, 0 },
+};
+
+
+static int
+modehelp(void)
+{
+ struct modelist *mt;
+
+ printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
+ for (mt = ModeList; mt->name; mt++) {
+ if (mt->help) {
+ if (*mt->help)
+ printf("%-15s %s\n", mt->name, mt->help);
+ else
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+#define GETMODECMD(name) (struct modelist *) \
+ genget(name, (char **) ModeList, sizeof(struct modelist))
+
+static int
+modecmd(int argc, char *argv[])
+{
+ struct modelist *mt;
+
+ if (argc != 2) {
+ printf("'mode' command requires an argument\n");
+ printf("'mode ?' for help.\n");
+ } else if ((mt = GETMODECMD(argv[1])) == 0) {
+ fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
+ } else if (Ambiguous((void *)mt)) {
+ fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
+ } else if (mt->needconnect && !connected) {
+ printf("?Need to be connected first.\n");
+ printf("'mode ?' for help.\n");
+ } else if (mt->handler) {
+ return (*mt->handler)(mt->arg1);
+ }
+ return 0;
+}
+
+/*
+ * The following data structures and routines implement the
+ * "display" command.
+ */
+
+static int
+display(int argc, char *argv[])
+{
+ struct togglelist *tl;
+ struct setlist *sl;
+
+#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
+ if (*tl->variable) { \
+ printf("will"); \
+ } else { \
+ printf("won't"); \
+ } \
+ printf(" %s.\n", tl->actionexplanation); \
+ }
+
+#define doset(sl) if (sl->name && *sl->name != ' ') { \
+ if (sl->handler == 0) \
+ printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
+ else \
+ printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
+ }
+
+ if (argc == 1) {
+ for (tl = Togglelist; tl->name; tl++) {
+ dotog(tl);
+ }
+ printf("\n");
+ for (sl = Setlist; sl->name; sl++) {
+ doset(sl);
+ }
+ } else {
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ sl = getset(argv[i]);
+ tl = GETTOGGLE(argv[i]);
+ if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) {
+ printf("?Ambiguous argument '%s'.\n", argv[i]);
+ return 0;
+ } else if (!sl && !tl) {
+ printf("?Unknown argument '%s'.\n", argv[i]);
+ return 0;
+ } else {
+ if (tl) {
+ dotog(tl);
+ }
+ if (sl) {
+ doset(sl);
+ }
+ }
+ }
+ }
+/*@*/optionstatus();
+#ifdef ENCRYPTION
+ EncryptStatus();
+#endif /* ENCRYPTION */
+ return 1;
+#undef doset
+#undef dotog
+}
+
+/*
+ * The following are the data structures, and many of the routines,
+ * relating to command processing.
+ */
+
+/*
+ * Set the escape character.
+ */
+static int
+setescape(int argc, char *argv[])
+{
+ char *arg;
+ char buf[50];
+
+ printf(
+ "Deprecated usage - please use 'set escape%s%s' in the future.\n",
+ (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
+ if (argc > 2)
+ arg = argv[1];
+ else {
+ printf("new escape character: ");
+ (void) fgets(buf, sizeof(buf), stdin);
+ arg = buf;
+ }
+ if (arg[0] != '\0')
+ escape = arg[0];
+ (void) fflush(stdout);
+ return 1;
+}
+
+static int
+togcrmod(void)
+{
+ crmod = !crmod;
+ printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
+ printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
+ (void) fflush(stdout);
+ return 1;
+}
+
+static int
+suspend(void)
+{
+#ifdef SIGTSTP
+ setcommandmode();
+ {
+ long oldrows, oldcols, newrows, newcols, err_;
+
+ err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
+ (void) kill(0, SIGTSTP);
+ /*
+ * If we didn't get the window size before the SUSPEND, but we
+ * can get them now (?), then send the NAWS to make sure that
+ * we are set up for the right window size.
+ */
+ if (TerminalWindowSize(&newrows, &newcols) && connected &&
+ (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
+ sendnaws();
+ }
+ }
+ /* reget parameters in case they were changed */
+ TerminalSaveState();
+ setconnmode(0);
+#else
+ printf("Suspend is not supported. Try the '!' command instead\n");
+#endif
+ return 1;
+}
+
+static int
+shell(int argc, char *argv[] __unused)
+{
+ long oldrows, oldcols, newrows, newcols, err_;
+
+ setcommandmode();
+
+ err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
+ switch(vfork()) {
+ case -1:
+ perror("Fork failed\n");
+ break;
+
+ case 0:
+ {
+ /*
+ * Fire up the shell in the child.
+ */
+ const char *shellp, *shellname;
+
+ shellp = getenv("SHELL");
+ if (shellp == NULL)
+ shellp = "/bin/sh";
+ if ((shellname = strrchr(shellp, '/')) == 0)
+ shellname = shellp;
+ else
+ shellname++;
+ if (argc > 1)
+ execl(shellp, shellname, "-c", &saveline[1], (char *)0);
+ else
+ execl(shellp, shellname, (char *)0);
+ perror("Execl");
+ _exit(1);
+ }
+ default:
+ (void)wait((int *)0); /* Wait for the shell to complete */
+
+ if (TerminalWindowSize(&newrows, &newcols) && connected &&
+ (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
+ sendnaws();
+ }
+ break;
+ }
+ return 1;
+}
+
+static int
+bye(int argc, char *argv[])
+{
+ extern int resettermname;
+
+ if (connected) {
+ (void) shutdown(net, 2);
+ printf("Connection closed.\n");
+ (void) NetClose(net);
+ connected = 0;
+ resettermname = 1;
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ auth_encrypt_connect(connected);
+#endif
+#endif
+ /* reset options */
+ tninit();
+ }
+ if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
+ longjmp(toplevel, 1);
+ /* NOTREACHED */
+ }
+ return 1; /* Keep lint, etc., happy */
+}
+
+void
+quit(void)
+{
+ (void) call(bye, "bye", "fromquit", 0);
+ Exit(0);
+}
+
+static int
+logout(void)
+{
+ send_do(TELOPT_LOGOUT, 1);
+ (void) netflush();
+ return 1;
+}
+
+
+/*
+ * The SLC command.
+ */
+
+struct slclist {
+ const char *name;
+ const char *help;
+ void (*handler)(int);
+ int arg;
+};
+
+static void slc_help(void);
+
+struct slclist SlcList[] = {
+ { "export", "Use local special character definitions",
+ (void (*)(int))slc_mode_export, 0 },
+ { "import", "Use remote special character definitions",
+ slc_mode_import, 1 },
+ { "check", "Verify remote special character definitions",
+ slc_mode_import, 0 },
+ { "help", NULL, (void (*)(int))slc_help, 0 },
+ { "?", "Print help information", (void (*)(int))slc_help, 0 },
+ { NULL, NULL, NULL, 0 },
+};
+
+static void
+slc_help(void)
+{
+ struct slclist *c;
+
+ for (c = SlcList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+}
+
+static struct slclist *
+getslc(char *name)
+{
+ return (struct slclist *)
+ genget(name, (char **) SlcList, sizeof(struct slclist));
+}
+
+static int
+slccmd(int argc, char *argv[])
+{
+ struct slclist *c;
+
+ if (argc != 2) {
+ fprintf(stderr,
+ "Need an argument to 'slc' command. 'slc ?' for help.\n");
+ return 0;
+ }
+ c = getslc(argv[1]);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ (*c->handler)(c->arg);
+ slcstate();
+ return 1;
+}
+
+/*
+ * The ENVIRON command.
+ */
+
+struct envlist {
+ const char *name;
+ const char *help;
+ void (*handler)(unsigned char *, unsigned char *);
+ int narg;
+};
+
+extern struct env_lst *
+ env_define(const unsigned char *, unsigned char *);
+extern void
+ env_undefine(unsigned char *),
+ env_export(const unsigned char *),
+ env_unexport(const unsigned char *),
+ env_send(unsigned char *),
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+ env_varval(unsigned char *),
+#endif
+ env_list(void);
+static void
+ env_help(void);
+
+struct envlist EnvList[] = {
+ { "define", "Define an environment variable",
+ (void (*)(unsigned char *, unsigned char *))env_define, 2 },
+ { "undefine", "Undefine an environment variable",
+ (void (*)(unsigned char *, unsigned char *))env_undefine, 1 },
+ { "export", "Mark an environment variable for automatic export",
+ (void (*)(unsigned char *, unsigned char *))env_export, 1 },
+ { "unexport", "Don't mark an environment variable for automatic export",
+ (void (*)(unsigned char *, unsigned char *))env_unexport, 1 },
+ { "send", "Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send, 1 },
+ { "list", "List the current environment variables",
+ (void (*)(unsigned char *, unsigned char *))env_list, 0 },
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+ { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
+ (void (*)(unsigned char *, unsigned char *))env_varval, 1 },
+#endif
+ { "help", NULL, (void (*)(unsigned char *, unsigned char *))env_help, 0 },
+ { "?", "Print help information", (void (*)(unsigned char *, unsigned char *))env_help, 0 },
+ { NULL, NULL, NULL, 0 },
+};
+
+static void
+env_help(void)
+{
+ struct envlist *c;
+
+ for (c = EnvList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+}
+
+static struct envlist *
+getenvcmd(char *name)
+{
+ return (struct envlist *)
+ genget(name, (char **) EnvList, sizeof(struct envlist));
+}
+
+static int
+env_cmd(int argc, char *argv[])
+{
+ struct envlist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'environ' command. 'environ ?' for help.\n");
+ return 0;
+ }
+ c = getenvcmd(argv[1]);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (c->narg + 2 != argc && strcasecmp(argv[1],"define")==0 && c->narg + 1 != argc) {
+ fprintf(stderr,
+ "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
+ c->narg < argc + 2 ? "only " : "",
+ c->narg, c->narg == 1 ? "" : "s", c->name);
+ return 0;
+ }
+ (*c->handler)((unsigned char *)argv[2], (unsigned char *)argv[3]);
+ return 1;
+}
+
+struct env_lst {
+ struct env_lst *next; /* pointer to next structure */
+ struct env_lst *prev; /* pointer to previous structure */
+ unsigned char *var; /* pointer to variable name */
+ unsigned char *value; /* pointer to variable value */
+ int export; /* 1 -> export with default list of variables */
+ int welldefined; /* A well defined variable */
+};
+
+struct env_lst envlisthead;
+
+static struct env_lst *
+env_find(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ for (ep = envlisthead.next; ep; ep = ep->next) {
+ if (strcmp((const char *)ep->var, (const char *)var) == 0)
+ return(ep);
+ }
+ return(NULL);
+}
+
+void
+env_init(void)
+{
+ char *ev;
+ struct env_lst *ep;
+ int i;
+
+ const char *safe_vars[]=
+ {"USER", "PRINTER", "DISPLAY", "TERM", "COLUMNS", "LINES"};
+
+ for(i=0;i<sizeof(safe_vars)/sizeof(const char *);i++) {
+ if((ev=getenv(safe_vars[i]))) {
+ ep=env_define((unsigned char *)safe_vars[i],(unsigned char *)ev);
+ ep->export=0;
+ }
+ }
+
+ /*
+ * Special case for DISPLAY variable. If it is ":0.0" or
+ * "unix:0.0", we have to get rid of "unix" and insert our
+ * hostname.
+ */
+ if ((ep = env_find((const unsigned char *)"DISPLAY"))
+ && ((*ep->value == ':')
+ || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
+ char hbuf[256+1];
+ char *cp, *cp2 = strchr((char *)ep->value, ':');
+
+ gethostname(hbuf, 256);
+ hbuf[256] = '\0';
+ cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
+ sprintf((char *)cp, "%s%s", hbuf, cp2);
+ free(ep->value);
+ ep->value = (unsigned char *)cp;
+ }
+ /*
+ * If USER is not defined, but LOGNAME is, then add
+ * USER with the value from LOGNAME. By default, we
+ * don't export the USER variable.
+ */
+ if ((env_find((const unsigned char *)"USER") == NULL) && (ep = env_find((const unsigned char *)"LOGNAME"))) {
+ env_define((const unsigned char *)"USER", ep->value);
+ env_unexport((const unsigned char *)"USER");
+ }
+ env_export((const unsigned char *)"DISPLAY");
+ env_export((const unsigned char *)"PRINTER");
+}
+
+struct env_lst *
+env_define(const unsigned char *var, unsigned char *value)
+{
+ char *ev;
+ struct env_lst *ep;
+
+ if ((ep = env_find(var))) {
+ if (ep->var)
+ free(ep->var);
+ if (ep->value)
+ free(ep->value);
+ } else {
+ ep = (struct env_lst *)malloc(sizeof(struct env_lst));
+ ep->next = envlisthead.next;
+ envlisthead.next = ep;
+ ep->prev = &envlisthead;
+ if (ep->next)
+ ep->next->prev = ep;
+ }
+
+ ep->welldefined = opt_welldefined((const char *)var);
+ ep->export = 1;
+ ep->var = (unsigned char *)strdup((const char *)var);
+
+ if(value)
+ ep->value = (unsigned char *)strdup((const char *)value);
+ else if((ev=getenv((const char *)var)))
+ ep->value = (unsigned char *)strdup(ev);
+ else ep->value = (unsigned char *)strdup("");
+ return(ep);
+}
+
+void
+env_undefine(unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var))) {
+ ep->prev->next = ep->next;
+ if (ep->next)
+ ep->next->prev = ep->prev;
+ if (ep->var)
+ free(ep->var);
+ if (ep->value)
+ free(ep->value);
+ free(ep);
+ }
+}
+
+void
+env_export(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var)))
+ ep->export = 1;
+}
+
+void
+env_unexport(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var)))
+ ep->export = 0;
+}
+
+void
+env_send(unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if (my_state_is_wont(TELOPT_NEW_ENVIRON)
+#ifdef OLD_ENVIRON
+ && my_state_is_wont(TELOPT_OLD_ENVIRON)
+#endif
+ ) {
+ fprintf(stderr,
+ "Cannot send '%s': Telnet ENVIRON option not enabled\n",
+ var);
+ return;
+ }
+ ep = env_find(var);
+ if (ep == 0) {
+ fprintf(stderr, "Cannot send '%s': variable not defined\n",
+ var);
+ return;
+ }
+ env_opt_start_info();
+ env_opt_add(ep->var);
+ env_opt_end(0);
+}
+
+void
+env_list(void)
+{
+ struct env_lst *ep;
+
+ for (ep = envlisthead.next; ep; ep = ep->next) {
+ printf("%c %-20s %s\n", ep->export ? '*' : ' ',
+ ep->var, ep->value);
+ }
+}
+
+unsigned char *
+env_default(int init, int welldefined)
+{
+ static struct env_lst *nep = NULL;
+
+ if (init) {
+ nep = &envlisthead;
+ return(NULL);
+ }
+ if (nep) {
+ while ((nep = nep->next)) {
+ if (nep->export && (nep->welldefined == welldefined))
+ return(nep->var);
+ }
+ }
+ return(NULL);
+}
+
+unsigned char *
+env_getvalue(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var)))
+ return(ep->value);
+ return(NULL);
+}
+
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+void
+env_varval(unsigned char *what)
+{
+ extern int old_env_var, old_env_value, env_auto;
+ int len = strlen((char *)what);
+
+ if (len == 0)
+ goto unknown;
+
+ if (strncasecmp((char *)what, "status", len) == 0) {
+ if (env_auto)
+ printf("%s%s", "VAR and VALUE are/will be ",
+ "determined automatically\n");
+ if (old_env_var == OLD_ENV_VAR)
+ printf("VAR and VALUE set to correct definitions\n");
+ else
+ printf("VAR and VALUE definitions are reversed\n");
+ } else if (strncasecmp((char *)what, "auto", len) == 0) {
+ env_auto = 1;
+ old_env_var = OLD_ENV_VALUE;
+ old_env_value = OLD_ENV_VAR;
+ } else if (strncasecmp((char *)what, "right", len) == 0) {
+ env_auto = 0;
+ old_env_var = OLD_ENV_VAR;
+ old_env_value = OLD_ENV_VALUE;
+ } else if (strncasecmp((char *)what, "wrong", len) == 0) {
+ env_auto = 0;
+ old_env_var = OLD_ENV_VALUE;
+ old_env_value = OLD_ENV_VAR;
+ } else {
+unknown:
+ printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
+ }
+}
+#endif
+
+#ifdef AUTHENTICATION
+/*
+ * The AUTHENTICATE command.
+ */
+
+struct authlist {
+ const char *name;
+ const char *help;
+ int (*handler)(char *);
+ int narg;
+};
+
+extern int
+ auth_enable(char *),
+ auth_disable(char *),
+ auth_status(void);
+static int
+ auth_help(void);
+
+struct authlist AuthList[] = {
+ { "status", "Display current status of authentication information",
+ (int (*)(char *))auth_status, 0 },
+ { "disable", "Disable an authentication type ('auth disable ?' for more)",
+ auth_disable, 1 },
+ { "enable", "Enable an authentication type ('auth enable ?' for more)",
+ auth_enable, 1 },
+ { "help", NULL, (int (*)(char *))auth_help, 0 },
+ { "?", "Print help information", (int (*)(char *))auth_help, 0 },
+ { NULL, NULL, NULL, 0 },
+};
+
+static int
+auth_help(void)
+{
+ struct authlist *c;
+
+ for (c = AuthList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+int
+auth_cmd(int argc, char *argv[])
+{
+ struct authlist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'auth' command. 'auth ?' for help.\n");
+ return 0;
+ }
+
+ c = (struct authlist *)
+ genget(argv[1], (char **) AuthList, sizeof(struct authlist));
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (c->narg + 2 != argc) {
+ fprintf(stderr,
+ "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
+ c->narg < argc + 2 ? "only " : "",
+ c->narg, c->narg == 1 ? "" : "s", c->name);
+ return 0;
+ }
+ return((*c->handler)(argv[2]));
+}
+#endif
+
+#ifdef ENCRYPTION
+/*
+ * The ENCRYPT command.
+ */
+
+struct encryptlist {
+ const char *name;
+ const char *help;
+ int (*handler)(char *, char *);
+ int needconnect;
+ int minarg;
+ int maxarg;
+};
+
+extern int
+ EncryptEnable(char *, char *),
+ EncryptDisable(char *, char *),
+ EncryptType(char *, char *),
+ EncryptStart(char *),
+ EncryptStartInput(void),
+ EncryptStartOutput(void),
+ EncryptStop(char *),
+ EncryptStopInput(void),
+ EncryptStopOutput(void),
+ EncryptStatus(void);
+static int
+ EncryptHelp(void);
+
+struct encryptlist EncryptList[] = {
+ { "enable", "Enable encryption. ('encrypt enable ?' for more)",
+ EncryptEnable, 1, 1, 2 },
+ { "disable", "Disable encryption. ('encrypt enable ?' for more)",
+ EncryptDisable, 0, 1, 2 },
+ { "type", "Set encryption type. ('encrypt type ?' for more)",
+ EncryptType, 0, 1, 1 },
+ { "start", "Start encryption. ('encrypt start ?' for more)",
+ (int (*)(char *, char *))EncryptStart, 1, 0, 1 },
+ { "stop", "Stop encryption. ('encrypt stop ?' for more)",
+ (int (*)(char *, char *))EncryptStop, 1, 0, 1 },
+ { "input", "Start encrypting the input stream",
+ (int (*)(char *, char *))EncryptStartInput, 1, 0, 0 },
+ { "-input", "Stop encrypting the input stream",
+ (int (*)(char *, char *))EncryptStopInput, 1, 0, 0 },
+ { "output", "Start encrypting the output stream",
+ (int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 },
+ { "-output", "Stop encrypting the output stream",
+ (int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 },
+
+ { "status", "Display current status of authentication information",
+ (int (*)(char *, char *))EncryptStatus, 0, 0, 0 },
+ { "help", NULL, (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
+ { "?", "Print help information", (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
+ { NULL, NULL, NULL, 0, 0, 0 },
+};
+
+static int
+EncryptHelp(void)
+{
+ struct encryptlist *c;
+
+ for (c = EncryptList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+static int
+encrypt_cmd(int argc, char *argv[])
+{
+ struct encryptlist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n");
+ return 0;
+ }
+
+ c = (struct encryptlist *)
+ genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ argc -= 2;
+ if (argc < c->minarg || argc > c->maxarg) {
+ if (c->minarg == c->maxarg) {
+ fprintf(stderr, "Need %s%d argument%s ",
+ c->minarg < argc ? "only " : "", c->minarg,
+ c->minarg == 1 ? "" : "s");
+ } else {
+ fprintf(stderr, "Need %s%d-%d arguments ",
+ c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
+ }
+ fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n",
+ c->name);
+ return 0;
+ }
+ if (c->needconnect && !connected) {
+ if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
+ printf("?Need to be connected first.\n");
+ return 0;
+ }
+ }
+ return ((*c->handler)(argc > 0 ? argv[2] : 0,
+ argc > 1 ? argv[3] : 0));
+}
+#endif /* ENCRYPTION */
+
+/*
+ * Print status about the connection.
+ */
+/*ARGSUSED*/
+static int
+status(int argc, char *argv[])
+{
+ if (connected) {
+ printf("Connected to %s.\n", hostname);
+ if ((argc < 2) || strcmp(argv[1], "notmuch")) {
+ int mode = getconnmode();
+
+ if (my_want_state_is_will(TELOPT_LINEMODE)) {
+ printf("Operating with LINEMODE option\n");
+ printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
+ printf("%s catching of signals\n",
+ (mode&MODE_TRAPSIG) ? "Local" : "No");
+ slcstate();
+#ifdef KLUDGELINEMODE
+ } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
+ printf("Operating in obsolete linemode\n");
+#endif
+ } else {
+ printf("Operating in single character mode\n");
+ if (localchars)
+ printf("Catching signals locally\n");
+ }
+ printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
+ if (my_want_state_is_will(TELOPT_LFLOW))
+ printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
+#ifdef ENCRYPTION
+ encrypt_display();
+#endif /* ENCRYPTION */
+ }
+ } else {
+ printf("No connection.\n");
+ }
+ printf("Escape character is '%s'.\n", control(escape));
+ (void) fflush(stdout);
+ return 1;
+}
+
+#ifdef SIGINFO
+/*
+ * Function that gets called when SIGINFO is received.
+ */
+void
+ayt_status(void)
+{
+ (void) call(status, "status", "notmuch", 0);
+}
+#endif
+
+static const char *
+sockaddr_ntop(struct sockaddr *sa)
+{
+ void *addr;
+ static char addrbuf[INET6_ADDRSTRLEN];
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ addr = &((struct sockaddr_in *)sa)->sin_addr;
+ break;
+ case AF_UNIX:
+ addr = &((struct sockaddr_un *)sa)->sun_path;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+ inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
+ return addrbuf;
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+static int
+setpolicy(int lnet, struct addrinfo *res, char *policy)
+{
+ char *buf;
+ int level;
+ int optname;
+
+ if (policy == NULL)
+ return 0;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ printf("%s\n", ipsec_strerror());
+ return -1;
+ }
+ level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
+ optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
+ if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){
+ perror("setsockopt");
+ return -1;
+ }
+
+ free(buf);
+ return 0;
+}
+#endif
+
+#ifdef INET6
+/*
+ * When an Address Family related error happend, check if retry with
+ * another AF is possible or not.
+ * Return 1, if retry with another af is OK. Else, return 0.
+ */
+static int
+switch_af(struct addrinfo **aip)
+{
+ int nextaf;
+ struct addrinfo *ai;
+
+ ai = *aip;
+ nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
+ do
+ ai=ai->ai_next;
+ while (ai != NULL && ai->ai_family != nextaf);
+ *aip = ai;
+ if (*aip != NULL) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+int
+tn(int argc, char *argv[])
+{
+ char *srp = 0;
+ int proto = 0, opt = 0;
+ int srlen = 0;
+#ifndef __APPLE__
+ int srcroute = 0, result;
+#else
+ int srcroute = 0;
+#endif
+ char *cmd, *hostp = 0, *portp = 0, *user = 0;
+ char *src_addr = NULL;
+ struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
+ int error = 0, af_error = 0;
+
+ if (connected) {
+ printf("?Already connected to %s\n", hostname);
+ setuid(getuid());
+ return 0;
+ }
+ if (argc < 2) {
+ (void) strcpy(line, "open ");
+ printf("(to) ");
+ (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ cmd = *argv;
+ --argc; ++argv;
+ while (argc) {
+ if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
+ goto usage;
+ if (strcmp(*argv, "-l") == 0) {
+ --argc; ++argv;
+ if (argc == 0)
+ goto usage;
+ user = *argv++;
+ --argc;
+ continue;
+ }
+ if (strcmp(*argv, "-a") == 0) {
+ --argc; ++argv;
+ autologin = 1;
+ continue;
+ }
+ if (strcmp(*argv, "-s") == 0) {
+ --argc; ++argv;
+ if (argc == 0)
+ goto usage;
+ src_addr = *argv++;
+ --argc;
+ continue;
+ }
+ if (hostp == 0) {
+ hostp = *argv++;
+ --argc;
+ continue;
+ }
+ if (portp == 0) {
+ portp = *argv++;
+ --argc;
+ continue;
+ }
+ usage:
+ printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
+ setuid(getuid());
+ return 0;
+ }
+ if (hostp == 0)
+ goto usage;
+
+ if (src_addr != NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(src_addr, 0, &hints, &src_res);
+#ifdef EAI_NODATA
+ if ((error == EAI_NODATA) || (error == EAI_NONAME))
+#else
+ if (error == EAI_NONAME)
+#endif
+ {
+ hints.ai_flags = 0;
+ error = getaddrinfo(src_addr, 0, &hints, &src_res);
+ }
+ if (error != 0) {
+ fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
+ setuid(getuid());
+ return 0;
+ }
+ src_res0 = src_res;
+ }
+ if (hostp[0] == '/') {
+ struct sockaddr_un su;
+
+ if (strlen(hostp) >= sizeof(su.sun_path)) {
+ fprintf(stderr, "hostname too long for unix domain socket: %s",
+ hostp);
+ goto fail;
+ }
+ memset(&su, 0, sizeof su);
+ su.sun_family = AF_UNIX;
+ strncpy(su.sun_path, hostp, sizeof su.sun_path);
+ printf("Trying %s...\n", hostp);
+ net = socket(PF_UNIX, SOCK_STREAM, 0);
+ if ( net < 0) {
+ perror("socket");
+ goto fail;
+ }
+ if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
+ perror(su.sun_path);
+ (void) NetClose(net);
+ goto fail;
+ }
+ goto af_unix;
+ } else if (hostp[0] == '@' || hostp[0] == '!') {
+ if (
+#ifdef INET6
+ family == AF_INET6 ||
+#endif
+ (hostname = strrchr(hostp, ':')) == NULL)
+ hostname = strrchr(hostp, '@');
+ if (hostname == NULL) {
+ hostname = hostp;
+ } else {
+ hostname++;
+ srcroute = 1;
+ }
+ } else
+ hostname = hostp;
+ if (!portp) {
+ telnetport = 1;
+ portp = strdup("telnet");
+ } else if (*portp == '-') {
+ portp++;
+ telnetport = 1;
+ } else if (*portp == '+') {
+ portp++;
+ telnetport = -1;
+ } else
+ telnetport = 0;
+
+#ifdef __APPLE__
+ {
+ /*
+ * 5760578: Attempt to convert service name to a
+ * numeric port before calling getaddrinfo().
+ */
+ struct servent *srv = getservbyname(portp, NULL);
+ if (srv != NULL) {
+ asprintf(&portp, "%d", ntohs(srv->s_port));
+ }
+ }
+#endif /* __APPLE__ */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(hostname, portp, &hints, &res);
+ if (error) {
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(hostname, portp, &hints, &res);
+ }
+ if (error != 0) {
+ fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
+ setuid(getuid());
+ goto fail;
+ }
+ if (hints.ai_flags == AI_NUMERICHOST) {
+ /* hostname has numeric */
+ int gni_err = 1;
+
+ if (doaddrlookup)
+ gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
+ _hostname, sizeof(_hostname) - 1, NULL, 0,
+ NI_NAMEREQD);
+ if (gni_err != 0)
+ (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
+ _hostname[sizeof(_hostname)-1] = '\0';
+ hostname = _hostname;
+ } else {
+ /* hostname has FQDN */
+ if (srcroute != 0)
+ (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
+ else if (res->ai_canonname != NULL)
+ strncpy(_hostname, res->ai_canonname, sizeof(_hostname) - 1);
+ else
+ (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
+ _hostname[sizeof(_hostname)-1] = '\0';
+ hostname = _hostname;
+ }
+ res0 = res;
+ #ifdef INET6
+ af_again:
+ #endif
+#ifndef __APPLE__
+ if (srcroute != 0) {
+ static char hostbuf[BUFSIZ];
+
+ if (af_error == 0) { /* save intermediate hostnames for retry */
+ strncpy(hostbuf, hostp, BUFSIZ - 1);
+ hostbuf[BUFSIZ - 1] = '\0';
+ } else
+ hostp = hostbuf;
+ srp = 0;
+ result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
+ if (result == 0) {
+#ifdef INET6
+ if (family == AF_UNSPEC && af_error == 0 &&
+ switch_af(&res) == 1) {
+ af_error = 1;
+ goto af_again;
+ }
+#endif
+ setuid(getuid());
+ goto fail;
+ } else if (result == -1) {
+ printf("Bad source route option: %s\n", hostp);
+ setuid(getuid());
+ goto fail;
+ }
+ }
+#endif
+ do {
+ printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
+ net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ setuid(getuid());
+ if (net < 0) {
+#ifdef INET6
+ if (family == AF_UNSPEC && af_error == 0 &&
+ switch_af(&res) == 1) {
+ af_error = 1;
+ goto af_again;
+ }
+#endif
+ perror("telnet: socket");
+ goto fail;
+ }
+ if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
+ perror("setsockopt (source route)");
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ if (res->ai_family == PF_INET) {
+# if defined(HAS_GETTOS)
+ struct tosent *tp;
+ if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+ tos = tp->t_tos;
+# endif
+ if (tos < 0)
+ tos = IPTOS_LOWDELAY;
+ if (tos
+ && (setsockopt(net, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(int)) < 0)
+ && (errno != ENOPROTOOPT))
+ perror("telnet: setsockopt (IP_TOS) (ignored)");
+ }
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
+
+ if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
+ perror("setsockopt (SO_DEBUG)");
+ }
+
+ if (src_addr != NULL) {
+ for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
+ if (src_res->ai_family == res->ai_family)
+ break;
+ if (src_res == NULL)
+ src_res = src_res0;
+ if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
+#ifdef INET6
+ if (family == AF_UNSPEC && af_error == 0 &&
+ switch_af(&res) == 1) {
+ af_error = 1;
+ (void) NetClose(net);
+ goto af_again;
+ }
+#endif
+ perror("bind");
+ (void) NetClose(net);
+ goto fail;
+ }
+ }
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(net, res, ipsec_policy_in) < 0) {
+ (void) NetClose(net);
+ goto fail;
+ }
+ if (setpolicy(net, res, ipsec_policy_out) < 0) {
+ (void) NetClose(net);
+ goto fail;
+ }
+#endif
+
+ if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
+ struct addrinfo *next;
+
+ next = res->ai_next;
+ /* If already an af failed, only try same af. */
+ if (af_error != 0)
+ while (next != NULL && next->ai_family != res->ai_family)
+ next = next->ai_next;
+ warn("connect to address %s", sockaddr_ntop(res->ai_addr));
+ if (next != NULL) {
+ res = next;
+ (void) NetClose(net);
+ continue;
+ }
+ warnx("Unable to connect to remote host");
+ (void) NetClose(net);
+ goto fail;
+ }
+ connected++;
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ auth_encrypt_connect(connected);
+#endif
+#endif
+ } while (connected == 0);
+ freeaddrinfo(res0);
+ if (src_res0 != NULL)
+ freeaddrinfo(src_res0);
+ cmdrc(hostp, hostname);
+ af_unix:
+ connected = 1;
+ if (autologin && user == NULL) {
+ struct passwd *pw;
+
+ user = getenv("USER");
+ if (user == NULL ||
+ ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
+ if ((pw = getpwuid(getuid())))
+ user = pw->pw_name;
+ else
+ user = NULL;
+ }
+ }
+ if (user) {
+ env_define((unsigned char*)"USER", (unsigned char*)user);
+ env_export((unsigned char*)"USER");
+ }
+ (void) call(status, "status", "notmuch", 0);
+ if (setjmp(peerdied) == 0)
+ telnet(user);
+ (void) NetClose(net);
+ ExitString("Connection closed by foreign host.\n",1);
+ /*NOTREACHED*/
+ fail:
+ if (res0 != NULL)
+ freeaddrinfo(res0);
+ if (src_res0 != NULL)
+ freeaddrinfo(src_res0);
+ return 0;
+}
+
+#define HELPINDENT (sizeof ("connect"))
+
+static char
+ openhelp[] = "connect to a site",
+ closehelp[] = "close current connection",
+ logouthelp[] = "forcibly logout remote user and close the connection",
+ quithelp[] = "exit telnet",
+ statushelp[] = "print status information",
+ helphelp[] = "print help information",
+ sendhelp[] = "transmit special characters ('send ?' for more)",
+ sethelp[] = "set operating parameters ('set ?' for more)",
+ unsethelp[] = "unset operating parameters ('unset ?' for more)",
+ togglestring[] ="toggle operating parameters ('toggle ?' for more)",
+ slchelp[] = "change state of special charaters ('slc ?' for more)",
+ displayhelp[] = "display operating parameters",
+#ifdef AUTHENTICATION
+ authhelp[] = "turn on (off) authentication ('auth ?' for more)",
+#endif
+#ifdef ENCRYPTION
+ encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
+#endif /* ENCRYPTION */
+ zhelp[] = "suspend telnet",
+#ifdef OPIE
+ opiehelp[] = "compute response to OPIE challenge",
+#endif
+ shellhelp[] = "invoke a subshell",
+ envhelp[] = "change environment variables ('environ ?' for more)",
+ modestring[] = "try to enter line or character mode ('mode ?' for more)";
+
+static Command cmdtab[] = {
+ { "close", closehelp, bye, 1 },
+ { "logout", logouthelp, (int (*)(int, char **))logout, 1 },
+ { "display", displayhelp, display, 0 },
+ { "mode", modestring, modecmd, 0 },
+ { "telnet", openhelp, tn, 0 },
+ { "open", openhelp, tn, 0 },
+ { "quit", quithelp, (int (*)(int, char **))quit, 0 },
+ { "send", sendhelp, sendcmd, 0 },
+ { "set", sethelp, setcmd, 0 },
+ { "unset", unsethelp, unsetcmd, 0 },
+ { "status", statushelp, status, 0 },
+ { "toggle", togglestring, toggle, 0 },
+ { "slc", slchelp, slccmd, 0 },
+#ifdef AUTHENTICATION
+ { "auth", authhelp, auth_cmd, 0 },
+#endif
+#ifdef ENCRYPTION
+ { "encrypt", encrypthelp, encrypt_cmd, 0 },
+#endif /* ENCRYPTION */
+ { "z", zhelp, (int (*)(int, char **))suspend, 0 },
+ { "!", shellhelp, shell, 1 },
+ { "environ", envhelp, env_cmd, 0 },
+ { "?", helphelp, help, 0 },
+#ifdef OPIE
+ { "opie", opiehelp, opie_calc, 0 },
+#endif
+ { NULL, NULL, NULL, 0 }
+};
+
+static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
+static char escapehelp[] = "deprecated command -- use 'set escape' instead";
+
+static Command cmdtab2[] = {
+ { "help", 0, help, 0 },
+ { "escape", escapehelp, setescape, 0 },
+ { "crmod", crmodhelp, (int (*)(int, char **))togcrmod, 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+
+/*
+ * Call routine with argc, argv set from args (terminated by 0).
+ */
+
+static int
+call(intrtn_t routine, ...)
+{
+ va_list ap;
+ char *args[100];
+ int argno = 0;
+
+ va_start(ap, routine);
+ while ((args[argno++] = va_arg(ap, char *)) != 0);
+ va_end(ap);
+ return (*routine)(argno-1, args);
+}
+
+
+static Command *
+getcmd(char *name)
+{
+ Command *cm;
+
+ if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
+ return cm;
+ return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
+}
+
+void
+command(int top, const char *tbuf, int cnt)
+{
+ Command *c;
+
+ setcommandmode();
+ if (!top) {
+ putchar('\n');
+ } else {
+ (void) signal(SIGINT, SIG_DFL);
+ (void) signal(SIGQUIT, SIG_DFL);
+ }
+ for (;;) {
+ if (rlogin == _POSIX_VDISABLE)
+ printf("%s> ", prompt);
+ if (tbuf) {
+ char *cp;
+ cp = line;
+ while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
+ cnt--;
+ tbuf = 0;
+ if (cp == line || *--cp != '\n' || cp == line)
+ goto getline;
+ *cp = '\0';
+ if (rlogin == _POSIX_VDISABLE)
+ printf("%s\n", line);
+ } else {
+ getline:
+ if (rlogin != _POSIX_VDISABLE)
+ printf("%s> ", prompt);
+ if (fgets(line, sizeof(line), stdin) == NULL) {
+ if (feof(stdin) || ferror(stdin)) {
+ (void) quit();
+ /*NOTREACHED*/
+ }
+ break;
+ }
+ }
+ if (line[0] == 0)
+ break;
+ makeargv();
+ if (margv[0] == 0) {
+ break;
+ }
+ c = getcmd(margv[0]);
+ if (Ambiguous((void *)c)) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->needconnect && !connected) {
+ printf("?Need to be connected first.\n");
+ continue;
+ }
+ if ((*c->handler)(margc, margv)) {
+ break;
+ }
+ }
+ if (!top) {
+ if (!connected) {
+ longjmp(toplevel, 1);
+ /*NOTREACHED*/
+ }
+ setconnmode(0);
+ }
+}
+
+/*
+ * Help command.
+ */
+static int
+help(int argc, char *argv[])
+{
+ Command *c;
+
+ if (argc == 1) {
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->name; c++)
+ if (c->help) {
+ printf("%-*s\t%s\n", (int)HELPINDENT, c->name,
+ c->help);
+ }
+ return 0;
+ }
+ else while (--argc > 0) {
+ char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (Ambiguous((void *)c))
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (Command *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%s\n", c->help);
+ }
+ return 0;
+}
+
+static char *rcname = 0;
+static char rcbuf[128];
+
+void
+cmdrc(char *m1, char *m2)
+{
+ Command *c;
+ FILE *rcfile;
+ int gotmachine = 0;
+ int l1 = strlen(m1);
+ int l2 = strlen(m2);
+ char m1save[MAXHOSTNAMELEN];
+
+ if (skiprc)
+ return;
+
+ strlcpy(m1save, m1, sizeof(m1save));
+ m1 = m1save;
+
+ if (rcname == 0) {
+ rcname = getenv("HOME");
+ if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
+ strcpy(rcbuf, rcname);
+ else
+ rcbuf[0] = '\0';
+ strcat(rcbuf, "/.telnetrc");
+ rcname = rcbuf;
+ }
+
+ if ((rcfile = fopen(rcname, "r")) == 0) {
+ return;
+ }
+
+ for (;;) {
+ if (fgets(line, sizeof(line), rcfile) == NULL)
+ break;
+ if (line[0] == 0)
+ break;
+ if (line[0] == '#')
+ continue;
+ if (gotmachine) {
+ if (!isspace(line[0]))
+ gotmachine = 0;
+ }
+ if (gotmachine == 0) {
+ if (isspace(line[0]))
+ continue;
+ if (strncasecmp(line, m1, l1) == 0)
+ strncpy(line, &line[l1], sizeof(line) - l1);
+ else if (strncasecmp(line, m2, l2) == 0)
+ strncpy(line, &line[l2], sizeof(line) - l2);
+ else if (strncasecmp(line, "DEFAULT", 7) == 0)
+ strncpy(line, &line[7], sizeof(line) - 7);
+ else
+ continue;
+ if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
+ continue;
+ gotmachine = 1;
+ }
+ makeargv();
+ if (margv[0] == 0)
+ continue;
+ c = getcmd(margv[0]);
+ if (Ambiguous((void *)c)) {
+ printf("?Ambiguous command: %s\n", margv[0]);
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command: %s\n", margv[0]);
+ continue;
+ }
+ /*
+ * This should never happen...
+ */
+ if (c->needconnect && !connected) {
+ printf("?Need to be connected first for %s.\n", margv[0]);
+ continue;
+ }
+ (*c->handler)(margc, margv);
+ }
+ fclose(rcfile);
+}
+
+#ifndef __APPLE__
+/*
+ * Source route is handed in as
+ * [!]@hop1@hop2...[@|:]dst
+ * If the leading ! is present, it is a
+ * strict source route, otherwise it is
+ * assmed to be a loose source route.
+ *
+ * We fill in the source route option as
+ * hop1,hop2,hop3...dest
+ * and return a pointer to hop1, which will
+ * be the address to connect() to.
+ *
+ * Arguments:
+ *
+ * res: ponter to addrinfo structure which contains sockaddr to
+ * the host to connect to.
+ *
+ * arg: pointer to route list to decipher
+ *
+ * cpp: If *cpp is not equal to NULL, this is a
+ * pointer to a pointer to a character array
+ * that should be filled in with the option.
+ *
+ * lenp: pointer to an integer that contains the
+ * length of *cpp if *cpp != NULL.
+ *
+ * protop: pointer to an integer that should be filled in with
+ * appropriate protocol for setsockopt, as socket
+ * protocol family.
+ *
+ * optp: pointer to an integer that should be filled in with
+ * appropriate option for setsockopt, as socket protocol
+ * family.
+ *
+ * Return values:
+ *
+ * If the return value is 1, then all operations are
+ * successful. If the
+ * return value is -1, there was a syntax error in the
+ * option, either unknown characters, or too many hosts.
+ * If the return value is 0, one of the hostnames in the
+ * path is unknown, and *cpp is set to point to the bad
+ * hostname.
+ *
+ * *cpp: If *cpp was equal to NULL, it will be filled
+ * in with a pointer to our static area that has
+ * the option filled in. This will be 32bit aligned.
+ *
+ * *lenp: This will be filled in with how long the option
+ * pointed to by *cpp is.
+ *
+ * *protop: This will be filled in with appropriate protocol for
+ * setsockopt, as socket protocol family.
+ *
+ * *optp: This will be filled in with appropriate option for
+ * setsockopt, as socket protocol family.
+ */
+static int
+sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop, int *optp)
+{
+ static char buf[1024 + ALIGNBYTES]; /*XXX*/
+ char *cp, *cp2, *lsrp, *ep;
+ struct sockaddr_in *_sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ struct cmsghdr *cmsg = NULL;
+#endif
+ struct addrinfo hints, *res;
+ int error;
+ char c;
+
+ /*
+ * Verify the arguments, and make sure we have
+ * at least 7 bytes for the option.
+ */
+ if (cpp == NULL || lenp == NULL)
+ return -1;
+ if (*cpp != NULL) {
+ switch (ai->ai_family) {
+ case AF_INET:
+ if (*lenp < 7)
+ return -1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) +
+ sizeof(struct in6_addr)))
+ return -1;
+ break;
+#endif
+ }
+ }
+ /*
+ * Decide whether we have a buffer passed to us,
+ * or if we need to use our own static buffer.
+ */
+ if (*cpp) {
+ lsrp = *cpp;
+ ep = lsrp + *lenp;
+ } else {
+ *cpp = lsrp = (char *)ALIGN(buf);
+ ep = lsrp + 1024;
+ }
+
+ cp = arg;
+
+#ifdef INET6
+ if (ai->ai_family == AF_INET6) {
+ cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
+ if (*cp != '@')
+ return -1;
+ *protop = IPPROTO_IPV6;
+ *optp = IPV6_PKTOPTIONS;
+ } else
+#endif
+ {
+ /*
+ * Next, decide whether we have a loose source
+ * route or a strict source route, and fill in
+ * the begining of the option.
+ */
+ if (*cp == '!') {
+ cp++;
+ *lsrp++ = IPOPT_SSRR;
+ } else
+ *lsrp++ = IPOPT_LSRR;
+
+ if (*cp != '@')
+ return -1;
+
+ lsrp++; /* skip over length, we'll fill it in later */
+ *lsrp++ = 4;
+ *protop = IPPROTO_IP;
+ *optp = IP_OPTIONS;
+ }
+
+ cp++;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai->ai_family;
+ hints.ai_socktype = SOCK_STREAM;
+ for (c = 0;;) {
+ if (
+#ifdef INET6
+ ai->ai_family != AF_INET6 &&
+#endif
+ c == ':')
+ cp2 = 0;
+ else for (cp2 = cp; (c = *cp2); cp2++) {
+ if (c == ',') {
+ *cp2++ = '\0';
+ if (*cp2 == '@')
+ cp2++;
+ } else if (c == '@') {
+ *cp2++ = '\0';
+ } else if (
+#ifdef INET6
+ ai->ai_family != AF_INET6 &&
+#endif
+ c == ':') {
+ *cp2++ = '\0';
+ } else
+ continue;
+ break;
+ }
+ if (!c)
+ cp2 = 0;
+
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(cp, NULL, &hints, &res);
+#ifdef EAI_NODATA
+ if ((error == EAI_NODATA) || (error == EAI_NONAME))
+#else
+ if (error == EAI_NONAME)
+#endif
+ {
+ hints.ai_flags = 0;
+ error = getaddrinfo(cp, NULL, &hints, &res);
+ }
+ if (error != 0) {
+ fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "%s: %s\n", cp,
+ strerror(errno));
+ *cpp = cp;
+ return(0);
+ }
+#ifdef INET6
+ if (res->ai_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)res->ai_addr;
+ inet6_rthdr_add(cmsg, &sin6->sin6_addr,
+ IPV6_RTHDR_LOOSE);
+ } else
+#endif
+ {
+ _sin = (struct sockaddr_in *)res->ai_addr;
+ memcpy(lsrp, (char *)&_sin->sin_addr, 4);
+ lsrp += 4;
+ }
+ if (cp2)
+ cp = cp2;
+ else
+ break;
+ /*
+ * Check to make sure there is space for next address
+ */
+#ifdef INET6
+ if (res->ai_family == AF_INET6) {
+ if (((char *)CMSG_DATA(cmsg) +
+ sizeof(struct ip6_rthdr) +
+ ((inet6_rthdr_segments(cmsg) + 1) *
+ sizeof(struct in6_addr))) > ep)
+ return -1;
+ } else
+#endif
+ if (lsrp + 4 > ep)
+ return -1;
+ freeaddrinfo(res);
+ }
+#ifdef INET6
+ if (res->ai_family == AF_INET6) {
+ inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
+ *lenp = cmsg->cmsg_len;
+ } else
+#endif
+ {
+ if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
+ *cpp = 0;
+ *lenp = 0;
+ return -1;
+ }
+ *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
+ *lenp = lsrp - *cpp;
+ }
+ freeaddrinfo(res);
+ return 1;
+}
+#endif
diff --git a/remote_cmds/telnet.tproj/defines.h b/remote_cmds/telnet.tproj/defines.h
new file mode 100644
index 0000000..d49cb2d
--- /dev/null
+++ b/remote_cmds/telnet.tproj/defines.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defines.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/contrib/telnet/telnet/defines.h,v 1.2 2001/11/30 21:06:35 markm Exp $
+ */
+
+#define settimer(x) clocks.x = clocks.system++
+
+#define NETADD(c) { *netoring.supply = c; ring_supplied(&netoring, 1); }
+#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); }
+#define NETBYTES() (ring_full_count(&netoring))
+#define NETROOM() (ring_empty_count(&netoring))
+
+#define TTYADD(c) if (!(SYNCHing||flushout)) { \
+ *ttyoring.supply = c; \
+ ring_supplied(&ttyoring, 1); \
+ }
+#define TTYBYTES() (ring_full_count(&ttyoring))
+#define TTYROOM() (ring_empty_count(&ttyoring))
+
+/* Various modes */
+#define MODE_LOCAL_CHARS(m) ((m)&(MODE_EDIT|MODE_TRAPSIG))
+#define MODE_LOCAL_ECHO(m) ((m)&MODE_ECHO)
+#define MODE_COMMAND_LINE(m) ((m)==-1)
+
+#define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
diff --git a/remote_cmds/telnet.tproj/externs.h b/remote_cmds/telnet.tproj/externs.h
new file mode 100644
index 0000000..bc450ec
--- /dev/null
+++ b/remote_cmds/telnet.tproj/externs.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)externs.h 8.3 (Berkeley) 5/30/95
+ * $FreeBSD: src/contrib/telnet/telnet/externs.h,v 1.11 2007/07/01 12:08:04 gnn Exp $
+ */
+
+#ifndef BSD
+# define BSD 43
+#endif
+
+/*
+ * ucb stdio.h defines BSD as something weird
+ */
+#if defined(sun) && defined(__svr4__)
+#define BSD 43
+#endif
+
+#ifndef USE_TERMIO
+# if BSD > 43 || defined(SYSV_TERMIO)
+# define USE_TERMIO
+# endif
+#endif
+
+#include <stdio.h>
+#include <setjmp.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#ifdef USE_TERMIO
+# ifndef VINTR
+# include <sys/termios.h>
+# endif
+# define termio termios
+#endif
+#if defined(NO_CC_T) || !defined(USE_TERMIO)
+# if !defined(USE_TERMIO)
+typedef char cc_t;
+# else
+typedef unsigned char cc_t;
+# endif
+#endif
+
+#include <string.h>
+
+#if defined(IPSEC)
+#ifdef __APPLE__
+#include <netinet6/ipsec.h>
+#else
+#include <netipsec/ipsec.h>
+#endif
+#if defined(IPSEC_POLICY_IPSEC)
+extern char *ipsec_policy_in;
+extern char *ipsec_policy_out;
+#endif
+#endif
+
+#ifndef _POSIX_VDISABLE
+# ifdef sun
+# include <sys/param.h> /* pick up VDISABLE definition, mayby */
+# endif
+# ifdef VDISABLE
+# define _POSIX_VDISABLE VDISABLE
+# else
+# define _POSIX_VDISABLE ((cc_t)'\377')
+# endif
+#endif
+
+#define SUBBUFSIZE 256
+
+#if !defined(P)
+# ifdef __STDC__
+# define P(x) x
+# else
+# define P(x) ()
+# endif
+#endif
+
+extern int
+ autologin, /* Autologin enabled */
+ skiprc, /* Don't process the ~/.telnetrc file */
+ eight, /* use eight bit mode (binary in and/or out */
+ family, /* address family of peer */
+ flushout, /* flush output */
+ connected, /* Are we connected to the other side? */
+ globalmode, /* Mode tty should be in */
+ telnetport, /* Are we connected to the telnet port? */
+ localflow, /* Flow control handled locally */
+ restartany, /* If flow control, restart output on any character */
+ localchars, /* we recognize interrupt/quit */
+ donelclchars, /* the user has set "localchars" */
+ showoptions,
+ net, /* Network file descriptor */
+ tin, /* Terminal input file descriptor */
+ tout, /* Terminal output file descriptor */
+ crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+ autoflush, /* flush output when interrupting? */
+ autosynch, /* send interrupt characters with SYNCH? */
+ SYNCHing, /* Is the stream in telnet SYNCH mode? */
+ donebinarytoggle, /* the user has put us in binary */
+ dontlecho, /* do we suppress local echoing right now? */
+ crmod,
+ netdata, /* Print out network data flow */
+ prettydump, /* Print "netdata" output in user readable format */
+ termdata, /* Print out terminal data flow */
+ telnet_debug, /* Debug level */
+ doaddrlookup, /* do a reverse lookup? */
+ clienteof; /* Client received EOF */
+
+extern cc_t escape; /* Escape to command mode */
+extern cc_t rlogin; /* Rlogin mode escape character */
+#ifdef KLUDGELINEMODE
+extern cc_t echoc; /* Toggle local echoing */
+#endif
+
+extern char
+ *prompt; /* Prompt for command. */
+
+extern char
+ doopt[],
+ dont[],
+ will[],
+ wont[],
+ options[], /* All the little options */
+ *hostname; /* Who are we connected to? */
+#ifdef ENCRYPTION
+extern void (*encrypt_output)(unsigned char *, int);
+extern int (*decrypt_input)(int);
+#endif /* ENCRYPTION */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define MY_STATE_WILL 0x01
+#define MY_WANT_STATE_WILL 0x02
+#define MY_STATE_DO 0x04
+#define MY_WANT_STATE_DO 0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define my_state_is_do(opt) (options[opt]&MY_STATE_DO)
+#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL)
+
+#define my_state_is_dont(opt) (!my_state_is_do(opt))
+#define my_state_is_wont(opt) (!my_state_is_will(opt))
+#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt))
+
+#define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;}
+#define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;}
+#define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;}
+#define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;}
+
+#define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;}
+#define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;}
+#define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;}
+#define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;}
+
+/*
+ * Make everything symetrical
+ */
+
+#define HIS_STATE_WILL MY_STATE_DO
+#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO
+#define HIS_STATE_DO MY_STATE_WILL
+#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL
+
+#define his_state_is_do my_state_is_will
+#define his_state_is_will my_state_is_do
+#define his_want_state_is_do my_want_state_is_will
+#define his_want_state_is_will my_want_state_is_do
+
+#define his_state_is_dont my_state_is_wont
+#define his_state_is_wont my_state_is_dont
+#define his_want_state_is_dont my_want_state_is_wont
+#define his_want_state_is_wont my_want_state_is_dont
+
+#define set_his_state_do set_my_state_will
+#define set_his_state_will set_my_state_do
+#define set_his_want_state_do set_my_want_state_will
+#define set_his_want_state_will set_my_want_state_do
+
+#define set_his_state_dont set_my_state_wont
+#define set_his_state_wont set_my_state_dont
+#define set_his_want_state_dont set_my_want_state_wont
+#define set_his_want_state_wont set_my_want_state_dont
+
+#if defined(USE_TERMIO)
+#define SIG_FUNC_RET void
+#else
+#define SIG_FUNC_RET int
+#endif
+
+#ifdef SIGINFO
+extern SIG_FUNC_RET
+ ayt_status(void);
+#endif
+
+extern FILE
+ *NetTrace; /* Where debugging output goes */
+extern unsigned char
+ NetTraceFile[]; /* Name of file where debugging output goes */
+extern void
+ SetNetTrace(char *); /* Function to change where debugging goes */
+
+extern jmp_buf
+ peerdied,
+ toplevel; /* For error conditions. */
+
+extern void
+ command(int, const char *, int),
+ Dump(char, unsigned char *, int),
+ env_init(void),
+ Exit(int),
+ ExitString(const char *, int),
+ init_network(void),
+ init_sys(void),
+ init_telnet(void),
+ init_terminal(void),
+ intp(void),
+ optionstatus(void),
+ printoption(const char *, int, int),
+ printsub(char, unsigned char *, int),
+ quit(void),
+ sendabort(void),
+ sendbrk(void),
+ sendeof(void),
+ sendsusp(void),
+ sendnaws(void),
+ sendayt(void),
+ setconnmode(int),
+ setcommandmode(void),
+ set_escape_char(char *s),
+ setneturg(void),
+ sys_telnet_init(void),
+ telnet(char *),
+ tel_enter_binary(int),
+ tel_leave_binary(int),
+ TerminalFlushOutput(void),
+ TerminalNewMode(int),
+ TerminalRestoreState(void),
+ TerminalSaveState(void),
+ TerminalDefaultChars(void),
+ TerminalSpeeds(long *, long *),
+ tninit(void),
+ upcase(char *),
+ willoption(int),
+ wontoption(int);
+
+extern void
+ send_do(int, int),
+ send_dont(int, int),
+ send_will(int, int),
+ send_wont(int, int);
+
+extern void
+ lm_will(unsigned char *, int),
+ lm_wont(unsigned char *, int),
+ lm_do(unsigned char *, int),
+ lm_dont(unsigned char *, int),
+ lm_mode(unsigned char *, int, int);
+
+extern void
+ slc_init(void),
+ slcstate(void),
+ slc_mode_export(void),
+ slc_mode_import(int),
+ slc_import(int),
+ slc_export(void),
+ slc(unsigned char *, int),
+ slc_check(void),
+ slc_start_reply(void),
+ slc_add_reply(unsigned char, unsigned char, cc_t),
+ slc_end_reply(void);
+extern int
+ getconnmode(void),
+ opt_welldefined(const char *),
+ NetClose(int),
+ netflush(void),
+ process_rings(int, int, int, int, int, int),
+ rlogin_susp(void),
+ SetSockOpt(int, int, int, int),
+ slc_update(void),
+ stilloob(void),
+ telrcv(void),
+ TerminalRead(char *, int),
+ TerminalWrite(char *, int),
+ TerminalAutoFlush(void),
+ TerminalWindowSize(long *, long *),
+ TerminalSpecialChars(int),
+ tn(int, char **),
+ ttyflush(int);
+
+extern void
+ env_opt(unsigned char *, int),
+ env_opt_start(void),
+ env_opt_start_info(void),
+ env_opt_add(unsigned char *),
+ env_opt_end(int);
+
+extern unsigned char
+ *env_default(int, int),
+ *env_getvalue(const unsigned char *);
+
+extern int
+ get_status(char *),
+ dosynch(char *);
+
+extern cc_t
+ *tcval(int);
+
+#ifndef USE_TERMIO
+
+extern struct tchars ntc;
+extern struct ltchars nltc;
+extern struct sgttyb nttyb;
+
+# define termEofChar ntc.t_eofc
+# define termEraseChar nttyb.sg_erase
+# define termFlushChar nltc.t_flushc
+# define termIntChar ntc.t_intrc
+# define termKillChar nttyb.sg_kill
+# define termLiteralNextChar nltc.t_lnextc
+# define termQuitChar ntc.t_quitc
+# define termSuspChar nltc.t_suspc
+# define termRprntChar nltc.t_rprntc
+# define termWerasChar nltc.t_werasc
+# define termStartChar ntc.t_startc
+# define termStopChar ntc.t_stopc
+# define termForw1Char ntc.t_brkc
+extern cc_t termForw2Char;
+extern cc_t termAytChar;
+
+# define termEofCharp (cc_t *)&ntc.t_eofc
+# define termEraseCharp (cc_t *)&nttyb.sg_erase
+# define termFlushCharp (cc_t *)&nltc.t_flushc
+# define termIntCharp (cc_t *)&ntc.t_intrc
+# define termKillCharp (cc_t *)&nttyb.sg_kill
+# define termLiteralNextCharp (cc_t *)&nltc.t_lnextc
+# define termQuitCharp (cc_t *)&ntc.t_quitc
+# define termSuspCharp (cc_t *)&nltc.t_suspc
+# define termRprntCharp (cc_t *)&nltc.t_rprntc
+# define termWerasCharp (cc_t *)&nltc.t_werasc
+# define termStartCharp (cc_t *)&ntc.t_startc
+# define termStopCharp (cc_t *)&ntc.t_stopc
+# define termForw1Charp (cc_t *)&ntc.t_brkc
+# define termForw2Charp (cc_t *)&termForw2Char
+# define termAytCharp (cc_t *)&termAytChar
+
+# else
+
+extern struct termio new_tc;
+
+# define termEofChar new_tc.c_cc[VEOF]
+# define termEraseChar new_tc.c_cc[VERASE]
+# define termIntChar new_tc.c_cc[VINTR]
+# define termKillChar new_tc.c_cc[VKILL]
+# define termQuitChar new_tc.c_cc[VQUIT]
+
+# ifndef VSUSP
+extern cc_t termSuspChar;
+# else
+# define termSuspChar new_tc.c_cc[VSUSP]
+# endif
+# if defined(VFLUSHO) && !defined(VDISCARD)
+# define VDISCARD VFLUSHO
+# endif
+# ifndef VDISCARD
+extern cc_t termFlushChar;
+# else
+# define termFlushChar new_tc.c_cc[VDISCARD]
+# endif
+# ifndef VWERASE
+extern cc_t termWerasChar;
+# else
+# define termWerasChar new_tc.c_cc[VWERASE]
+# endif
+# ifndef VREPRINT
+extern cc_t termRprntChar;
+# else
+# define termRprntChar new_tc.c_cc[VREPRINT]
+# endif
+# ifndef VLNEXT
+extern cc_t termLiteralNextChar;
+# else
+# define termLiteralNextChar new_tc.c_cc[VLNEXT]
+# endif
+# ifndef VSTART
+extern cc_t termStartChar;
+# else
+# define termStartChar new_tc.c_cc[VSTART]
+# endif
+# ifndef VSTOP
+extern cc_t termStopChar;
+# else
+# define termStopChar new_tc.c_cc[VSTOP]
+# endif
+# ifndef VEOL
+extern cc_t termForw1Char;
+# else
+# define termForw1Char new_tc.c_cc[VEOL]
+# endif
+# ifndef VEOL2
+extern cc_t termForw2Char;
+# else
+# define termForw2Char new_tc.c_cc[VEOL]
+# endif
+# ifndef VSTATUS
+extern cc_t termAytChar;
+#else
+# define termAytChar new_tc.c_cc[VSTATUS]
+#endif
+
+# if defined(__STDC__)
+# define termEofCharp &termEofChar
+# define termEraseCharp &termEraseChar
+# define termIntCharp &termIntChar
+# define termKillCharp &termKillChar
+# define termQuitCharp &termQuitChar
+# define termSuspCharp &termSuspChar
+# define termFlushCharp &termFlushChar
+# define termWerasCharp &termWerasChar
+# define termRprntCharp &termRprntChar
+# define termLiteralNextCharp &termLiteralNextChar
+# define termStartCharp &termStartChar
+# define termStopCharp &termStopChar
+# define termForw1Charp &termForw1Char
+# define termForw2Charp &termForw2Char
+# define termAytCharp &termAytChar
+# else
+ /* Work around a compiler bug */
+# define termEofCharp 0
+# define termEraseCharp 0
+# define termIntCharp 0
+# define termKillCharp 0
+# define termQuitCharp 0
+# define termSuspCharp 0
+# define termFlushCharp 0
+# define termWerasCharp 0
+# define termRprntCharp 0
+# define termLiteralNextCharp 0
+# define termStartCharp 0
+# define termStopCharp 0
+# define termForw1Charp 0
+# define termForw2Charp 0
+# define termAytCharp 0
+# endif
+#endif
+
+
+/* Ring buffer structures which are shared */
+
+extern Ring
+ netoring,
+ netiring,
+ ttyoring,
+ ttyiring;
+
+extern void
+ xmitAO(void),
+ xmitEC(void),
+ xmitEL(void);
diff --git a/remote_cmds/telnet.tproj/fdset.h b/remote_cmds/telnet.tproj/fdset.h
new file mode 100644
index 0000000..045bb72
--- /dev/null
+++ b/remote_cmds/telnet.tproj/fdset.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdset.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * The following is defined just in case someone should want to run
+ * this telnet on a 4.2 system.
+ *
+ */
+
+#ifndef FD_SETSIZE
+
+#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
+#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
+#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
+#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
+
+#endif
diff --git a/remote_cmds/telnet.tproj/general.h b/remote_cmds/telnet.tproj/general.h
new file mode 100644
index 0000000..4efa951
--- /dev/null
+++ b/remote_cmds/telnet.tproj/general.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)general.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Some general definitions.
+ */
+
+
+#define numberof(x) (sizeof x/sizeof x[0])
+#define highestof(x) (numberof(x)-1)
+
+#define ClearElement(x) memset((char *)&x, 0, sizeof x)
+#define ClearArray(x) memset((char *)x, 0, sizeof x)
diff --git a/remote_cmds/telnet.tproj/krb4-proto.h b/remote_cmds/telnet.tproj/krb4-proto.h
new file mode 100644
index 0000000..9f3f0b0
--- /dev/null
+++ b/remote_cmds/telnet.tproj/krb4-proto.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifdef __STDC__
+# define P(s) s
+#else
+# define P(s) ()
+#endif
+
+/* add_ticket.c */
+int add_ticket P((KTEXT , int , char *, int , char *, char *, char *, int , KTEXT ));
+
+/* cr_err_reply.c */
+void cr_err_reply P((KTEXT , char *, char *, char *, u_long , u_long , char *));
+
+/* create_auth_reply.c */
+KTEXT create_auth_reply P((char *, char *, char *, long , int , unsigned long , int , KTEXT ));
+
+/* create_ciph.c */
+int create_ciph P((KTEXT , C_Block , char *, char *, char *, unsigned long , int , KTEXT , unsigned long , C_Block ));
+
+/* create_death_packet.c */
+KTEXT krb_create_death_packet P((char *));
+
+/* create_ticket.c */
+int krb_create_ticket P((KTEXT , unsigned int , char *, char *, char *, long , char *, int , long , char *, char *, C_Block ));
+
+/* debug_decl.c */
+
+/* decomp_ticket.c */
+int decomp_ticket P((KTEXT , unsigned char *, char *, char *, char *, unsigned long *, C_Block , int *, unsigned long *, char *, char *, C_Block , Key_schedule ));
+
+/* dest_tkt.c */
+int dest_tkt P((void ));
+
+/* extract_ticket.c */
+int extract_ticket P((KTEXT , int , char *, int *, int *, char *, KTEXT ));
+
+/* fgetst.c */
+int fgetst P((FILE *, char *, int ));
+
+/* get_ad_tkt.c */
+int get_ad_tkt P((char *, char *, char *, int ));
+
+/* get_admhst.c */
+int krb_get_admhst P((char *, char *, int ));
+
+/* get_cred.c */
+int krb_get_cred P((char *, char *, char *, CREDENTIALS *));
+
+/* get_in_tkt.c */
+int krb_get_pw_in_tkt P((char *, char *, char *, char *, char *, int , char *));
+int placebo_read_password P((des_cblock *, char *, int ));
+int placebo_read_pw_string P((char *, int , char *, int ));
+
+/* get_krbhst.c */
+int krb_get_krbhst P((char *, char *, int ));
+
+/* get_krbrlm.c */
+int krb_get_lrealm P((char *, int ));
+
+/* get_phost.c */
+char *krb_get_phost P((char *));
+
+/* get_pw_tkt.c */
+int get_pw_tkt P((char *, char *, char *, char *));
+
+/* get_request.c */
+int get_request P((KTEXT , int , char **, char **));
+
+/* get_svc_in_tkt.c */
+int krb_get_svc_in_tkt P((char *, char *, char *, char *, char *, int , char *));
+
+/* get_tf_fullname.c */
+int krb_get_tf_fullname P((char *, char *, char *, char *));
+
+/* get_tf_realm.c */
+int krb_get_tf_realm P((char *, char *));
+
+/* getopt.c */
+int getopt P((int , char **, char *));
+
+/* getrealm.c */
+char *krb_realmofhost P((char *));
+
+/* getst.c */
+int getst P((int , char *, int ));
+
+/* in_tkt.c */
+int in_tkt P((char *, char *));
+
+/* k_gethostname.c */
+int k_gethostname P((char *, int ));
+
+/* klog.c */
+char *klog P((int , char *, int , int , int , int , int , int , int , int , int , int ));
+int kset_logfile P((char *));
+
+/* kname_parse.c */
+int kname_parse P((char *, char *, char *, char *));
+int k_isname P((char *));
+int k_isinst P((char *));
+int k_isrealm P((char *));
+
+/* kntoln.c */
+int krb_kntoln P((AUTH_DAT *, char *));
+
+/* krb_err_txt.c */
+
+/* krb_get_in_tkt.c */
+int krb_get_in_tkt P((char *, char *, char *, char *, char *, int , int (*key_proc )(), int (*decrypt_proc )(), char *));
+
+/* kuserok.c */
+int kuserok P((AUTH_DAT *, char *));
+
+/* log.c */
+void log P((char *, int , int , int , int , int , int , int , int , int , int ));
+int set_logfile P((char *));
+int new_log P((long , char *));
+
+/* mk_err.c */
+long krb_mk_err P((u_char *, long , char *));
+
+/* mk_priv.c */
+long krb_mk_priv P((u_char *, u_char *, u_long , Key_schedule , C_Block , struct sockaddr_in *, struct sockaddr_in *));
+
+/* mk_req.c */
+int krb_mk_req P((KTEXT , char *, char *, char *, long ));
+int krb_set_lifetime P((int ));
+
+/* mk_safe.c */
+long krb_mk_safe P((u_char *, u_char *, u_long , C_Block *, struct sockaddr_in *, struct sockaddr_in *));
+
+/* month_sname.c */
+char *month_sname P((int ));
+
+/* netread.c */
+int krb_net_read P((int , char *, int ));
+
+/* netwrite.c */
+int krb_net_write P((int , char *, int ));
+
+/* one.c */
+
+/* pkt_cipher.c */
+KTEXT pkt_cipher P((KTEXT ));
+
+/* pkt_clen.c */
+int pkt_clen P((KTEXT ));
+
+/* rd_err.c */
+int krb_rd_err P((u_char *, u_long , long *, MSG_DAT *));
+
+/* rd_priv.c */
+long krb_rd_priv P((u_char *, u_long , Key_schedule , C_Block , struct sockaddr_in *, struct sockaddr_in *, MSG_DAT *));
+
+/* rd_req.c */
+int krb_set_key P((char *, int ));
+int krb_rd_req P((KTEXT , char *, char *, long , AUTH_DAT *, char *));
+
+/* rd_safe.c */
+long krb_rd_safe P((u_char *, u_long , C_Block *, struct sockaddr_in *, struct sockaddr_in *, MSG_DAT *));
+
+/* read_service_key.c */
+int read_service_key P((char *, char *, char *, int , char *, char *));
+
+/* recvauth.c */
+int krb_recvauth P((long , int , KTEXT , char *, char *, struct sockaddr_in *, struct sockaddr_in *, AUTH_DAT *, char *, Key_schedule , char *));
+
+/* save_credentials.c */
+int save_credentials P((char *, char *, char *, C_Block , int , int , KTEXT , long ));
+
+/* send_to_kdc.c */
+int send_to_kdc P((KTEXT , KTEXT , char *));
+
+/* sendauth.c */
+int krb_sendauth P((long , int , KTEXT , char *, char *, char *, u_long , MSG_DAT *, CREDENTIALS *, Key_schedule , struct sockaddr_in *, struct sockaddr_in *, char *));
+int krb_sendsvc P((int , char *));
+
+/* setenv.c */
+int setenv P((char *, char *, int ));
+void unsetenv P((char *));
+char *getenv P((char *));
+char *_findenv P((char *, int *));
+
+/* stime.c */
+char *stime P((long *));
+
+/* tf_shm.c */
+int krb_shm_create P((char *));
+int krb_is_diskless P((void ));
+int krb_shm_dest P((char *));
+
+/* tf_util.c */
+int tf_init P((char *, int ));
+int tf_get_pname P((char *));
+int tf_get_pinst P((char *));
+int tf_get_cred P((CREDENTIALS *));
+int tf_close P((void ));
+int tf_save_cred P((char *, char *, char *, C_Block , int , int , KTEXT , long ));
+
+/* tkt_string.c */
+char *tkt_string P((void ));
+void krb_set_tkt_string P((char *));
+
+/* util.c */
+int ad_print P((AUTH_DAT *));
+int placebo_cblock_print P((des_cblock ));
+
+#undef P
diff --git a/remote_cmds/telnet.tproj/main.c b/remote_cmds/telnet.tproj/main.c
new file mode 100644
index 0000000..fd01a30
--- /dev/null
+++ b/remote_cmds/telnet.tproj/main.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/main.c,v 1.20 2005/01/09 10:24:45 maxim Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ring.h"
+#include "externs.h"
+#include "defines.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/* These values need to be the same as defined in libtelnet/kerberos5.c */
+/* Either define them in both places, or put in some common header file. */
+#define OPTS_FORWARD_CREDS 0x00000002
+#define OPTS_FORWARDABLE_CREDS 0x00000001
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+char *ipsec_policy_in = NULL;
+char *ipsec_policy_out = NULL;
+#endif
+
+extern int tos;
+
+int family = AF_UNSPEC;
+
+/*
+ * Initialize variables.
+ */
+void
+tninit(void)
+{
+ init_terminal();
+
+ init_network();
+
+ init_telnet();
+
+ init_sys();
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s %s%s%s%s\n",
+ prompt,
+#ifdef AUTHENTICATION
+ "[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-c] [-d]",
+ "\n\t[-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ",
+#else
+ "[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-c] [-d]",
+ "\n\t[-e char] [-l user] [-n tracefile] ",
+#endif
+ "[-r] [-s src_addr] [-u] ",
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ "[-P policy] "
+#endif
+#ifdef ENCRYPTION
+ "[-y] [host-name [port]]"
+#else /* ENCRYPTION */
+ "[host-name [port]]"
+#endif /* ENCRYPTION */
+ );
+ exit(1);
+}
+
+/*
+ * main. Parse arguments, invoke the protocol or command parser.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ u_long ultmp;
+ int ch;
+ char *ep, *user;
+ char *src_addr = NULL;
+#ifdef FORWARD
+ extern int forward_flags;
+#endif /* FORWARD */
+
+ tninit(); /* Clear out things */
+
+ TerminalSaveState();
+
+ if ((prompt = strrchr(argv[0], '/')))
+ ++prompt;
+ else
+ prompt = argv[0];
+
+ user = NULL;
+
+ rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
+#ifdef AUTHENTICATION
+ autologin = 1;
+#else
+ autologin = -1;
+#endif
+
+#ifdef ENCRYPTION
+ encrypt_auto(1);
+ decrypt_auto(1);
+#endif
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+#define IPSECOPT "P:"
+#else
+#define IPSECOPT
+#endif
+ while ((ch = getopt(argc, argv,
+ "468EKLNS:X:acde:fFk:l:n:rs:uxy" IPSECOPT)) != -1)
+#undef IPSECOPT
+ {
+ switch(ch) {
+ case '4':
+ family = AF_INET;
+ break;
+#ifdef INET6
+ case '6':
+ family = AF_INET6;
+ break;
+#endif
+ case '8':
+ eight = 3; /* binary output and input */
+ break;
+ case 'E':
+ rlogin = escape = _POSIX_VDISABLE;
+ break;
+ case 'K':
+#ifdef AUTHENTICATION
+ autologin = 0;
+#endif
+ break;
+ case 'L':
+ eight |= 2; /* binary output only */
+ break;
+ case 'N':
+ doaddrlookup = 0;
+ break;
+ case 'S':
+#ifdef HAS_GETTOS
+
+ if ((tos = parsetos(optarg, "tcp")) < 0)
+ fprintf(stderr, "%s%s%s%s\n",
+ prompt, ": Bad TOS argument '",
+ optarg,
+ "; will try to use default TOS");
+#else
+#define MAXTOS 255
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTOS)
+ fprintf(stderr, "%s%s%s%s\n",
+ prompt, ": Bad TOS argument '",
+ optarg,
+ "; will try to use default TOS");
+ else
+ tos = ultmp;
+#endif
+ break;
+ case 'X':
+#ifdef AUTHENTICATION
+ auth_disable_name(optarg);
+#endif
+ break;
+ case 'a':
+#ifdef AUTHENTICATION
+ /* It's the default now, so ignore */
+#else
+ autologin = 1;
+#endif
+ break;
+ case 'c':
+ skiprc = 1;
+ break;
+ case 'd':
+ telnet_debug = 1;
+ break;
+ case 'e':
+ set_escape_char(optarg);
+ break;
+ case 'f':
+#ifdef AUTHENTICATION
+#if defined(KRB5) && defined(FORWARD)
+ if (forward_flags & OPTS_FORWARD_CREDS) {
+ fprintf(stderr,
+ "%s: Only one of -f and -F allowed.\n",
+ prompt);
+ usage();
+ }
+ forward_flags |= OPTS_FORWARD_CREDS;
+#else
+ fprintf(stderr,
+ "%s: Warning: -f ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+#else
+ fprintf(stderr,
+ "%s: Warning: -f ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+ break;
+ case 'F':
+#ifdef AUTHENTICATION
+#if defined(KRB5) && defined(FORWARD)
+ if (forward_flags & OPTS_FORWARD_CREDS) {
+ fprintf(stderr,
+ "%s: Only one of -f and -F allowed.\n",
+ prompt);
+ usage();
+ }
+ forward_flags |= OPTS_FORWARD_CREDS;
+ forward_flags |= OPTS_FORWARDABLE_CREDS;
+#else
+ fprintf(stderr,
+ "%s: Warning: -F ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+#else
+ fprintf(stderr,
+ "%s: Warning: -F ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+ break;
+ case 'k':
+#ifdef AUTHENTICATION
+#if defined(KRB4)
+ {
+ extern char *dest_realm, dst_realm_buf[], dst_realm_sz;
+ dest_realm = dst_realm_buf;
+ (void)strncpy(dest_realm, optarg, dst_realm_sz);
+ }
+#else
+ fprintf(stderr,
+ "%s: Warning: -k ignored, no Kerberos V4 support.\n",
+ prompt);
+#endif
+#else
+ fprintf(stderr,
+ "%s: Warning: -k ignored, no Kerberos V4 support.\n",
+ prompt);
+#endif
+ break;
+ case 'l':
+#ifdef AUTHENTICATION
+ /* This is the default now, so ignore it */
+#else
+ autologin = 1;
+#endif
+ user = optarg;
+ break;
+ case 'n':
+ SetNetTrace(optarg);
+ break;
+ case 'r':
+ rlogin = '~';
+ break;
+ case 's':
+ src_addr = optarg;
+ break;
+ case 'u':
+ family = AF_UNIX;
+ break;
+ case 'x':
+#ifndef ENCRYPTION
+ fprintf(stderr,
+ "%s: Warning: -x ignored, no ENCRYPT support.\n",
+ prompt);
+#endif /* ENCRYPTION */
+ break;
+ case 'y':
+#ifdef ENCRYPTION
+ encrypt_auto(0);
+ decrypt_auto(0);
+#else
+ fprintf(stderr,
+ "%s: Warning: -y ignored, no ENCRYPT support.\n",
+ prompt);
+#endif /* ENCRYPTION */
+ break;
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ case 'P':
+ if (!strncmp("in", optarg, 2))
+ ipsec_policy_in = strdup(optarg);
+ else if (!strncmp("out", optarg, 3))
+ ipsec_policy_out = strdup(optarg);
+ else
+ usage();
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ if (autologin == -1)
+ autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1;
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc) {
+ char *args[9], **argp = args;
+
+ if (argc > 2)
+ usage();
+ *argp++ = prompt;
+ if (user) {
+ *argp++ = strdup("-l");
+ *argp++ = user;
+ }
+ if (src_addr) {
+ *argp++ = strdup("-s");
+ *argp++ = src_addr;
+ }
+ *argp++ = argv[0]; /* host */
+ if (argc > 1)
+ *argp++ = argv[1]; /* port */
+ *argp = 0;
+
+ if (setjmp(toplevel) != 0)
+ Exit(0);
+ if (tn(argp - args, args) == 1)
+ return (0);
+ else
+ return (1);
+ }
+ (void)setjmp(toplevel);
+ for (;;) {
+ command(1, 0, 0);
+ }
+ return 0;
+}
diff --git a/remote_cmds/telnet.tproj/misc-proto.h b/remote_cmds/telnet.tproj/misc-proto.h
new file mode 100644
index 0000000..511a1bf
--- /dev/null
+++ b/remote_cmds/telnet.tproj/misc-proto.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc-proto.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/misc-proto.h,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#ifndef __MISC_PROTO__
+#define __MISC_PROTO__
+
+void auth_encrypt_init(char *, char *, const char *, int);
+void auth_encrypt_connect(int);
+void printd(const unsigned char *, int);
+
+int isprefix(char *, const char *);
+char **genget(char *, char **, int);
+int Ambiguous(char **);
+
+int getent(char *, const char *);
+char *Getstr(const char *, char **);
+
+/*
+ * These functions are imported from the application
+ */
+int net_write(unsigned char *, int);
+void net_encrypt(void);
+int telnet_spin(void);
+char *telnet_getenv(char *);
+char *telnet_gets(const char *, char *, int, int);
+void printsub(char, unsigned char *, int);
+#endif
diff --git a/remote_cmds/telnet.tproj/misc.h b/remote_cmds/telnet.tproj/misc.h
new file mode 100644
index 0000000..41ffa7f
--- /dev/null
+++ b/remote_cmds/telnet.tproj/misc.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc.h 8.1 (Berkeley) 6/4/93
+ */
+
+extern char *UserNameRequested;
+extern char *LocalHostName;
+extern char *RemoteHostName;
+extern int ConnectedCount;
+extern int ReservedPort;
+
+#include "misc-proto.h"
diff --git a/remote_cmds/telnet.tproj/network.c b/remote_cmds/telnet.tproj/network.c
new file mode 100644
index 0000000..e93345f
--- /dev/null
+++ b/remote_cmds/telnet.tproj/network.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/network.c,v 1.7 2003/05/04 02:54:48 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <arpa/telnet.h>
+#include <unistd.h>
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "fdset.h"
+
+Ring netoring, netiring;
+unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ];
+
+/*
+ * Initialize internal network data structures.
+ */
+
+void
+init_network(void)
+{
+ if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) {
+ exit(1);
+ }
+ if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) {
+ exit(1);
+ }
+ NetTrace = stdout;
+}
+
+
+/*
+ * Check to see if any out-of-band data exists on a socket (for
+ * Telnet "synch" processing).
+ */
+
+int
+stilloob(void)
+{
+ static struct timeval timeout = { 0, 0 };
+ fd_set excepts;
+ int value;
+
+ do {
+ FD_ZERO(&excepts);
+ FD_SET(net, &excepts);
+ value = select(net+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
+ } while ((value == -1) && (errno == EINTR));
+
+ if (value < 0) {
+ perror("select");
+ (void) quit();
+ /* NOTREACHED */
+ }
+ if (FD_ISSET(net, &excepts)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/*
+ * setneturg()
+ *
+ * Sets "neturg" to the current location.
+ */
+
+void
+setneturg(void)
+{
+ ring_mark(&netoring);
+}
+
+
+/*
+ * netflush
+ * Send as much data as possible to the network,
+ * handling requests for urgent data.
+ *
+ * The return value indicates whether we did any
+ * useful work.
+ */
+
+int
+netflush(void)
+{
+ int n, n1;
+
+#ifdef ENCRYPTION
+ if (encrypt_output)
+ ring_encrypt(&netoring, encrypt_output);
+#endif /* ENCRYPTION */
+ if ((n1 = n = ring_full_consecutive(&netoring)) > 0) {
+ if (!ring_at_mark(&netoring)) {
+ n = send(net, (char *)netoring.consume, n, 0); /* normal write */
+ } else {
+ /*
+ * In 4.2 (and 4.3) systems, there is some question about
+ * what byte in a sendOOB operation is the "OOB" data.
+ * To make ourselves compatible, we only send ONE byte
+ * out of band, the one WE THINK should be OOB (though
+ * we really have more the TCP philosophy of urgent data
+ * rather than the Unix philosophy of OOB data).
+ */
+ n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */
+ }
+ }
+ if (n < 0) {
+ if (errno != ENOBUFS && errno != EWOULDBLOCK) {
+ setcommandmode();
+ perror(hostname);
+ (void)NetClose(net);
+ ring_clear_mark(&netoring);
+ longjmp(peerdied, -1);
+ /*NOTREACHED*/
+ }
+ n = 0;
+ }
+ if (netdata && n) {
+ Dump('>', netoring.consume, n);
+ }
+ if (n) {
+ ring_consumed(&netoring, n);
+ /*
+ * If we sent all, and more to send, then recurse to pick
+ * up the other half.
+ */
+ if ((n1 == n) && ring_full_consecutive(&netoring)) {
+ (void) netflush();
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/remote_cmds/telnet.tproj/ring.c b/remote_cmds/telnet.tproj/ring.c
new file mode 100644
index 0000000..0706133
--- /dev/null
+++ b/remote_cmds/telnet.tproj/ring.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/ring.c,v 1.7 2003/05/04 02:54:48 obrien Exp $");
+
+/*
+ * This defines a structure for a ring buffer.
+ *
+ * The circular buffer has two parts:
+ *(((
+ * full: [consume, supply)
+ * empty: [supply, consume)
+ *]]]
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef size_t
+#undef size_t
+#endif
+
+#include <sys/types.h>
+#ifndef FILIO_H
+#include <sys/ioctl.h>
+#endif
+#include <sys/socket.h>
+
+#include "ring.h"
+#include "general.h"
+
+/* Internal macros */
+
+#if !defined(MIN)
+#define MIN(a,b) (((a)<(b))? (a):(b))
+#endif /* !defined(MIN) */
+
+#define ring_subtract(d,a,b) (((a)-(b) >= 0)? \
+ (a)-(b): (((a)-(b))+(d)->size))
+
+#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \
+ (a)+(c) : (((a)+(c))-(d)->size))
+
+#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \
+ (a)-(c) : (((a)-(c))-(d)->size))
+
+
+/*
+ * The following is a clock, used to determine full, empty, etc.
+ *
+ * There is some trickiness here. Since the ring buffers are initialized
+ * to ZERO on allocation, we need to make sure, when interpreting the
+ * clock, that when the times are EQUAL, then the buffer is FULL.
+ */
+static u_long ring_clock = 0;
+
+
+#define ring_empty(d) (((d)->consume == (d)->supply) && \
+ ((d)->consumetime >= (d)->supplytime))
+#define ring_full(d) (((d)->supply == (d)->consume) && \
+ ((d)->supplytime > (d)->consumetime))
+
+/* Buffer state transition routines */
+
+int
+ring_init(Ring *ring, unsigned char *buffer, int count)
+{
+ memset((char *)ring, 0, sizeof *ring);
+
+ ring->size = count;
+
+ ring->supply = ring->consume = ring->bottom = buffer;
+
+ ring->top = ring->bottom+ring->size;
+
+#ifdef ENCRYPTION
+ ring->clearto = 0;
+#endif /* ENCRYPTION */
+
+ return 1;
+}
+
+/* Mark routines */
+
+/*
+ * Mark the most recently supplied byte.
+ */
+
+void
+ring_mark(Ring *ring)
+{
+ ring->mark = ring_decrement(ring, ring->supply, 1);
+}
+
+/*
+ * Is the ring pointing to the mark?
+ */
+
+int
+ring_at_mark(Ring *ring)
+{
+ if (ring->mark == ring->consume) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Clear any mark set on the ring.
+ */
+
+void
+ring_clear_mark(Ring *ring)
+{
+ ring->mark = 0;
+}
+
+/*
+ * Add characters from current segment to ring buffer.
+ */
+void
+ring_supplied(Ring *ring, int count)
+{
+ ring->supply = ring_increment(ring, ring->supply, count);
+ ring->supplytime = ++ring_clock;
+}
+
+/*
+ * We have just consumed "c" bytes.
+ */
+void
+ring_consumed(Ring *ring, int count)
+{
+ if (count == 0) /* don't update anything */
+ return;
+
+ if (ring->mark &&
+ (ring_subtract(ring, ring->mark, ring->consume) < count)) {
+ ring->mark = 0;
+ }
+#ifdef ENCRYPTION
+ if (ring->consume < ring->clearto &&
+ ring->clearto <= ring->consume + count)
+ ring->clearto = 0;
+ else if (ring->consume + count > ring->top &&
+ ring->bottom <= ring->clearto &&
+ ring->bottom + ((ring->consume + count) - ring->top))
+ ring->clearto = 0;
+#endif /* ENCRYPTION */
+ ring->consume = ring_increment(ring, ring->consume, count);
+ ring->consumetime = ++ring_clock;
+ /*
+ * Try to encourage "ring_empty_consecutive()" to be large.
+ */
+ if (ring_empty(ring)) {
+ ring->consume = ring->supply = ring->bottom;
+ }
+}
+
+
+
+/* Buffer state query routines */
+
+
+/* Number of bytes that may be supplied */
+int
+ring_empty_count(Ring *ring)
+{
+ if (ring_empty(ring)) { /* if empty */
+ return ring->size;
+ } else {
+ return ring_subtract(ring, ring->consume, ring->supply);
+ }
+}
+
+/* number of CONSECUTIVE bytes that may be supplied */
+int
+ring_empty_consecutive(Ring *ring)
+{
+ if ((ring->consume < ring->supply) || ring_empty(ring)) {
+ /*
+ * if consume is "below" supply, or empty, then
+ * return distance to the top
+ */
+ return ring_subtract(ring, ring->top, ring->supply);
+ } else {
+ /*
+ * else, return what we may.
+ */
+ return ring_subtract(ring, ring->consume, ring->supply);
+ }
+}
+
+/* Return the number of bytes that are available for consuming
+ * (but don't give more than enough to get to cross over set mark)
+ */
+
+int
+ring_full_count(Ring *ring)
+{
+ if ((ring->mark == 0) || (ring->mark == ring->consume)) {
+ if (ring_full(ring)) {
+ return ring->size; /* nothing consumed, but full */
+ } else {
+ return ring_subtract(ring, ring->supply, ring->consume);
+ }
+ } else {
+ return ring_subtract(ring, ring->mark, ring->consume);
+ }
+}
+
+/*
+ * Return the number of CONSECUTIVE bytes available for consuming.
+ * However, don't return more than enough to cross over set mark.
+ */
+int
+ring_full_consecutive(Ring *ring)
+{
+ if ((ring->mark == 0) || (ring->mark == ring->consume)) {
+ if ((ring->supply < ring->consume) || ring_full(ring)) {
+ return ring_subtract(ring, ring->top, ring->consume);
+ } else {
+ return ring_subtract(ring, ring->supply, ring->consume);
+ }
+ } else {
+ if (ring->mark < ring->consume) {
+ return ring_subtract(ring, ring->top, ring->consume);
+ } else { /* Else, distance to mark */
+ return ring_subtract(ring, ring->mark, ring->consume);
+ }
+ }
+}
+
+/*
+ * Move data into the "supply" portion of of the ring buffer.
+ */
+void
+ring_supply_data(Ring *ring, unsigned char *buffer, int count)
+{
+ int i;
+
+ while (count) {
+ i = MIN(count, ring_empty_consecutive(ring));
+ memcpy(ring->supply, buffer, i);
+ ring_supplied(ring, i);
+ count -= i;
+ buffer += i;
+ }
+}
+
+#ifdef ENCRYPTION
+void
+ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int))
+{
+ unsigned char *s, *c;
+
+ if (ring_empty(ring) || ring->clearto == ring->supply)
+ return;
+
+ if (!(c = ring->clearto))
+ c = ring->consume;
+
+ s = ring->supply;
+
+ if (s <= c) {
+ (*encryptor)(c, ring->top - c);
+ (*encryptor)(ring->bottom, s - ring->bottom);
+ } else
+ (*encryptor)(c, s - c);
+
+ ring->clearto = ring->supply;
+}
+
+ void
+ring_clearto(ring)
+ Ring *ring;
+{
+ if (!ring_empty(ring))
+ ring->clearto = ring->supply;
+ else
+ ring->clearto = 0;
+}
+#endif /* ENCRYPTION */
diff --git a/remote_cmds/telnet.tproj/ring.h b/remote_cmds/telnet.tproj/ring.h
new file mode 100644
index 0000000..6b8d11d
--- /dev/null
+++ b/remote_cmds/telnet.tproj/ring.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ring.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/contrib/telnet/telnet/ring.h,v 1.4 2001/11/30 22:28:07 markm Exp $
+ */
+
+#if defined(P)
+# undef P
+#endif
+
+#if defined(__STDC__) || defined(LINT_ARGS)
+# define P(x) x
+#else
+# define P(x) ()
+#endif
+
+/*
+ * This defines a structure for a ring buffer.
+ *
+ * The circular buffer has two parts:
+ *(((
+ * full: [consume, supply)
+ * empty: [supply, consume)
+ *]]]
+ *
+ */
+typedef struct {
+ unsigned char *consume, /* where data comes out of */
+ *supply, /* where data comes in to */
+ *bottom, /* lowest address in buffer */
+ *top, /* highest address+1 in buffer */
+ *mark; /* marker (user defined) */
+#ifdef ENCRYPTION
+ unsigned char *clearto; /* Data to this point is clear text */
+ unsigned char *encryyptedto; /* Data is encrypted to here */
+#endif /* ENCRYPTION */
+ int size; /* size in bytes of buffer */
+ u_long consumetime, /* help us keep straight full, empty, etc. */
+ supplytime;
+} Ring;
+
+/* Here are some functions and macros to deal with the ring buffer */
+
+/* Initialization routine */
+extern int
+ ring_init(Ring *ring, unsigned char *buffer, int count);
+
+/* Data movement routines */
+extern void
+ ring_supply_data(Ring *ring, unsigned char *buffer, int count);
+#ifdef notdef
+extern void
+ ring_consume_data(Ring *ring, unsigned char *buffer, int count);
+#endif
+
+/* Buffer state transition routines */
+extern void
+ ring_supplied(Ring *ring, int count),
+ ring_consumed(Ring *ring, int count);
+
+/* Buffer state query routines */
+extern int
+ ring_at_mark(Ring *),
+ ring_empty_count(Ring *ring),
+ ring_empty_consecutive(Ring *ring),
+ ring_full_count(Ring *ring),
+ ring_full_consecutive(Ring *ring);
+
+#ifdef ENCRYPTION
+extern void
+ ring_encrypt(Ring *ring, void (*func)(unsigned char *, int)),
+ ring_clearto(Ring *ring);
+#endif /* ENCRYPTION */
+
+extern void
+ ring_clear_mark(Ring *),
+ ring_mark(Ring *);
diff --git a/remote_cmds/telnet.tproj/sys_bsd.c b/remote_cmds/telnet.tproj/sys_bsd.c
new file mode 100644
index 0000000..0c08223
--- /dev/null
+++ b/remote_cmds/telnet.tproj/sys_bsd.c
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/sys_bsd.c,v 1.12 2003/05/04 02:54:48 obrien Exp $");
+
+/*
+ * The following routines try to encapsulate what is system dependent
+ * (at least between 4.x and dos) which is used in telnet.c.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/telnet.h>
+
+#include "ring.h"
+#include "fdset.h"
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+
+int
+ tout, /* Output file descriptor */
+ tin, /* Input file descriptor */
+ net;
+
+#ifndef USE_TERMIO
+struct tchars otc = { 0 }, ntc = { 0 };
+struct ltchars oltc = { 0 }, nltc = { 0 };
+struct sgttyb ottyb = { 0 }, nttyb = { 0 };
+int olmode = 0;
+# define cfgetispeed(ptr) (ptr)->sg_ispeed
+# define cfgetospeed(ptr) (ptr)->sg_ospeed
+# define old_tc ottyb
+
+#else /* USE_TERMIO */
+struct termio old_tc = { 0, 0, 0, 0, {}, 0, 0 };
+
+# ifndef TCSANOW
+# ifdef TCSETS
+# define TCSANOW TCSETS
+# define TCSADRAIN TCSETSW
+# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+# else
+# ifdef TCSETA
+# define TCSANOW TCSETA
+# define TCSADRAIN TCSETAW
+# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
+# else
+# define TCSANOW TIOCSETA
+# define TCSADRAIN TIOCSETAW
+# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
+# endif
+# endif
+# define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
+# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
+# ifdef CIBAUD
+# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
+# else
+# define cfgetispeed(ptr) cfgetospeed(ptr)
+# endif
+# endif /* TCSANOW */
+# ifdef sysV88
+# define TIOCFLUSH TC_PX_DRAIN
+# endif
+#endif /* USE_TERMIO */
+
+static fd_set *ibitsp, *obitsp, *xbitsp;
+int fdsn;
+
+#ifdef SIGINT
+static SIG_FUNC_RET intr(int);
+#endif /* SIGINT */
+#ifdef SIGQUIT
+static SIG_FUNC_RET intr2(int);
+#endif /* SIGQUIT */
+#ifdef SIGTSTP
+static SIG_FUNC_RET susp(int);
+#endif /* SIGTSTP */
+#ifdef SIGINFO
+static SIG_FUNC_RET ayt(int);
+#endif
+
+void
+init_sys(void)
+{
+ tout = fileno(stdout);
+ tin = fileno(stdin);
+ errno = 0;
+}
+
+int
+TerminalWrite(char *buf, int n)
+{
+ return write(tout, buf, n);
+}
+
+int
+TerminalRead(char *buf, int n)
+{
+ return read(tin, buf, n);
+}
+
+/*
+ *
+ */
+
+int
+TerminalAutoFlush(void)
+{
+#if defined(LNOFLSH)
+ int flush;
+
+ ioctl(0, TIOCLGET, (char *)&flush);
+ return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
+#else /* LNOFLSH */
+ return 1;
+#endif /* LNOFLSH */
+}
+
+#ifdef KLUDGELINEMODE
+extern int kludgelinemode;
+#endif
+/*
+ * TerminalSpecialChars()
+ *
+ * Look at an input character to see if it is a special character
+ * and decide what to do.
+ *
+ * Output:
+ *
+ * 0 Don't add this character.
+ * 1 Do add this character
+ */
+
+int
+TerminalSpecialChars(int c)
+{
+ if (c == termIntChar) {
+ intp();
+ return 0;
+ } else if (c == termQuitChar) {
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ sendbrk();
+ else
+#endif
+ sendabort();
+ return 0;
+ } else if (c == termEofChar) {
+ if (my_want_state_is_will(TELOPT_LINEMODE)) {
+ sendeof();
+ return 0;
+ }
+ return 1;
+ } else if (c == termSuspChar) {
+ sendsusp();
+ return(0);
+ } else if (c == termFlushChar) {
+ xmitAO(); /* Transmit Abort Output */
+ return 0;
+ } else if (!MODE_LOCAL_CHARS(globalmode)) {
+ if (c == termKillChar) {
+ xmitEL();
+ return 0;
+ } else if (c == termEraseChar) {
+ xmitEC(); /* Transmit Erase Character */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/*
+ * Flush output to the terminal
+ */
+
+void
+TerminalFlushOutput(void)
+{
+#ifdef TIOCFLUSH
+ (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
+#else
+ (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
+#endif
+}
+
+void
+TerminalSaveState(void)
+{
+#ifndef USE_TERMIO
+ ioctl(0, TIOCGETP, (char *)&ottyb);
+ ioctl(0, TIOCGETC, (char *)&otc);
+ ioctl(0, TIOCGLTC, (char *)&oltc);
+ ioctl(0, TIOCLGET, (char *)&olmode);
+
+ ntc = otc;
+ nltc = oltc;
+ nttyb = ottyb;
+
+#else /* USE_TERMIO */
+ tcgetattr(0, &old_tc);
+
+ new_tc = old_tc;
+
+#ifndef VDISCARD
+ termFlushChar = CONTROL('O');
+#endif
+#ifndef VWERASE
+ termWerasChar = CONTROL('W');
+#endif
+#ifndef VREPRINT
+ termRprntChar = CONTROL('R');
+#endif
+#ifndef VLNEXT
+ termLiteralNextChar = CONTROL('V');
+#endif
+#ifndef VSTART
+ termStartChar = CONTROL('Q');
+#endif
+#ifndef VSTOP
+ termStopChar = CONTROL('S');
+#endif
+#ifndef VSTATUS
+ termAytChar = CONTROL('T');
+#endif
+#endif /* USE_TERMIO */
+}
+
+cc_t *
+tcval(int func)
+{
+ switch(func) {
+ case SLC_IP: return(&termIntChar);
+ case SLC_ABORT: return(&termQuitChar);
+ case SLC_EOF: return(&termEofChar);
+ case SLC_EC: return(&termEraseChar);
+ case SLC_EL: return(&termKillChar);
+ case SLC_XON: return(&termStartChar);
+ case SLC_XOFF: return(&termStopChar);
+ case SLC_FORW1: return(&termForw1Char);
+#ifdef USE_TERMIO
+ case SLC_FORW2: return(&termForw2Char);
+# ifdef VDISCARD
+ case SLC_AO: return(&termFlushChar);
+# endif
+# ifdef VSUSP
+ case SLC_SUSP: return(&termSuspChar);
+# endif
+# ifdef VWERASE
+ case SLC_EW: return(&termWerasChar);
+# endif
+# ifdef VREPRINT
+ case SLC_RP: return(&termRprntChar);
+# endif
+# ifdef VLNEXT
+ case SLC_LNEXT: return(&termLiteralNextChar);
+# endif
+# ifdef VSTATUS
+ case SLC_AYT: return(&termAytChar);
+# endif
+#endif
+
+ case SLC_SYNCH:
+ case SLC_BRK:
+ case SLC_EOR:
+ default:
+ return((cc_t *)0);
+ }
+}
+
+void
+TerminalDefaultChars(void)
+{
+#ifndef USE_TERMIO
+ ntc = otc;
+ nltc = oltc;
+ nttyb.sg_kill = ottyb.sg_kill;
+ nttyb.sg_erase = ottyb.sg_erase;
+#else /* USE_TERMIO */
+ memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
+# ifndef VDISCARD
+ termFlushChar = CONTROL('O');
+# endif
+# ifndef VWERASE
+ termWerasChar = CONTROL('W');
+# endif
+# ifndef VREPRINT
+ termRprntChar = CONTROL('R');
+# endif
+# ifndef VLNEXT
+ termLiteralNextChar = CONTROL('V');
+# endif
+# ifndef VSTART
+ termStartChar = CONTROL('Q');
+# endif
+# ifndef VSTOP
+ termStopChar = CONTROL('S');
+# endif
+# ifndef VSTATUS
+ termAytChar = CONTROL('T');
+# endif
+#endif /* USE_TERMIO */
+}
+
+/*
+ * TerminalNewMode - set up terminal to a specific mode.
+ * MODE_ECHO: do local terminal echo
+ * MODE_FLOW: do local flow control
+ * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
+ * MODE_EDIT: do local line editing
+ *
+ * Command mode:
+ * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
+ * local echo
+ * local editing
+ * local xon/xoff
+ * local signal mapping
+ *
+ * Linemode:
+ * local/no editing
+ * Both Linemode and Single Character mode:
+ * local/remote echo
+ * local/no xon/xoff
+ * local/no signal mapping
+ */
+
+void
+TerminalNewMode(int f)
+{
+ static int prevmode = 0;
+#ifndef USE_TERMIO
+ struct tchars tc;
+ struct ltchars ltc;
+ struct sgttyb sb;
+ int lmode;
+#else /* USE_TERMIO */
+ struct termio tmp_tc;
+#endif /* USE_TERMIO */
+ int onoff;
+ int old;
+ cc_t esc;
+
+ globalmode = f&~MODE_FORCE;
+ if (prevmode == f)
+ return;
+
+ /*
+ * Write any outstanding data before switching modes
+ * ttyflush() returns 0 only when there is no more data
+ * left to write out, it returns -1 if it couldn't do
+ * anything at all, otherwise it returns 1 + the number
+ * of characters left to write.
+#ifndef USE_TERMIO
+ * We would really like ask the kernel to wait for the output
+ * to drain, like we can do with the TCSADRAIN, but we don't have
+ * that option. The only ioctl that waits for the output to
+ * drain, TIOCSETP, also flushes the input queue, which is NOT
+ * what we want (TIOCSETP is like TCSADFLUSH).
+#endif
+ */
+ old = ttyflush(SYNCHing|flushout);
+ if (old < 0 || old > 1) {
+#ifdef USE_TERMIO
+ tcgetattr(tin, &tmp_tc);
+#endif /* USE_TERMIO */
+ do {
+ /*
+ * Wait for data to drain, then flush again.
+ */
+#ifdef USE_TERMIO
+ tcsetattr(tin, TCSADRAIN, &tmp_tc);
+#endif /* USE_TERMIO */
+ old = ttyflush(SYNCHing|flushout);
+ } while (old < 0 || old > 1);
+ }
+
+ old = prevmode;
+ prevmode = f&~MODE_FORCE;
+#ifndef USE_TERMIO
+ sb = nttyb;
+ tc = ntc;
+ ltc = nltc;
+ lmode = olmode;
+#else
+ tmp_tc = new_tc;
+#endif
+
+ if (f&MODE_ECHO) {
+#ifndef USE_TERMIO
+ sb.sg_flags |= ECHO;
+#else
+ tmp_tc.c_lflag |= ECHO;
+ tmp_tc.c_oflag |= ONLCR;
+ if (crlf)
+ tmp_tc.c_iflag |= ICRNL;
+#endif
+ } else {
+#ifndef USE_TERMIO
+ sb.sg_flags &= ~ECHO;
+#else
+ tmp_tc.c_lflag &= ~ECHO;
+ tmp_tc.c_oflag &= ~ONLCR;
+#endif
+ }
+
+ if ((f&MODE_FLOW) == 0) {
+#ifndef USE_TERMIO
+ tc.t_startc = _POSIX_VDISABLE;
+ tc.t_stopc = _POSIX_VDISABLE;
+#else
+ tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
+ } else {
+ if (restartany < 0) {
+ tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */
+ } else if (restartany > 0) {
+ tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
+ } else {
+ tmp_tc.c_iflag |= IXOFF|IXON;
+ tmp_tc.c_iflag &= ~IXANY;
+ }
+#endif
+ }
+
+ if ((f&MODE_TRAPSIG) == 0) {
+#ifndef USE_TERMIO
+ tc.t_intrc = _POSIX_VDISABLE;
+ tc.t_quitc = _POSIX_VDISABLE;
+ tc.t_eofc = _POSIX_VDISABLE;
+ ltc.t_suspc = _POSIX_VDISABLE;
+ ltc.t_dsuspc = _POSIX_VDISABLE;
+#else
+ tmp_tc.c_lflag &= ~ISIG;
+#endif
+ localchars = 0;
+ } else {
+#ifdef USE_TERMIO
+ tmp_tc.c_lflag |= ISIG;
+#endif
+ localchars = 1;
+ }
+
+ if (f&MODE_EDIT) {
+#ifndef USE_TERMIO
+ sb.sg_flags &= ~CBREAK;
+ sb.sg_flags |= CRMOD;
+#else
+ tmp_tc.c_lflag |= ICANON;
+#endif
+ } else {
+#ifndef USE_TERMIO
+ sb.sg_flags |= CBREAK;
+ if (f&MODE_ECHO)
+ sb.sg_flags |= CRMOD;
+ else
+ sb.sg_flags &= ~CRMOD;
+#else
+ tmp_tc.c_lflag &= ~ICANON;
+ tmp_tc.c_iflag &= ~ICRNL;
+ tmp_tc.c_cc[VMIN] = 1;
+ tmp_tc.c_cc[VTIME] = 0;
+#endif
+ }
+
+ if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
+#ifndef USE_TERMIO
+ ltc.t_lnextc = _POSIX_VDISABLE;
+#else
+# ifdef VLNEXT
+ tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
+# endif
+#endif
+ }
+
+ if (f&MODE_SOFT_TAB) {
+#ifndef USE_TERMIO
+ sb.sg_flags |= XTABS;
+#else
+# ifdef OXTABS
+ tmp_tc.c_oflag |= OXTABS;
+# endif
+# ifdef TABDLY
+ tmp_tc.c_oflag &= ~TABDLY;
+ tmp_tc.c_oflag |= TAB3;
+# endif
+#endif
+ } else {
+#ifndef USE_TERMIO
+ sb.sg_flags &= ~XTABS;
+#else
+# ifdef OXTABS
+ tmp_tc.c_oflag &= ~OXTABS;
+# endif
+# ifdef TABDLY
+ tmp_tc.c_oflag &= ~TABDLY;
+# endif
+#endif
+ }
+
+ if (f&MODE_LIT_ECHO) {
+#ifndef USE_TERMIO
+ lmode &= ~LCTLECH;
+#else
+# ifdef ECHOCTL
+ tmp_tc.c_lflag &= ~ECHOCTL;
+# endif
+#endif
+ } else {
+#ifndef USE_TERMIO
+ lmode |= LCTLECH;
+#else
+# ifdef ECHOCTL
+ tmp_tc.c_lflag |= ECHOCTL;
+# endif
+#endif
+ }
+
+ if (f == -1) {
+ onoff = 0;
+ } else {
+#ifndef USE_TERMIO
+ if (f & MODE_OUTBIN)
+ lmode |= LLITOUT;
+ else
+ lmode &= ~LLITOUT;
+
+ if (f & MODE_INBIN)
+ lmode |= LPASS8;
+ else
+ lmode &= ~LPASS8;
+#else
+ if (f & MODE_INBIN)
+ tmp_tc.c_iflag &= ~ISTRIP;
+ else
+ tmp_tc.c_iflag |= ISTRIP;
+ if (f & MODE_OUTBIN) {
+ tmp_tc.c_cflag &= ~(CSIZE|PARENB);
+ tmp_tc.c_cflag |= CS8;
+ tmp_tc.c_oflag &= ~OPOST;
+ } else {
+ tmp_tc.c_cflag &= ~(CSIZE|PARENB);
+ tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
+ tmp_tc.c_oflag |= OPOST;
+ }
+#endif
+ onoff = 1;
+ }
+
+ if (f != -1) {
+#ifdef SIGINT
+ (void) signal(SIGINT, intr);
+#endif
+#ifdef SIGQUIT
+ (void) signal(SIGQUIT, intr2);
+#endif
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, susp);
+#endif /* SIGTSTP */
+#ifdef SIGINFO
+ (void) signal(SIGINFO, ayt);
+#endif
+#if defined(USE_TERMIO) && defined(NOKERNINFO)
+ tmp_tc.c_lflag |= NOKERNINFO;
+#endif
+ /*
+ * We don't want to process ^Y here. It's just another
+ * character that we'll pass on to the back end. It has
+ * to process it because it will be processed when the
+ * user attempts to read it, not when we send it.
+ */
+#ifndef USE_TERMIO
+ ltc.t_dsuspc = _POSIX_VDISABLE;
+#else
+# ifdef VDSUSP
+ tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
+# endif
+#endif
+#ifdef USE_TERMIO
+ /*
+ * If the VEOL character is already set, then use VEOL2,
+ * otherwise use VEOL.
+ */
+ esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
+ if ((tmp_tc.c_cc[VEOL] != esc)
+# ifdef VEOL2
+ && (tmp_tc.c_cc[VEOL2] != esc)
+# endif
+ ) {
+ if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
+ tmp_tc.c_cc[VEOL] = esc;
+# ifdef VEOL2
+ else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
+ tmp_tc.c_cc[VEOL2] = esc;
+# endif
+ }
+#else
+ if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
+ tc.t_brkc = esc;
+#endif
+ } else {
+#ifdef SIGINFO
+ (void) signal(SIGINFO, (void (*)(int))ayt_status);
+#endif
+#ifdef SIGINT
+ (void) signal(SIGINT, SIG_DFL);
+#endif
+#ifdef SIGQUIT
+ (void) signal(SIGQUIT, SIG_DFL);
+#endif
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, SIG_DFL);
+# ifndef SOLARIS
+ (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+# else /* SOLARIS */
+ (void) sigrelse(SIGTSTP);
+# endif /* SOLARIS */
+#endif /* SIGTSTP */
+#ifndef USE_TERMIO
+ ltc = oltc;
+ tc = otc;
+ sb = ottyb;
+ lmode = olmode;
+#else
+ tmp_tc = old_tc;
+#endif
+ }
+#ifndef USE_TERMIO
+ ioctl(tin, TIOCLSET, (char *)&lmode);
+ ioctl(tin, TIOCSLTC, (char *)&ltc);
+ ioctl(tin, TIOCSETC, (char *)&tc);
+ ioctl(tin, TIOCSETN, (char *)&sb);
+#else
+ if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
+ tcsetattr(tin, TCSANOW, &tmp_tc);
+#endif
+
+ ioctl(tin, FIONBIO, (char *)&onoff);
+ ioctl(tout, FIONBIO, (char *)&onoff);
+
+}
+
+/*
+ * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
+ */
+#if B4800 != 4800
+#define DECODE_BAUD
+#endif
+
+#ifdef DECODE_BAUD
+#ifndef B7200
+#define B7200 B4800
+#endif
+
+#ifndef B14400
+#define B14400 B9600
+#endif
+
+#ifndef B19200
+# define B19200 B14400
+#endif
+
+#ifndef B28800
+#define B28800 B19200
+#endif
+
+#ifndef B38400
+# define B38400 B28800
+#endif
+
+#ifndef B57600
+#define B57600 B38400
+#endif
+
+#ifndef B76800
+#define B76800 B57600
+#endif
+
+#ifndef B115200
+#define B115200 B76800
+#endif
+
+#ifndef B230400
+#define B230400 B115200
+#endif
+
+
+/*
+ * This code assumes that the values B0, B50, B75...
+ * are in ascending order. They do not have to be
+ * contiguous.
+ */
+struct termspeeds {
+ long speed;
+ long value;
+} termspeeds[] = {
+ { 0, B0 }, { 50, B50 }, { 75, B75 },
+ { 110, B110 }, { 134, B134 }, { 150, B150 },
+ { 200, B200 }, { 300, B300 }, { 600, B600 },
+ { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
+ { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 },
+ { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 },
+ { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 },
+ { 230400, B230400 }, { -1, B230400 }
+};
+#endif /* DECODE_BAUD */
+
+void
+TerminalSpeeds(long *ispeed, long *ospeed)
+{
+#ifdef DECODE_BAUD
+ struct termspeeds *tp;
+#endif /* DECODE_BAUD */
+ long in, out;
+
+ out = cfgetospeed(&old_tc);
+ in = cfgetispeed(&old_tc);
+ if (in == 0)
+ in = out;
+
+#ifdef DECODE_BAUD
+ tp = termspeeds;
+ while ((tp->speed != -1) && (tp->value < in))
+ tp++;
+ *ispeed = tp->speed;
+
+ tp = termspeeds;
+ while ((tp->speed != -1) && (tp->value < out))
+ tp++;
+ *ospeed = tp->speed;
+#else /* DECODE_BAUD */
+ *ispeed = in;
+ *ospeed = out;
+#endif /* DECODE_BAUD */
+}
+
+int
+TerminalWindowSize(long *rows, long *cols)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+
+ if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
+ *rows = ws.ws_row;
+ *cols = ws.ws_col;
+ return 1;
+ }
+#endif /* TIOCGWINSZ */
+ return 0;
+}
+
+int
+NetClose(int fd)
+{
+ return close(fd);
+}
+
+static void
+NetNonblockingIO(int fd, int onoff)
+{
+ ioctl(fd, FIONBIO, (char *)&onoff);
+}
+
+
+/*
+ * Various signal handling routines.
+ */
+
+/* ARGSUSED */
+static SIG_FUNC_RET
+deadpeer(int sig __unused)
+{
+ setcommandmode();
+ longjmp(peerdied, -1);
+}
+
+/* ARGSUSED */
+SIG_FUNC_RET
+intr(int sig __unused)
+{
+ if (localchars) {
+ intp();
+ return;
+ }
+ setcommandmode();
+ longjmp(toplevel, -1);
+}
+
+/* ARGSUSED */
+SIG_FUNC_RET
+intr2(int sig __unused)
+{
+ if (localchars) {
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ sendbrk();
+ else
+#endif
+ sendabort();
+ return;
+ }
+}
+
+#ifdef SIGTSTP
+/* ARGSUSED */
+SIG_FUNC_RET
+susp(int sig __unused)
+{
+ if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
+ return;
+ if (localchars)
+ sendsusp();
+}
+#endif
+
+#ifdef SIGWINCH
+/* ARGSUSED */
+static SIG_FUNC_RET
+sendwin(int sig __unused)
+{
+ if (connected) {
+ sendnaws();
+ }
+}
+#endif
+
+#ifdef SIGINFO
+/* ARGSUSED */
+SIG_FUNC_RET
+ayt(int sig __unused)
+{
+ if (connected)
+ sendayt();
+ else
+ ayt_status();
+}
+#endif
+
+
+void
+sys_telnet_init(void)
+{
+ (void) signal(SIGINT, intr);
+ (void) signal(SIGQUIT, intr2);
+ (void) signal(SIGPIPE, deadpeer);
+#ifdef SIGWINCH
+ (void) signal(SIGWINCH, sendwin);
+#endif
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, susp);
+#endif
+#ifdef SIGINFO
+ (void) signal(SIGINFO, ayt);
+#endif
+
+ setconnmode(0);
+
+ NetNonblockingIO(net, 1);
+
+#if defined(SO_OOBINLINE)
+ if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
+ perror("SetSockOpt");
+ }
+#endif /* defined(SO_OOBINLINE) */
+}
+
+/*
+ * Process rings -
+ *
+ * This routine tries to fill up/empty our various rings.
+ *
+ * The parameter specifies whether this is a poll operation,
+ * or a block-until-something-happens operation.
+ *
+ * The return value is 1 if something happened, 0 if not.
+ */
+
+int
+process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll)
+{
+ int c;
+ int returnValue = 0;
+ static struct timeval TimeValue = { 0, 0 };
+ int maxfd = -1;
+ int tmp;
+
+ if ((netout || netin || netex) && net > maxfd)
+ maxfd = net;
+
+ if (ttyout && tout > maxfd)
+ maxfd = tout;
+ if (ttyin && tin > maxfd)
+ maxfd = tin;
+ tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
+ if (tmp > fdsn) {
+ if (ibitsp)
+ free(ibitsp);
+ if (obitsp)
+ free(obitsp);
+ if (xbitsp)
+ free(xbitsp);
+
+ fdsn = tmp;
+ if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ memset(ibitsp, 0, fdsn);
+ memset(obitsp, 0, fdsn);
+ memset(xbitsp, 0, fdsn);
+ }
+
+ if (netout)
+ FD_SET(net, obitsp);
+ if (ttyout)
+ FD_SET(tout, obitsp);
+ if (ttyin)
+ FD_SET(tin, ibitsp);
+ if (netin)
+ FD_SET(net, ibitsp);
+ if (netex)
+ FD_SET(net, xbitsp);
+ if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp,
+ (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
+ if (c == -1) {
+ /*
+ * we can get EINTR if we are in line mode,
+ * and the user does an escape (TSTP), or
+ * some other signal generator.
+ */
+ if (errno == EINTR) {
+ return 0;
+ }
+ /* I don't like this, does it ever happen? */
+ printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
+ sleep(5);
+ }
+ return 0;
+ }
+
+ /*
+ * Any urgent data?
+ */
+ if (FD_ISSET(net, xbitsp)) {
+ FD_CLR(net, xbitsp);
+ SYNCHing = 1;
+ (void) ttyflush(1); /* flush already enqueued data */
+ }
+
+ /*
+ * Something to read from the network...
+ */
+ if (FD_ISSET(net, ibitsp)) {
+ int canread;
+
+ FD_CLR(net, ibitsp);
+ canread = ring_empty_consecutive(&netiring);
+#if !defined(SO_OOBINLINE)
+ /*
+ * In 4.2 (and some early 4.3) systems, the
+ * OOB indication and data handling in the kernel
+ * is such that if two separate TCP Urgent requests
+ * come in, one byte of TCP data will be overlaid.
+ * This is fatal for Telnet, but we try to live
+ * with it.
+ *
+ * In addition, in 4.2 (and...), a special protocol
+ * is needed to pick up the TCP Urgent data in
+ * the correct sequence.
+ *
+ * What we do is: if we think we are in urgent
+ * mode, we look to see if we are "at the mark".
+ * If we are, we do an OOB receive. If we run
+ * this twice, we will do the OOB receive twice,
+ * but the second will fail, since the second
+ * time we were "at the mark", but there wasn't
+ * any data there (the kernel doesn't reset
+ * "at the mark" until we do a normal read).
+ * Once we've read the OOB data, we go ahead
+ * and do normal reads.
+ *
+ * There is also another problem, which is that
+ * since the OOB byte we read doesn't put us
+ * out of OOB state, and since that byte is most
+ * likely the TELNET DM (data mark), we would
+ * stay in the TELNET SYNCH (SYNCHing) state.
+ * So, clocks to the rescue. If we've "just"
+ * received a DM, then we test for the
+ * presence of OOB data when the receive OOB
+ * fails (and AFTER we did the normal mode read
+ * to clear "at the mark").
+ */
+ if (SYNCHing) {
+ int atmark;
+ static int bogus_oob = 0, first = 1;
+
+ ioctl(net, SIOCATMARK, (char *)&atmark);
+ if (atmark) {
+ c = recv(net, netiring.supply, canread, MSG_OOB);
+ if ((c == -1) && (errno == EINVAL)) {
+ c = recv(net, netiring.supply, canread, 0);
+ if (clocks.didnetreceive < clocks.gotDM) {
+ SYNCHing = stilloob(net);
+ }
+ } else if (first && c > 0) {
+ /*
+ * Bogosity check. Systems based on 4.2BSD
+ * do not return an error if you do a second
+ * recv(MSG_OOB). So, we do one. If it
+ * succeeds and returns exactly the same
+ * data, then assume that we are running
+ * on a broken system and set the bogus_oob
+ * flag. (If the data was different, then
+ * we probably got some valid new data, so
+ * increment the count...)
+ */
+ int i;
+ i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
+ if (i == c &&
+ memcmp(netiring.supply, netiring.supply + c, i) == 0) {
+ bogus_oob = 1;
+ first = 0;
+ } else if (i < 0) {
+ bogus_oob = 0;
+ first = 0;
+ } else
+ c += i;
+ }
+ if (bogus_oob && c > 0) {
+ int i;
+ /*
+ * Bogosity. We have to do the read
+ * to clear the atmark to get out of
+ * an infinate loop.
+ */
+ i = read(net, netiring.supply + c, canread - c);
+ if (i > 0)
+ c += i;
+ }
+ } else {
+ c = recv(net, netiring.supply, canread, 0);
+ }
+ } else {
+ c = recv(net, netiring.supply, canread, 0);
+ }
+ settimer(didnetreceive);
+#else /* !defined(SO_OOBINLINE) */
+ c = recv(net, (char *)netiring.supply, canread, 0);
+#endif /* !defined(SO_OOBINLINE) */
+ if (c < 0 && errno == EWOULDBLOCK) {
+ c = 0;
+ } else if (c <= 0) {
+ return -1;
+ }
+ if (netdata) {
+ Dump('<', netiring.supply, c);
+ }
+ if (c)
+ ring_supplied(&netiring, c);
+ returnValue = 1;
+ }
+
+ /*
+ * Something to read from the tty...
+ */
+ if (FD_ISSET(tin, ibitsp)) {
+ FD_CLR(tin, ibitsp);
+ c = TerminalRead((char*)ttyiring.supply, ring_empty_consecutive(&ttyiring));
+ if (c < 0 && errno == EIO)
+ c = 0;
+ if (c < 0 && errno == EWOULDBLOCK) {
+ c = 0;
+ } else {
+ /* EOF detection for line mode!!!! */
+ if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
+ /* must be an EOF... */
+ *ttyiring.supply = termEofChar;
+ c = 1;
+ }
+ if (c <= 0) {
+ return -1;
+ }
+ if (termdata) {
+ Dump('<', ttyiring.supply, c);
+ }
+ ring_supplied(&ttyiring, c);
+ }
+ returnValue = 1; /* did something useful */
+ }
+
+ if (FD_ISSET(net, obitsp)) {
+ FD_CLR(net, obitsp);
+ returnValue |= netflush();
+ }
+ if (FD_ISSET(tout, obitsp)) {
+ FD_CLR(tout, obitsp);
+ returnValue |= (ttyflush(SYNCHing|flushout) > 0);
+ }
+
+ return returnValue;
+}
diff --git a/remote_cmds/telnet.tproj/telnet.1 b/remote_cmds/telnet.tproj/telnet.1
new file mode 100644
index 0000000..46d129d
--- /dev/null
+++ b/remote_cmds/telnet.tproj/telnet.1
@@ -0,0 +1,1417 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)telnet.1 8.6 (Berkeley) 6/1/94
+.\" $FreeBSD: src/crypto/telnet/telnet/telnet.1,v 1.4.2.9 2002/04/13 10:59:08 markm Exp $
+.\"
+.Dd January 27, 2000
+.Dt TELNET 1
+.Os
+.Sh NAME
+.Nm telnet
+.Nd user interface to the
+.Tn TELNET
+protocol
+.Sh SYNOPSIS
+.Nm
+.Op Fl 468EFKLNacdfruxy
+.Op Fl S Ar tos
+.Op Fl X Ar authtype
+.Op Fl e Ar escapechar
+.Op Fl k Ar realm
+.Op Fl l Ar user
+.Op Fl n Ar tracefile
+.Op Fl s Ar src_addr
+.Oo
+.Ar host
+.Op Ar port
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+command
+is used to communicate with another host using the
+.Tn TELNET
+protocol.
+If
+.Nm
+is invoked without the
+.Ar host
+argument, it enters command mode,
+indicated by its prompt
+.Pq Dq Li telnet\&> .
+In this mode, it accepts and executes the commands listed below.
+If it is invoked with arguments, it performs an
+.Ic open
+command with those arguments.
+.Pp
+Options:
+.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl 8
+Specifies an 8-bit data path. This causes an attempt to
+negotiate the
+.Dv TELNET BINARY
+option on both input and output.
+.It Fl E
+Stops any character from being recognized as an escape character.
+.It Fl F
+If Kerberos V5 authentication is being used, the
+.Fl F
+option allows the local credentials to be forwarded
+to the remote system, including any credentials that
+have already been forwarded into the local environment.
+.It Fl K
+Specifies no automatic login to the remote system.
+.It Fl L
+Specifies an 8-bit data path on output. This causes the
+.Dv BINARY
+option to be negotiated on output.
+.It Fl N
+Prevents IP address to name lookup when destination host is given
+as an IP address.
+.It Fl S Ar tos
+Sets the IP type-of-service (TOS) option for the telnet
+connection to the value
+.Ar tos ,
+which can be a numeric TOS value
+or, on systems that support it, a symbolic
+TOS name found in the
+.Pa /etc/iptos
+file.
+.It Fl X Ar atype
+Disables the
+.Ar atype
+type of authentication.
+.It Fl a
+Attempt automatic login.
+This is now the default, so this option is ignored.
+Currently, this sends the user name via the
+.Ev USER
+variable
+of the
+.Ev ENVIRON
+option if supported by the remote system.
+The name used is that of the current user as returned by
+.Xr getlogin 2
+if it agrees with the current user ID,
+otherwise it is the name associated with the user ID.
+.It Fl c
+Disables the reading of the user's
+.Pa \&.telnetrc
+file. (See the
+.Ic toggle skiprc
+command on this man page.)
+.It Fl d
+Sets the initial value of the
+.Ic debug
+toggle to
+.Dv TRUE .
+.It Fl e Ar escapechar
+Sets the initial
+.Nm
+escape character to
+.Ar escapechar .
+If
+.Ar escapechar
+is omitted, then
+there will be no escape character.
+.It Fl f
+If Kerberos V5 authentication is being used, the
+.Fl f
+option allows the local credentials to be forwarded to the remote system.
+.It Fl k Ar realm
+If Kerberos authentication is being used, the
+.Fl k
+option requests that
+.Nm
+obtain tickets for the remote host in
+realm
+.Ar realm
+instead of the remote host's realm, as determined by
+.Xr krb_realmofhost 3 .
+.It Fl l Ar user
+When connecting to the remote system, if the remote system
+understands the
+.Ev ENVIRON
+option, then
+.Ar user
+will be sent to the remote system as the value for the variable
+.Ev USER .
+This option implies the
+.Fl a
+option.
+This option may also be used with the
+.Ic open
+command.
+.It Fl n Ar tracefile
+Opens
+.Ar tracefile
+for recording trace information.
+See the
+.Ic set tracefile
+command below.
+.It Fl r
+Specifies a user interface similar to
+.Xr rlogin 1 .
+In this
+mode, the escape character is set to the tilde (~) character,
+unless modified by the
+.Fl e
+option.
+.It Fl s Ar src_addr
+Set the source IP address for the
+.Nm
+connection to
+.Ar src_addr ,
+which can be an IP address or a host name.
+.It Fl u
+Forces
+.Nm
+to use
+.Dv AF_UNIX
+addresses only (e.g.,
+.Ux
+domain sockets, accessed with a file path).
+.It Fl x
+Turns on encryption of the data stream if possible.
+This is now the default, so this option is ignored.
+.It Fl y
+Suppresses encryption of the data stream.
+.It Ar host
+Indicates the official name, an alias, or the Internet address
+of a remote host.
+If
+.Ar host
+starts with a
+.Ql / ,
+.Nm
+establishes a connection to the corresponding named socket.
+.It Ar port
+Indicates a port number (address of an application). If a number is
+not specified, the default
+.Nm
+port is used.
+.El
+.Pp
+When in rlogin mode, a line of the form ~. disconnects from the
+remote host; ~ is the
+.Nm
+escape character.
+Similarly, the line ~^Z suspends the
+.Nm
+session.
+The line ~^] escapes to the normal
+.Nm
+escape prompt.
+.Pp
+Once a connection has been opened,
+.Nm
+will attempt to enable the
+.Dv TELNET LINEMODE
+option.
+If this fails, then
+.Nm
+will revert to one of two input modes:
+either \*(Lqcharacter at a time\*(Rq
+or \*(Lqold line by line\*(Rq
+depending on what the remote system supports.
+.Pp
+When
+.Dv LINEMODE
+is enabled, character processing is done on the
+local system, under the control of the remote system. When input
+editing or character echoing is to be disabled, the remote system
+will relay that information. The remote system will also relay
+changes to any special characters that happen on the remote
+system, so that they can take effect on the local system.
+.Pp
+In \*(Lqcharacter at a time\*(Rq mode, most
+text typed is immediately sent to the remote host for processing.
+.Pp
+In \*(Lqold line by line\*(Rq mode, all text is echoed locally,
+and (normally) only completed lines are sent to the remote host.
+The \*(Lqlocal echo character\*(Rq (initially \*(Lq^E\*(Rq) may be used
+to turn off and on the local echo
+(this would mostly be used to enter passwords
+without the password being echoed).
+.Pp
+If the
+.Dv LINEMODE
+option is enabled, or if the
+.Ic localchars
+toggle is
+.Dv TRUE
+(the default for \*(Lqold line by line\*(Rq; see below),
+the user's
+.Ic quit ,
+.Ic intr ,
+and
+.Ic flush
+characters are trapped locally, and sent as
+.Tn TELNET
+protocol sequences to the remote side.
+If
+.Dv LINEMODE
+has ever been enabled, then the user's
+.Ic susp
+and
+.Ic eof
+are also sent as
+.Tn TELNET
+protocol sequences,
+and
+.Ic quit
+is sent as a
+.Dv TELNET ABORT
+instead of
+.Dv BREAK .
+There are options (see
+.Ic toggle
+.Ic autoflush
+and
+.Ic toggle
+.Ic autosynch
+below)
+which cause this action to flush subsequent output to the terminal
+(until the remote host acknowledges the
+.Tn TELNET
+sequence) and flush previous terminal input
+(in the case of
+.Ic quit
+and
+.Ic intr ) .
+.Pp
+While connected to a remote host,
+.Nm
+command mode may be entered by typing the
+.Nm
+\*(Lqescape character\*(Rq (initially \*(Lq^]\*(Rq).
+When in command mode, the normal terminal editing conventions are available.
+.Pp
+The following
+.Nm
+commands are available.
+Only enough of each command to uniquely identify it need be typed
+(this is also true for arguments to the
+.Ic mode ,
+.Ic set ,
+.Ic toggle ,
+.Ic unset ,
+.Ic slc ,
+.Ic environ ,
+and
+.Ic display
+commands).
+.Pp
+.Bl -tag -width "mode type"
+.It Ic auth Ar argument ...
+The auth command manipulates the information sent through the
+.Dv TELNET AUTHENTICATE
+option. Valid arguments for the
+.Ic auth
+command are:
+.Bl -tag -width "disable type"
+.It Ic disable Ar type
+Disables the specified type of authentication. To
+obtain a list of available types, use the
+.Ic auth disable ?\&
+command.
+.It Ic enable Ar type
+Enables the specified type of authentication. To
+obtain a list of available types, use the
+.Ic auth enable ?\&
+command.
+.It Ic status
+Lists the current status of the various types of
+authentication.
+.El
+.It Ic close
+Close a
+.Tn TELNET
+session and return to command mode.
+.It Ic display Ar argument ...
+Displays all, or some, of the
+.Ic set
+and
+.Ic toggle
+values (see below).
+.It Ic encrypt Ar argument ...
+The encrypt command manipulates the information sent through the
+.Dv TELNET ENCRYPT
+option.
+.Pp
+Valid arguments for the
+.Ic encrypt
+command are:
+.Bl -tag -width Ar
+.It Ic disable Ar type Xo
+.Op Cm input | output
+.Xc
+Disables the specified type of encryption. If you
+omit the input and output, both input and output
+are disabled. To obtain a list of available
+types, use the
+.Ic encrypt disable ?\&
+command.
+.It Ic enable Ar type Xo
+.Op Cm input | output
+.Xc
+Enables the specified type of encryption. If you
+omit input and output, both input and output are
+enabled. To obtain a list of available types, use the
+.Ic encrypt enable ?\&
+command.
+.It Ic input
+This is the same as the
+.Ic encrypt start input
+command.
+.It Ic -input
+This is the same as the
+.Ic encrypt stop input
+command.
+.It Ic output
+This is the same as the
+.Ic encrypt start output
+command.
+.It Ic -output
+This is the same as the
+.Ic encrypt stop output
+command.
+.It Ic start Op Cm input | output
+Attempts to start encryption. If you omit
+.Ic input
+and
+.Ic output ,
+both input and output are enabled. To
+obtain a list of available types, use the
+.Ic encrypt enable ?\&
+command.
+.It Ic status
+Lists the current status of encryption.
+.It Ic stop Op Cm input | output
+Stops encryption. If you omit input and output,
+encryption is on both input and output.
+.It Ic type Ar type
+Sets the default type of encryption to be used
+with later
+.Ic encrypt start
+or
+.Ic encrypt stop
+commands.
+.El
+.It Ic environ Ar arguments ...
+The
+.Ic environ
+command is used to manipulate the
+variables that may be sent through the
+.Dv TELNET ENVIRON
+option.
+The initial set of variables is populated with the
+contents of the following environment variables, if
+present:
+.Ev USER , PRINTER , DISPLAY , TERM , COLUMNS , LINES.
+Only the first three are exported, by default.
+.Pp
+Valid arguments for the
+.Ic environ
+command are:
+.Bl -tag -width Fl
+.It Ic define Ar variable [value]
+Define the variable
+.Ar variable
+to have a value of
+.Ar value .
+If value is empty, the value is taken from the environment variable.
+Any variables defined by this command are automatically exported.
+The
+.Ar value
+may be enclosed in single or double quotes so
+that tabs and spaces may be included.
+.It Ic undefine Ar variable
+Remove
+.Ar variable
+from the list of environment variables.
+.It Ic export Ar variable
+Mark the variable
+.Ar variable
+to be exported to the remote side.
+.It Ic unexport Ar variable
+Mark the variable
+.Ar variable
+to not be exported unless
+explicitly asked for by the remote side.
+.It Ic list
+List the current set of environment variables.
+Those marked with a
+.Cm *
+will be sent automatically,
+other variables will only be sent if explicitly requested.
+.It Ic ?\&
+Prints out help information for the
+.Ic environ
+command.
+.El
+.It Ic logout
+Sends the
+.Dv TELNET LOGOUT
+option to the remote side.
+This command is similar to a
+.Ic close
+command; however, if the remote side does not support the
+.Dv LOGOUT
+option, nothing happens.
+If, however, the remote side does support the
+.Dv LOGOUT
+option, this command should cause the remote side to close the
+.Tn TELNET
+connection.
+If the remote side also supports the concept of
+suspending a user's session for later reattachment,
+the logout argument indicates that you
+should terminate the session immediately.
+.It Ic mode Ar type
+.Ar Type
+is one of several options, depending on the state of the
+.Tn TELNET
+session.
+The remote host is asked for permission to go into the requested mode.
+If the remote host is capable of entering that mode, the requested
+mode will be entered.
+.Bl -tag -width Ar
+.It Ic character
+Disable the
+.Dv TELNET LINEMODE
+option, or, if the remote side does not understand the
+.Dv LINEMODE
+option, then enter \*(Lqcharacter at a time\*(Rq mode.
+.It Ic line
+Enable the
+.Dv TELNET LINEMODE
+option, or, if the remote side does not understand the
+.Dv LINEMODE
+option, then attempt to enter \*(Lqold-line-by-line\*(Rq mode.
+.It Ic isig Pq Ic \-isig
+Attempt to enable (disable) the
+.Dv TRAPSIG
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic edit Pq Ic \-edit
+Attempt to enable (disable) the
+.Dv EDIT
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic softtabs Pq Ic \-softtabs
+Attempt to enable (disable) the
+.Dv SOFT_TAB
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic litecho Pq Ic \-litecho
+Attempt to enable (disable) the
+.Dv LIT_ECHO
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic ?\&
+Prints out help information for the
+.Ic mode
+command.
+.El
+.It Xo
+.Ic open Ar host
+.Op Fl l Ar user
+.Op Oo Fl Oc Ns Ar port
+.Xc
+Open a connection to the named host.
+If no port number
+is specified,
+.Nm
+will attempt to contact a
+.Tn TELNET
+server at the default port.
+The host specification may be either a host name (see
+.Xr hosts 5 ) ,
+an Internet address specified in the \*(Lqdot notation\*(Rq (see
+.Xr inet 3 ) ,
+or IPv6 host name or IPv6 coloned-hexadecimal addreess.
+The
+.Fl l
+option may be used to specify the user name
+to be passed to the remote system via the
+.Ev ENVIRON
+option.
+When connecting to a non-standard port,
+.Nm
+omits any automatic initiation of
+.Tn TELNET
+options. When the port number is preceded by a minus sign,
+the initial option negotiation is done.
+After establishing a connection, the file
+.Pa \&.telnetrc
+in the
+users home directory is opened. Lines beginning with a # are
+comment lines. Blank lines are ignored. Lines that begin
+without white space are the start of a machine entry. The
+first thing on the line is the name of the machine that is
+being connected to. The rest of the line, and successive
+lines that begin with white space are assumed to be
+.Nm
+commands and are processed as if they had been typed
+in manually to the
+.Nm
+command prompt.
+.It Ic quit
+Close any open
+.Tn TELNET
+session and exit
+.Nm .
+An end of file (in command mode) will also close a session and exit.
+.It Ic send Ar arguments
+Sends one or more special character sequences to the remote host.
+The following are the arguments which may be specified
+(more than one argument may be specified at a time):
+.Pp
+.Bl -tag -width escape
+.It Ic abort
+Sends the
+.Dv TELNET ABORT
+(Abort
+processes)
+sequence.
+.It Ic ao
+Sends the
+.Dv TELNET AO
+(Abort Output) sequence, which should cause the remote system to flush
+all output
+.Em from
+the remote system
+.Em to
+the user's terminal.
+.It Ic ayt
+Sends the
+.Dv TELNET AYT
+(Are You There)
+sequence, to which the remote system may or may not choose to respond.
+.It Ic brk
+Sends the
+.Dv TELNET BRK
+(Break) sequence, which may have significance to the remote
+system.
+.It Ic ec
+Sends the
+.Dv TELNET EC
+(Erase Character)
+sequence, which should cause the remote system to erase the last character
+entered.
+.It Ic el
+Sends the
+.Dv TELNET EL
+(Erase Line)
+sequence, which should cause the remote system to erase the line currently
+being entered.
+.It Ic eof
+Sends the
+.Dv TELNET EOF
+(End Of File)
+sequence.
+.It Ic eor
+Sends the
+.Dv TELNET EOR
+(End of Record)
+sequence.
+.It Ic escape
+Sends the current
+.Nm
+escape character (initially \*(Lq^\*(Rq).
+.It Ic ga
+Sends the
+.Dv TELNET GA
+(Go Ahead)
+sequence, which likely has no significance to the remote system.
+.It Ic getstatus
+If the remote side supports the
+.Dv TELNET STATUS
+command,
+.Ic getstatus
+will send the subnegotiation to request that the server send
+its current option status.
+.It Ic ip
+Sends the
+.Dv TELNET IP
+(Interrupt Process) sequence, which should cause the remote
+system to abort the currently running process.
+.It Ic nop
+Sends the
+.Dv TELNET NOP
+(No OPeration)
+sequence.
+.It Ic susp
+Sends the
+.Dv TELNET SUSP
+(SUSPend process)
+sequence.
+.It Ic synch
+Sends the
+.Dv TELNET SYNCH
+sequence.
+This sequence causes the remote system to discard all previously typed
+(but not yet read) input.
+This sequence is sent as
+.Tn TCP
+urgent
+data (and may not work if the remote system is a
+.Bx 4.2
+system -- if
+it doesn't work, a lower case \*(Lqr\*(Rq may be echoed on the terminal).
+.It Ic do Ar cmd
+.It Ic dont Ar cmd
+.It Ic will Ar cmd
+.It Ic wont Ar cmd
+Sends the
+.Dv TELNET DO
+.Ar cmd
+sequence.
+.Ar Cmd
+can be either a decimal number between 0 and 255,
+or a symbolic name for a specific
+.Dv TELNET
+command.
+.Ar Cmd
+can also be either
+.Ic help
+or
+.Ic ?\&
+to print out help information, including
+a list of known symbolic names.
+.It Ic ?\&
+Prints out help information for the
+.Ic send
+command.
+.El
+.It Ic set Ar argument value
+.It Ic unset Ar argument value
+The
+.Ic set
+command will set any one of a number of
+.Nm
+variables to a specific value or to
+.Dv TRUE .
+The special value
+.Ic off
+turns off the function associated with
+the variable, this is equivalent to using the
+.Ic unset
+command.
+The
+.Ic unset
+command will disable or set to
+.Dv FALSE
+any of the specified functions.
+The values of variables may be interrogated with the
+.Ic display
+command.
+The variables which may be set or unset, but not toggled, are
+listed here. In addition, any of the variables for the
+.Ic toggle
+command may be explicitly set or unset using
+the
+.Ic set
+and
+.Ic unset
+commands.
+.Bl -tag -width escape
+.It Ic ayt
+If
+.Tn TELNET
+is in localchars mode, or
+.Dv LINEMODE
+is enabled, and the status character is typed, a
+.Dv TELNET AYT
+sequence (see
+.Ic send ayt
+preceding) is sent to the
+remote host. The initial value for the \*(LqAre You There\*(Rq
+character is the terminal's status character.
+.It Ic echo
+This is the value (initially \*(Lq^E\*(Rq) which, when in
+\*(Lqline by line\*(Rq mode, toggles between doing local echoing
+of entered characters (for normal processing), and suppressing
+echoing of entered characters (for entering, say, a password).
+.It Ic eof
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, entering this character
+as the first character on a line will cause this character to be
+sent to the remote system.
+The initial value of the eof character is taken to be the terminal's
+.Ic eof
+character.
+.It Ic erase
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below),
+.Sy and
+if
+.Nm
+is operating in \*(Lqcharacter at a time\*(Rq mode, then when this
+character is typed, a
+.Dv TELNET EC
+sequence (see
+.Ic send
+.Ic ec
+above)
+is sent to the remote system.
+The initial value for the erase character is taken to be
+the terminal's
+.Ic erase
+character.
+.It Ic escape
+This is the
+.Nm
+escape character (initially \*(Lq^[\*(Rq) which causes entry
+into
+.Nm
+command mode (when connected to a remote system).
+.It Ic flushoutput
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below)
+and the
+.Ic flushoutput
+character is typed, a
+.Dv TELNET AO
+sequence (see
+.Ic send
+.Ic ao
+above)
+is sent to the remote host.
+The initial value for the flush character is taken to be
+the terminal's
+.Ic flush
+character.
+.It Ic forw1
+.It Ic forw2
+If
+.Nm
+is operating in
+.Dv LINEMODE ,
+these are the
+characters that, when typed, cause partial lines to be
+forwarded to the remote system. The initial value for
+the forwarding characters are taken from the terminal's
+eol and eol2 characters.
+.It Ic interrupt
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below)
+and the
+.Ic interrupt
+character is typed, a
+.Dv TELNET IP
+sequence (see
+.Ic send
+.Ic ip
+above)
+is sent to the remote host.
+The initial value for the interrupt character is taken to be
+the terminal's
+.Ic intr
+character.
+.It Ic kill
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below),
+.Ic and
+if
+.Nm
+is operating in \*(Lqcharacter at a time\*(Rq mode, then when this
+character is typed, a
+.Dv TELNET EL
+sequence (see
+.Ic send
+.Ic el
+above)
+is sent to the remote system.
+The initial value for the kill character is taken to be
+the terminal's
+.Ic kill
+character.
+.It Ic lnext
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, then this character is taken to
+be the terminal's
+.Ic lnext
+character.
+The initial value for the lnext character is taken to be
+the terminal's
+.Ic lnext
+character.
+.It Ic quit
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below)
+and the
+.Ic quit
+character is typed, a
+.Dv TELNET BRK
+sequence (see
+.Ic send
+.Ic brk
+above)
+is sent to the remote host.
+The initial value for the quit character is taken to be
+the terminal's
+.Ic quit
+character.
+.It Ic reprint
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, then this character is taken to
+be the terminal's
+.Ic reprint
+character.
+The initial value for the reprint character is taken to be
+the terminal's
+.Ic reprint
+character.
+.It Ic rlogin
+This is the rlogin escape character.
+If set, the normal
+.Nm
+escape character is ignored unless it is
+preceded by this character at the beginning of a line.
+This character, at the beginning of a line followed by
+a "." closes the connection; when followed by a ^Z it
+suspends the
+.Nm
+command. The initial state is to
+disable the
+.Nm rlogin
+escape character.
+.It Ic start
+If the
+.Dv TELNET TOGGLE-FLOW-CONTROL
+option has been enabled,
+then this character is taken to
+be the terminal's
+.Ic start
+character.
+The initial value for the start character is taken to be
+the terminal's
+.Ic start
+character.
+.It Ic stop
+If the
+.Dv TELNET TOGGLE-FLOW-CONTROL
+option has been enabled,
+then this character is taken to
+be the terminal's
+.Ic stop
+character.
+The initial value for the stop character is taken to be
+the terminal's
+.Ic stop
+character.
+.It Ic susp
+If
+.Nm
+is in
+.Ic localchars
+mode, or
+.Dv LINEMODE
+is enabled, and the
+.Ic suspend
+character is typed, a
+.Dv TELNET SUSP
+sequence (see
+.Ic send
+.Ic susp
+above)
+is sent to the remote host.
+The initial value for the suspend character is taken to be
+the terminal's
+.Ic suspend
+character.
+.It Ic tracefile
+This is the file to which the output, caused by
+.Ic netdata
+or
+.Ic option
+tracing being
+.Dv TRUE ,
+will be written. If it is set to
+.Dq Fl ,
+then tracing information will be written to standard output (the default).
+.It Ic worderase
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, then this character is taken to
+be the terminal's
+.Ic worderase
+character.
+The initial value for the worderase character is taken to be
+the terminal's
+.Ic worderase
+character.
+.It Ic ?\&
+Displays the legal
+.Ic set
+.Pq Ic unset
+commands.
+.El
+.It Ic opie Ar sequence challenge
+The
+.Ic opie
+command computes a response to the OPIE challenge.
+.It Ic slc Ar state
+The
+.Ic slc
+command (Set Local Characters) is used to set
+or change the state of the special
+characters when the
+.Dv TELNET LINEMODE
+option has
+been enabled. Special characters are characters that get
+mapped to
+.Tn TELNET
+commands sequences (like
+.Ic ip
+or
+.Ic quit )
+or line editing characters (like
+.Ic erase
+and
+.Ic kill ) .
+By default, the local special characters are exported.
+.Bl -tag -width Fl
+.It Ic check
+Verify the current settings for the current special characters.
+The remote side is requested to send all the current special
+character settings, and if there are any discrepancies with
+the local side, the local side will switch to the remote value.
+.It Ic export
+Switch to the local defaults for the special characters. The
+local default characters are those of the local terminal at
+the time when
+.Nm
+was started.
+.It Ic import
+Switch to the remote defaults for the special characters.
+The remote default characters are those of the remote system
+at the time when the
+.Tn TELNET
+connection was established.
+.It Ic ?\&
+Prints out help information for the
+.Ic slc
+command.
+.El
+.It Ic status
+Show the current status of
+.Nm .
+This includes the peer one is connected to, as well
+as the current mode.
+.It Ic toggle Ar arguments ...
+Toggle (between
+.Dv TRUE
+and
+.Dv FALSE )
+various flags that control how
+.Nm
+responds to events.
+These flags may be set explicitly to
+.Dv TRUE
+or
+.Dv FALSE
+using the
+.Ic set
+and
+.Ic unset
+commands listed above.
+More than one argument may be specified.
+The state of these flags may be interrogated with the
+.Ic display
+command.
+Valid arguments are:
+.Bl -tag -width Ar
+.It Ic authdebug
+Turns on debugging information for the authentication code.
+.It Ic autoflush
+If
+.Ic autoflush
+and
+.Ic localchars
+are both
+.Dv TRUE ,
+then when the
+.Ic ao ,
+or
+.Ic quit
+characters are recognized (and transformed into
+.Tn TELNET
+sequences; see
+.Ic set
+above for details),
+.Nm
+refuses to display any data on the user's terminal
+until the remote system acknowledges (via a
+.Dv TELNET TIMING MARK
+option)
+that it has processed those
+.Tn TELNET
+sequences.
+The initial value for this toggle is
+.Dv TRUE
+if the terminal user had not
+done an "stty noflsh", otherwise
+.Dv FALSE
+(see
+.Xr stty 1 ) .
+.It Ic autodecrypt
+When the
+.Dv TELNET ENCRYPT
+option is negotiated, by
+default the actual encryption (decryption) of the data
+stream does not start automatically. The autoencrypt
+(autodecrypt) command states that encryption of the
+output (input) stream should be enabled as soon as
+possible.
+.It Ic autologin
+If the remote side supports the
+.Dv TELNET AUTHENTICATION
+option
+.Nm
+attempts to use it to perform automatic authentication. If the
+.Dv AUTHENTICATION
+option is not supported, the user's login
+name are propagated through the
+.Dv TELNET ENVIRON
+option.
+This command is the same as specifying
+.Fl a
+option on the
+.Ic open
+command.
+.It Ic autosynch
+If
+.Ic autosynch
+and
+.Ic localchars
+are both
+.Dv TRUE ,
+then when either the
+.Ic intr
+or
+.Ic quit
+characters is typed (see
+.Ic set
+above for descriptions of the
+.Ic intr
+and
+.Ic quit
+characters), the resulting
+.Tn TELNET
+sequence sent is followed by the
+.Dv TELNET SYNCH
+sequence.
+This procedure
+.Ic should
+cause the remote system to begin throwing away all previously
+typed input until both of the
+.Tn TELNET
+sequences have been read and acted upon.
+The initial value of this toggle is
+.Dv FALSE .
+.It Ic binary
+Enable or disable the
+.Dv TELNET BINARY
+option on both input and output.
+.It Ic inbinary
+Enable or disable the
+.Dv TELNET BINARY
+option on input.
+.It Ic outbinary
+Enable or disable the
+.Dv TELNET BINARY
+option on output.
+.It Ic crlf
+If this is
+.Dv TRUE ,
+then carriage returns will be sent as
+.Li <CR><LF> .
+If this is
+.Dv FALSE ,
+then carriage returns will be send as
+.Li <CR><NUL> .
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic crmod
+Toggle carriage return mode.
+When this mode is enabled, most carriage return characters received from
+the remote host will be mapped into a carriage return followed by
+a line feed.
+This mode does not affect those characters typed by the user, only
+those received from the remote host.
+This mode is not very useful unless the remote host
+only sends carriage return, but never line feed.
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic debug
+Toggles socket level debugging (useful only to the
+.Ic super user ) .
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic encdebug
+Turns on debugging information for the encryption code.
+.It Ic localchars
+If this is
+.Dv TRUE ,
+then the
+.Ic flush ,
+.Ic interrupt ,
+.Ic quit ,
+.Ic erase ,
+and
+.Ic kill
+characters (see
+.Ic set
+above) are recognized locally, and transformed into (hopefully) appropriate
+.Tn TELNET
+control sequences
+(respectively
+.Ic ao ,
+.Ic ip ,
+.Ic brk ,
+.Ic ec ,
+and
+.Ic el ;
+see
+.Ic send
+above).
+The initial value for this toggle is
+.Dv TRUE
+in \*(Lqold line by line\*(Rq mode,
+and
+.Dv FALSE
+in \*(Lqcharacter at a time\*(Rq mode.
+When the
+.Dv LINEMODE
+option is enabled, the value of
+.Ic localchars
+is ignored, and assumed to always be
+.Dv TRUE .
+If
+.Dv LINEMODE
+has ever been enabled, then
+.Ic quit
+is sent as
+.Ic abort ,
+and
+.Ic eof
+and
+.Ic suspend
+are sent as
+.Ic eof
+and
+.Ic susp
+(see
+.Ic send
+above).
+.It Ic netdata
+Toggles the display of all network data (in hexadecimal format).
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic options
+Toggles the display of some internal
+.Nm
+protocol processing (having to do with
+.Tn TELNET
+options).
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic prettydump
+When the
+.Ic netdata
+toggle is enabled, if
+.Ic prettydump
+is enabled the output from the
+.Ic netdata
+command will be formatted in a more user readable format.
+Spaces are put between each character in the output, and the
+beginning of any
+.Nm
+escape sequence is preceded by a '*' to aid in locating them.
+.It Ic skiprc
+When the skiprc toggle is
+.Dv TRUE ,
+.Nm
+skips the reading of the
+.Pa \&.telnetrc
+file in the users home
+directory when connections are opened. The initial
+value for this toggle is
+.Dv FALSE .
+.It Ic termdata
+Toggles the display of all terminal data (in hexadecimal format).
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic verbose_encrypt
+When the
+.Ic verbose_encrypt
+toggle is
+.Dv TRUE ,
+.Nm
+prints out a message each time encryption is enabled or
+disabled. The initial value for this toggle is
+.Dv FALSE .
+.It Ic ?\&
+Displays the legal
+.Ic toggle
+commands.
+.El
+.It Ic z
+Suspend
+.Nm .
+This command only works when the user is using the
+.Xr csh 1 .
+.It Ic \&! Op Ar command
+Execute a single command in a subshell on the local
+system. If
+.Ar command
+is omitted, then an interactive
+subshell is invoked.
+.It Ic ?\& Op Ar command
+Get help. With no arguments,
+.Nm
+prints a help summary.
+If
+.Ar command
+is specified,
+.Nm
+will print the help information for just that command.
+.El
+.Sh ENVIRONMENT
+.Nm
+uses at least the
+.Ev HOME ,
+.Ev SHELL ,
+.Ev DISPLAY ,
+and
+.Ev TERM
+environment variables.
+Other environment variables may be propagated
+to the other side via the
+.Dv TELNET ENVIRON
+option.
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr rsh 1 ,
+.Xr hosts 5 ,
+.Xr nologin 5 ,
+.Xr telnetd 8
+.Sh FILES
+.Bl -tag -width ~/.telnetrc -compact
+.It Pa ~/.telnetrc
+user customized telnet startup values
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
+.Sh NOTES
+On some remote systems, echo has to be turned off manually when in
+\*(Lqold line by line\*(Rq mode.
+.Pp
+In \*(Lqold line by line\*(Rq mode or
+.Dv LINEMODE
+the terminal's
+.Ic eof
+character is only recognized (and sent to the remote system)
+when it is the first character on a line.
diff --git a/remote_cmds/telnet.tproj/telnet.c b/remote_cmds/telnet.tproj/telnet.c
new file mode 100644
index 0000000..541cf9b
--- /dev/null
+++ b/remote_cmds/telnet.tproj/telnet.c
@@ -0,0 +1,2418 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/telnet.c,v 1.16 2005/03/28 14:45:12 nectar Exp $");
+
+#include <sys/types.h>
+
+/* By the way, we need to include curses.h before telnet.h since,
+ * among other things, telnet.h #defines 'DO', which is a variable
+ * declared in curses.h.
+ */
+
+#include <ctype.h>
+#include <curses.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <term.h>
+#include <unistd.h>
+#include <arpa/telnet.h>
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+#include "general.h"
+
+#ifdef TERMCAP
+#include <curses.h>
+#include <term.h>
+#endif /* TERMCAP */
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+#include <libtelnet/misc.h>
+
+#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
+
+static unsigned char subbuffer[SUBBUFSIZE],
+ *subpointer, *subend; /* buffer for sub-options */
+#define SB_CLEAR() subpointer = subbuffer;
+#define SB_TERM() { subend = subpointer; SB_CLEAR(); }
+#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
+ *subpointer++ = (c); \
+ }
+
+#define SB_GET() ((*subpointer++)&0xff)
+#define SB_PEEK() ((*subpointer)&0xff)
+#define SB_EOF() (subpointer >= subend)
+#define SB_LEN() (subend - subpointer)
+
+char options[256]; /* The combined options */
+char do_dont_resp[256];
+char will_wont_resp[256];
+
+int
+ eight = 0,
+ autologin = 0, /* Autologin anyone? */
+ skiprc = 0,
+ connected,
+ showoptions,
+ ISend, /* trying to send network data in */
+ telnet_debug = 0,
+ crmod,
+ netdata, /* Print out network data flow */
+ crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+ telnetport,
+ SYNCHing, /* we are in TELNET SYNCH mode */
+ flushout, /* flush output */
+ autoflush = 0, /* flush output when interrupting? */
+ autosynch, /* send interrupt characters with SYNCH? */
+ localflow, /* we handle flow control locally */
+ restartany, /* if flow control enabled, restart on any character */
+ localchars, /* we recognize interrupt/quit */
+ donelclchars, /* the user has set "localchars" */
+ donebinarytoggle, /* the user has put us in binary */
+ dontlecho, /* do we suppress local echoing right now? */
+ globalmode,
+ doaddrlookup = 1, /* do a reverse address lookup? */
+ clienteof = 0;
+
+char *prompt = 0;
+#ifdef ENCRYPTION
+char *line; /* hack around breakage in sra.c :-( !! */
+#endif
+
+cc_t escape;
+cc_t rlogin;
+#ifdef KLUDGELINEMODE
+cc_t echoc;
+#endif
+
+/*
+ * Telnet receiver states for fsm
+ */
+#define TS_DATA 0
+#define TS_IAC 1
+#define TS_WILL 2
+#define TS_WONT 3
+#define TS_DO 4
+#define TS_DONT 5
+#define TS_CR 6
+#define TS_SB 7 /* sub-option collection */
+#define TS_SE 8 /* looking for sub-option end */
+
+static int telrcv_state;
+#ifdef OLD_ENVIRON
+unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
+#else
+# define telopt_environ TELOPT_NEW_ENVIRON
+#endif
+
+jmp_buf toplevel;
+jmp_buf peerdied;
+
+int flushline;
+int linemode;
+
+#ifdef KLUDGELINEMODE
+int kludgelinemode = 1;
+#endif
+
+static int is_unique(char *, char **, char **);
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+Clocks clocks;
+
+/*
+ * Initialize telnet environment.
+ */
+
+void
+init_telnet(void)
+{
+ env_init();
+
+ SB_CLEAR();
+ ClearArray(options);
+
+ connected = ISend = localflow = donebinarytoggle = 0;
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ auth_encrypt_connect(connected);
+#endif
+#endif
+ restartany = -1;
+
+ SYNCHing = 0;
+
+ /* Don't change NetTrace */
+
+ escape = CONTROL(']');
+ rlogin = _POSIX_VDISABLE;
+#ifdef KLUDGELINEMODE
+ echoc = CONTROL('E');
+#endif
+
+ flushline = 1;
+ telrcv_state = TS_DATA;
+}
+
+
+/*
+ * These routines are in charge of sending option negotiations
+ * to the other side.
+ *
+ * The basic idea is that we send the negotiation if either side
+ * is in disagreement as to what the current state should be.
+ */
+
+void
+send_do(int c, int init)
+{
+ if (init) {
+ if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
+ my_want_state_is_do(c))
+ return;
+ set_my_want_state_do(c);
+ do_dont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, DO);
+ NETADD(c);
+ printoption("SENT", DO, c);
+}
+
+void
+send_dont(int c, int init)
+{
+ if (init) {
+ if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
+ my_want_state_is_dont(c))
+ return;
+ set_my_want_state_dont(c);
+ do_dont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, DONT);
+ NETADD(c);
+ printoption("SENT", DONT, c);
+}
+
+void
+send_will(int c, int init)
+{
+ if (init) {
+ if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
+ my_want_state_is_will(c))
+ return;
+ set_my_want_state_will(c);
+ will_wont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, WILL);
+ NETADD(c);
+ printoption("SENT", WILL, c);
+}
+
+void
+send_wont(int c, int init)
+{
+ if (init) {
+ if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
+ my_want_state_is_wont(c))
+ return;
+ set_my_want_state_wont(c);
+ will_wont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, WONT);
+ NETADD(c);
+ printoption("SENT", WONT, c);
+}
+
+void
+willoption(int option)
+{
+ int new_state_ok = 0;
+
+ if (do_dont_resp[option]) {
+ --do_dont_resp[option];
+ if (do_dont_resp[option] && my_state_is_do(option))
+ --do_dont_resp[option];
+ }
+
+ if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
+
+ switch (option) {
+
+ case TELOPT_ECHO:
+ case TELOPT_BINARY:
+ case TELOPT_SGA:
+ settimer(modenegotiated);
+ /* FALLTHROUGH */
+ case TELOPT_STATUS:
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+#endif
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+#endif /* ENCRYPTION */
+ new_state_ok = 1;
+ break;
+
+ case TELOPT_TM:
+ if (flushout)
+ flushout = 0;
+ /*
+ * Special case for TM. If we get back a WILL,
+ * pretend we got back a WONT.
+ */
+ set_my_want_state_dont(option);
+ set_my_state_dont(option);
+ return; /* Never reply to TM will's/wont's */
+
+ case TELOPT_LINEMODE:
+ default:
+ break;
+ }
+
+ if (new_state_ok) {
+ set_my_want_state_do(option);
+ send_do(option, 0);
+ setconnmode(0); /* possibly set new tty mode */
+ } else {
+ do_dont_resp[option]++;
+ send_dont(option, 0);
+ }
+ }
+ set_my_state_do(option);
+#ifdef ENCRYPTION
+ if (option == TELOPT_ENCRYPT)
+ encrypt_send_support();
+#endif /* ENCRYPTION */
+}
+
+void
+wontoption(int option)
+{
+ if (do_dont_resp[option]) {
+ --do_dont_resp[option];
+ if (do_dont_resp[option] && my_state_is_dont(option))
+ --do_dont_resp[option];
+ }
+
+ if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
+
+ switch (option) {
+
+#ifdef KLUDGELINEMODE
+ case TELOPT_SGA:
+ if (!kludgelinemode)
+ break;
+ /* FALLTHROUGH */
+#endif
+ case TELOPT_ECHO:
+ settimer(modenegotiated);
+ break;
+
+ case TELOPT_TM:
+ if (flushout)
+ flushout = 0;
+ set_my_want_state_dont(option);
+ set_my_state_dont(option);
+ return; /* Never reply to TM will's/wont's */
+
+ default:
+ break;
+ }
+ set_my_want_state_dont(option);
+ if (my_state_is_do(option))
+ send_dont(option, 0);
+ setconnmode(0); /* Set new tty mode */
+ } else if (option == TELOPT_TM) {
+ /*
+ * Special case for TM.
+ */
+ if (flushout)
+ flushout = 0;
+ set_my_want_state_dont(option);
+ }
+ set_my_state_dont(option);
+}
+
+static void
+dooption(int option)
+{
+ int new_state_ok = 0;
+
+ if (will_wont_resp[option]) {
+ --will_wont_resp[option];
+ if (will_wont_resp[option] && my_state_is_will(option))
+ --will_wont_resp[option];
+ }
+
+ if (will_wont_resp[option] == 0) {
+ if (my_want_state_is_wont(option)) {
+
+ switch (option) {
+
+ case TELOPT_TM:
+ /*
+ * Special case for TM. We send a WILL, but pretend
+ * we sent WONT.
+ */
+ send_will(option, 0);
+ set_my_want_state_wont(TELOPT_TM);
+ set_my_state_wont(TELOPT_TM);
+ return;
+
+ case TELOPT_BINARY: /* binary mode */
+ case TELOPT_NAWS: /* window size */
+ case TELOPT_TSPEED: /* terminal speed */
+ case TELOPT_LFLOW: /* local flow control */
+ case TELOPT_TTYPE: /* terminal type option */
+ case TELOPT_SGA: /* no big deal */
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT: /* encryption variable option */
+#endif /* ENCRYPTION */
+ new_state_ok = 1;
+ break;
+
+ case TELOPT_NEW_ENVIRON: /* New environment variable option */
+#ifdef OLD_ENVIRON
+ if (my_state_is_will(TELOPT_OLD_ENVIRON))
+ send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
+ goto env_common;
+ case TELOPT_OLD_ENVIRON: /* Old environment variable option */
+ if (my_state_is_will(TELOPT_NEW_ENVIRON))
+ break; /* Don't enable if new one is in use! */
+ env_common:
+ telopt_environ = option;
+#endif
+ new_state_ok = 1;
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (autologin)
+ new_state_ok = 1;
+ break;
+#endif
+
+ case TELOPT_XDISPLOC: /* X Display location */
+ if (env_getvalue((const unsigned char *)"DISPLAY"))
+ new_state_ok = 1;
+ break;
+
+ case TELOPT_LINEMODE:
+#ifdef KLUDGELINEMODE
+ kludgelinemode = 0;
+ send_do(TELOPT_SGA, 1);
+#endif
+ set_my_want_state_will(TELOPT_LINEMODE);
+ send_will(option, 0);
+ set_my_state_will(TELOPT_LINEMODE);
+ slc_init();
+ return;
+
+ case TELOPT_ECHO: /* We're never going to echo... */
+ default:
+ break;
+ }
+
+ if (new_state_ok) {
+ set_my_want_state_will(option);
+ send_will(option, 0);
+ setconnmode(0); /* Set new tty mode */
+ } else {
+ will_wont_resp[option]++;
+ send_wont(option, 0);
+ }
+ } else {
+ /*
+ * Handle options that need more things done after the
+ * other side has acknowledged the option.
+ */
+ switch (option) {
+ case TELOPT_LINEMODE:
+#ifdef KLUDGELINEMODE
+ kludgelinemode = 0;
+ send_do(TELOPT_SGA, 1);
+#endif
+ set_my_state_will(option);
+ slc_init();
+ send_do(TELOPT_SGA, 0);
+ return;
+ }
+ }
+ }
+ set_my_state_will(option);
+}
+
+static void
+dontoption(int option)
+{
+
+ if (will_wont_resp[option]) {
+ --will_wont_resp[option];
+ if (will_wont_resp[option] && my_state_is_wont(option))
+ --will_wont_resp[option];
+ }
+
+ if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
+ switch (option) {
+ case TELOPT_LINEMODE:
+ linemode = 0; /* put us back to the default state */
+ break;
+#ifdef OLD_ENVIRON
+ case TELOPT_NEW_ENVIRON:
+ /*
+ * The new environ option wasn't recognized, try
+ * the old one.
+ */
+ send_will(TELOPT_OLD_ENVIRON, 1);
+ telopt_environ = TELOPT_OLD_ENVIRON;
+ break;
+#endif
+ }
+ /* we always accept a DONT */
+ set_my_want_state_wont(option);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
+ setconnmode(0); /* Set new tty mode */
+ }
+ set_my_state_wont(option);
+}
+
+/*
+ * Given a buffer returned by tgetent(), this routine will turn
+ * the pipe separated list of names in the buffer into an array
+ * of pointers to null terminated names. We toss out any bad,
+ * duplicate, or verbose names (names with spaces).
+ */
+
+static const char *name_unknown = "UNKNOWN";
+static const char *unknown[] = { NULL, NULL };
+
+static const char **
+mklist(char *buf, char *name)
+{
+ int n;
+ char c, *cp, **argvp, *cp2, **argv, **avt;
+
+ if (name) {
+ if (strlen(name) > 40) {
+ name = 0;
+ unknown[0] = name_unknown;
+ } else {
+ unknown[0] = name;
+ upcase(name);
+ }
+ } else
+ unknown[0] = name_unknown;
+ /*
+ * Count up the number of names.
+ */
+ for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
+ if (*cp == '|')
+ n++;
+ }
+ /*
+ * Allocate an array to put the name pointers into
+ */
+ argv = (char **)malloc((n+3)*sizeof(char *));
+ if (argv == 0)
+ return(unknown);
+
+ /*
+ * Fill up the array of pointers to names.
+ */
+ *argv = 0;
+ argvp = argv+1;
+ n = 0;
+ for (cp = cp2 = buf; (c = *cp); cp++) {
+ if (c == '|' || c == ':') {
+ *cp++ = '\0';
+ /*
+ * Skip entries that have spaces or are over 40
+ * characters long. If this is our environment
+ * name, then put it up front. Otherwise, as
+ * long as this is not a duplicate name (case
+ * insensitive) add it to the list.
+ */
+ if (n || (cp - cp2 > 41))
+ ;
+ else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
+ *argv = cp2;
+ else if (is_unique(cp2, argv+1, argvp))
+ *argvp++ = cp2;
+ if (c == ':')
+ break;
+ /*
+ * Skip multiple delimiters. Reset cp2 to
+ * the beginning of the next name. Reset n,
+ * the flag for names with spaces.
+ */
+ while ((c = *cp) == '|')
+ cp++;
+ cp2 = cp;
+ n = 0;
+ }
+ /*
+ * Skip entries with spaces or non-ascii values.
+ * Convert lower case letters to upper case.
+ */
+ if ((c == ' ') || !isascii(c))
+ n = 1;
+ else if (islower(c))
+ *cp = toupper(c);
+ }
+
+ /*
+ * Check for an old V6 2 character name. If the second
+ * name points to the beginning of the buffer, and is
+ * only 2 characters long, move it to the end of the array.
+ */
+ if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
+ --argvp;
+ for (avt = &argv[1]; avt < argvp; avt++)
+ *avt = *(avt+1);
+ *argvp++ = buf;
+ }
+
+ /*
+ * Duplicate last name, for TTYPE option, and null
+ * terminate the array. If we didn't find a match on
+ * our terminal name, put that name at the beginning.
+ */
+ cp = *(argvp-1);
+ *argvp++ = cp;
+ *argvp = 0;
+
+ if (*argv == 0) {
+ if (name)
+ *argv = name;
+ else {
+ --argvp;
+ for (avt = argv; avt < argvp; avt++)
+ *avt = *(avt+1);
+ }
+ }
+ if (*argv)
+ return((const char **)argv);
+ else
+ return(unknown);
+}
+
+static int
+is_unique(char *name, char **as, char **ae)
+{
+ char **ap;
+ int n;
+
+ n = strlen(name) + 1;
+ for (ap = as; ap < ae; ap++)
+ if (strncasecmp(*ap, name, n) == 0)
+ return(0);
+ return (1);
+}
+
+#ifdef TERMCAP
+char termbuf[1024];
+
+/*ARGSUSED*/
+#ifdef __APPLE__
+__private_extern__ int
+#else
+static int
+#endif
+setupterm(char *tname, int fd, int *errp)
+{
+ if (tgetent(termbuf, tname) == 1) {
+ termbuf[1023] = '\0';
+ if (errp)
+ *errp = 1;
+ return(0);
+ }
+ if (errp)
+ *errp = 0;
+ return(-1);
+}
+#else
+#define termbuf ttytype
+extern char ttytype[];
+#endif
+
+int resettermname = 1;
+
+static const char *
+gettermname(void)
+{
+ char *tname;
+ static const char **tnamep = 0;
+ static const char **next;
+ int err;
+
+ if (resettermname) {
+ resettermname = 0;
+ if (tnamep && tnamep != unknown)
+ free(tnamep);
+ if ((tname = (char *)env_getvalue((const unsigned char *)"TERM")) &&
+ (setupterm(tname, 1, &err) == 0)) {
+ tnamep = mklist(termbuf, tname);
+ } else {
+ if (tname && (strlen(tname) <= 40)) {
+ unknown[0] = tname;
+ upcase(tname);
+ } else
+ unknown[0] = name_unknown;
+ tnamep = unknown;
+ }
+ next = tnamep;
+ }
+ if (*next == 0)
+ next = tnamep;
+ return(*next++);
+}
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ * Currently we recognize:
+ *
+ * Terminal type, send request.
+ * Terminal speed (send request).
+ * Local flow control (is request).
+ * Linemode
+ */
+
+static void
+suboption(void)
+{
+ unsigned char subchar;
+
+ printsub('<', subbuffer, SB_LEN()+2);
+ switch (subchar = SB_GET()) {
+ case TELOPT_TTYPE:
+ if (my_want_state_is_wont(TELOPT_TTYPE))
+ return;
+ if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
+ return;
+ } else {
+ const char *name;
+ unsigned char temp[50];
+ int len;
+
+ name = gettermname();
+ len = strlen(name) + 4 + 2;
+ if (len < NETROOM()) {
+ sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+ TELQUAL_IS, name, IAC, SE);
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', &temp[2], len-2);
+ } else {
+ ExitString("No room in buffer for terminal type.\n", 1);
+ /*NOTREACHED*/
+ }
+ }
+ break;
+ case TELOPT_TSPEED:
+ if (my_want_state_is_wont(TELOPT_TSPEED))
+ return;
+ if (SB_EOF())
+ return;
+ if (SB_GET() == TELQUAL_SEND) {
+ long ospeed, ispeed;
+ unsigned char temp[50];
+ int len;
+
+ TerminalSpeeds(&ispeed, &ospeed);
+
+ sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
+ TELQUAL_IS, ospeed, ispeed, IAC, SE);
+ len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
+
+ if (len < NETROOM()) {
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', temp+2, len - 2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ }
+ break;
+ case TELOPT_LFLOW:
+ if (my_want_state_is_wont(TELOPT_LFLOW))
+ return;
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case LFLOW_RESTART_ANY:
+ restartany = 1;
+ break;
+ case LFLOW_RESTART_XON:
+ restartany = 0;
+ break;
+ case LFLOW_ON:
+ localflow = 1;
+ break;
+ case LFLOW_OFF:
+ localflow = 0;
+ break;
+ default:
+ return;
+ }
+ setcommandmode();
+ setconnmode(0);
+ break;
+
+ case TELOPT_LINEMODE:
+ if (my_want_state_is_wont(TELOPT_LINEMODE))
+ return;
+ if (SB_EOF())
+ return;
+ switch (SB_GET()) {
+ case WILL:
+ lm_will(subpointer, SB_LEN());
+ break;
+ case WONT:
+ lm_wont(subpointer, SB_LEN());
+ break;
+ case DO:
+ lm_do(subpointer, SB_LEN());
+ break;
+ case DONT:
+ lm_dont(subpointer, SB_LEN());
+ break;
+ case LM_SLC:
+ slc(subpointer, SB_LEN());
+ break;
+ case LM_MODE:
+ lm_mode(subpointer, SB_LEN(), 0);
+ break;
+ default:
+ break;
+ }
+ break;
+
+#ifdef OLD_ENVIRON
+ case TELOPT_OLD_ENVIRON:
+#endif
+ case TELOPT_NEW_ENVIRON:
+ if (SB_EOF())
+ return;
+ switch(SB_PEEK()) {
+ case TELQUAL_IS:
+ case TELQUAL_INFO:
+ if (my_want_state_is_dont(subchar))
+ return;
+ break;
+ case TELQUAL_SEND:
+ if (my_want_state_is_wont(subchar)) {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ env_opt(subpointer, SB_LEN());
+ break;
+
+ case TELOPT_XDISPLOC:
+ if (my_want_state_is_wont(TELOPT_XDISPLOC))
+ return;
+ if (SB_EOF())
+ return;
+ if (SB_GET() == TELQUAL_SEND) {
+ unsigned char temp[50], *dp;
+ int len;
+
+ if ((dp = env_getvalue((const unsigned char *)"DISPLAY")) == NULL ||
+ strlen((const char *)dp) > sizeof(temp) - 7) {
+ /*
+ * Something happened, we no longer have a DISPLAY
+ * variable. Or it is too long. So, turn off the option.
+ */
+ send_wont(TELOPT_XDISPLOC, 1);
+ break;
+ }
+ snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB,
+ TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
+ len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
+
+ if (len < NETROOM()) {
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', temp+2, len - 2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ }
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION: {
+ if (!autologin)
+ break;
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case TELQUAL_IS:
+ if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+ return;
+ auth_is(subpointer, SB_LEN());
+ break;
+ case TELQUAL_SEND:
+ if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ return;
+ auth_send(subpointer, SB_LEN());
+ break;
+ case TELQUAL_REPLY:
+ if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ return;
+ auth_reply(subpointer, SB_LEN());
+ break;
+ case TELQUAL_NAME:
+ if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+ return;
+ auth_name(subpointer, SB_LEN());
+ break;
+ }
+ }
+ break;
+#endif
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case ENCRYPT_START:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_END:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_end();
+ break;
+ case ENCRYPT_SUPPORT:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_support(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQSTART:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_request_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQEND:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ /*
+ * We can always send an REQEND so that we cannot
+ * get stuck encrypting. We should only get this
+ * if we have been able to get in the correct mode
+ * anyhow.
+ */
+ encrypt_request_end();
+ break;
+ case ENCRYPT_IS:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_is(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REPLY:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_reply(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_ENC_KEYID:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_enc_keyid(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_DEC_KEYID:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_dec_keyid(subpointer, SB_LEN());
+ break;
+ default:
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+ default:
+ break;
+ }
+}
+
+static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
+
+void
+lm_will(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK: /* We shouldn't ever get this... */
+ default:
+ str_lm[3] = DONT;
+ str_lm[4] = cmd[0];
+ if (NETROOM() > (int)sizeof(str_lm)) {
+ ring_supply_data(&netoring, str_lm, sizeof(str_lm));
+ printsub('>', &str_lm[2], sizeof(str_lm)-2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ break;
+ }
+}
+
+void
+lm_wont(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK: /* We shouldn't ever get this... */
+ default:
+ /* We are always DONT, so don't respond */
+ return;
+ }
+}
+
+void
+lm_do(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK:
+ default:
+ str_lm[3] = WONT;
+ str_lm[4] = cmd[0];
+ if (NETROOM() > (int)sizeof(str_lm)) {
+ ring_supply_data(&netoring, str_lm, sizeof(str_lm));
+ printsub('>', &str_lm[2], sizeof(str_lm)-2);
+ }
+/*@*/ else printf("lm_do: not enough room in buffer\n");
+ break;
+ }
+}
+
+void
+lm_dont(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK:
+ default:
+ /* we are always WONT, so don't respond */
+ break;
+ }
+}
+
+static unsigned char str_lm_mode[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
+};
+
+void
+lm_mode(unsigned char *cmd, int len, int init)
+{
+ if (len != 1)
+ return;
+ if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
+ return;
+ if (*cmd&MODE_ACK)
+ return;
+ linemode = *cmd&(MODE_MASK&~MODE_ACK);
+ str_lm_mode[4] = linemode;
+ if (!init)
+ str_lm_mode[4] |= MODE_ACK;
+ if (NETROOM() > (int)sizeof(str_lm_mode)) {
+ ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
+ printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
+ }
+/*@*/ else printf("lm_mode: not enough room in buffer\n");
+ setconnmode(0); /* set changed mode */
+}
+
+
+
+/*
+ * slc()
+ * Handle special character suboption of LINEMODE.
+ */
+
+struct spc {
+ cc_t val;
+ cc_t *valp;
+ char flags; /* Current flags & level */
+ char mylevel; /* Maximum level & flags */
+} spc_data[NSLC+1];
+
+#define SLC_IMPORT 0
+#define SLC_EXPORT 1
+#define SLC_RVALUE 2
+static int slc_mode = SLC_EXPORT;
+
+void
+slc_init(void)
+{
+ struct spc *spcp;
+
+ localchars = 1;
+ for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
+ spcp->val = 0;
+ spcp->valp = 0;
+ spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
+ }
+
+#define initfunc(func, flags) { \
+ spcp = &spc_data[func]; \
+ if ((spcp->valp = tcval(func))) { \
+ spcp->val = *spcp->valp; \
+ spcp->mylevel = SLC_VARIABLE|flags; \
+ } else { \
+ spcp->val = 0; \
+ spcp->mylevel = SLC_DEFAULT; \
+ } \
+ }
+
+ initfunc(SLC_SYNCH, 0);
+ /* No BRK */
+ initfunc(SLC_AO, 0);
+ initfunc(SLC_AYT, 0);
+ /* No EOR */
+ initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
+ initfunc(SLC_EOF, 0);
+#ifndef SYSV_TERMIO
+ initfunc(SLC_SUSP, SLC_FLUSHIN);
+#endif
+ initfunc(SLC_EC, 0);
+ initfunc(SLC_EL, 0);
+#ifndef SYSV_TERMIO
+ initfunc(SLC_EW, 0);
+ initfunc(SLC_RP, 0);
+ initfunc(SLC_LNEXT, 0);
+#endif
+ initfunc(SLC_XON, 0);
+ initfunc(SLC_XOFF, 0);
+#ifdef SYSV_TERMIO
+ spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
+ spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
+#endif
+ initfunc(SLC_FORW1, 0);
+#ifdef USE_TERMIO
+ initfunc(SLC_FORW2, 0);
+ /* No FORW2 */
+#endif
+
+ initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
+#undef initfunc
+
+ if (slc_mode == SLC_EXPORT)
+ slc_export();
+ else
+ slc_import(1);
+
+}
+
+void
+slcstate(void)
+{
+ printf("Special characters are %s values\n",
+ slc_mode == SLC_IMPORT ? "remote default" :
+ slc_mode == SLC_EXPORT ? "local" :
+ "remote");
+}
+
+void
+slc_mode_export(void)
+{
+ slc_mode = SLC_EXPORT;
+ if (my_state_is_will(TELOPT_LINEMODE))
+ slc_export();
+}
+
+void
+slc_mode_import(int def)
+{
+ slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
+ if (my_state_is_will(TELOPT_LINEMODE))
+ slc_import(def);
+}
+
+unsigned char slc_import_val[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
+};
+unsigned char slc_import_def[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
+};
+
+void
+slc_import(int def)
+{
+ if (NETROOM() > (int)sizeof(slc_import_val)) {
+ if (def) {
+ ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
+ printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
+ } else {
+ ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
+ printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
+ }
+ }
+/*@*/ else printf("slc_import: not enough room\n");
+}
+
+void
+slc_export(void)
+{
+ struct spc *spcp;
+
+ TerminalDefaultChars();
+
+ slc_start_reply();
+ for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+ if (spcp->mylevel != SLC_NOSUPPORT) {
+ if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+ spcp->flags = SLC_NOSUPPORT;
+ else
+ spcp->flags = spcp->mylevel;
+ if (spcp->valp)
+ spcp->val = *spcp->valp;
+ slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
+ }
+ }
+ slc_end_reply();
+ (void)slc_update();
+ setconnmode(1); /* Make sure the character values are set */
+}
+
+void
+slc(unsigned char *cp, int len)
+{
+ struct spc *spcp;
+ int func,level;
+
+ slc_start_reply();
+
+ for (; len >= 3; len -=3, cp +=3) {
+
+ func = cp[SLC_FUNC];
+
+ if (func == 0) {
+ /*
+ * Client side: always ignore 0 function.
+ */
+ continue;
+ }
+ if (func > NSLC) {
+ if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
+ slc_add_reply(func, SLC_NOSUPPORT, 0);
+ continue;
+ }
+
+ spcp = &spc_data[func];
+
+ level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
+
+ if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
+ ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
+ continue;
+ }
+
+ if (level == (SLC_DEFAULT|SLC_ACK)) {
+ /*
+ * This is an error condition, the SLC_ACK
+ * bit should never be set for the SLC_DEFAULT
+ * level. Our best guess to recover is to
+ * ignore the SLC_ACK bit.
+ */
+ cp[SLC_FLAGS] &= ~SLC_ACK;
+ }
+
+ if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
+ spcp->val = (cc_t)cp[SLC_VALUE];
+ spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
+ continue;
+ }
+
+ level &= ~SLC_ACK;
+
+ if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
+ spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
+ spcp->val = (cc_t)cp[SLC_VALUE];
+ }
+ if (level == SLC_DEFAULT) {
+ if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
+ spcp->flags = spcp->mylevel;
+ else
+ spcp->flags = SLC_NOSUPPORT;
+ }
+ slc_add_reply(func, spcp->flags, spcp->val);
+ }
+ slc_end_reply();
+ if (slc_update())
+ setconnmode(1); /* set the new character values */
+}
+
+void
+slc_check(void)
+{
+ struct spc *spcp;
+
+ slc_start_reply();
+ for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+ if (spcp->valp && spcp->val != *spcp->valp) {
+ spcp->val = *spcp->valp;
+ if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+ spcp->flags = SLC_NOSUPPORT;
+ else
+ spcp->flags = spcp->mylevel;
+ slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
+ }
+ }
+ slc_end_reply();
+ setconnmode(1);
+}
+
+unsigned char slc_reply[128];
+unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
+unsigned char *slc_replyp;
+
+void
+slc_start_reply(void)
+{
+ slc_replyp = slc_reply;
+ *slc_replyp++ = IAC;
+ *slc_replyp++ = SB;
+ *slc_replyp++ = TELOPT_LINEMODE;
+ *slc_replyp++ = LM_SLC;
+}
+
+void
+slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
+{
+ /* A sequence of up to 6 bytes my be written for this member of the SLC
+ * suboption list by this function. The end of negotiation command,
+ * which is written by slc_end_reply(), will require 2 additional
+ * bytes. Do not proceed unless there is sufficient space for these
+ * items.
+ */
+ if (&slc_replyp[6+2] > slc_reply_eom)
+ return;
+ if ((*slc_replyp++ = func) == IAC)
+ *slc_replyp++ = IAC;
+ if ((*slc_replyp++ = flags) == IAC)
+ *slc_replyp++ = IAC;
+ if ((*slc_replyp++ = (unsigned char)value) == IAC)
+ *slc_replyp++ = IAC;
+}
+
+void
+slc_end_reply(void)
+{
+ int len;
+
+ /* The end of negotiation command requires 2 bytes. */
+ if (&slc_replyp[2] > slc_reply_eom)
+ return;
+ *slc_replyp++ = IAC;
+ *slc_replyp++ = SE;
+ len = slc_replyp - slc_reply;
+ if (len <= 6)
+ return;
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
+ printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
+ }
+/*@*/else printf("slc_end_reply: not enough room\n");
+}
+
+int
+slc_update(void)
+{
+ struct spc *spcp;
+ int need_update = 0;
+
+ for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+ if (!(spcp->flags&SLC_ACK))
+ continue;
+ spcp->flags &= ~SLC_ACK;
+ if (spcp->valp && (*spcp->valp != spcp->val)) {
+ *spcp->valp = spcp->val;
+ need_update = 1;
+ }
+ }
+ return(need_update);
+}
+
+#ifdef OLD_ENVIRON
+# ifdef ENV_HACK
+/*
+ * Earlier version of telnet/telnetd from the BSD code had
+ * the definitions of VALUE and VAR reversed. To ensure
+ * maximum interoperability, we assume that the server is
+ * an older BSD server, until proven otherwise. The newer
+ * BSD servers should be able to handle either definition,
+ * so it is better to use the wrong values if we don't
+ * know what type of server it is.
+ */
+int env_auto = 1;
+int old_env_var = OLD_ENV_VAR;
+int old_env_value = OLD_ENV_VALUE;
+# else
+# define old_env_var OLD_ENV_VAR
+# define old_env_value OLD_ENV_VALUE
+# endif
+#endif
+
+void
+env_opt(unsigned char *buf, int len)
+{
+ unsigned char *ep = 0, *epc = 0;
+ int i;
+
+ switch(buf[0]&0xff) {
+ case TELQUAL_SEND:
+ env_opt_start();
+ if (len == 1) {
+ env_opt_add(NULL);
+ } else for (i = 1; i < len; i++) {
+ switch (buf[i]&0xff) {
+#ifdef OLD_ENVIRON
+ case OLD_ENV_VAR:
+# ifdef ENV_HACK
+ if (telopt_environ == TELOPT_OLD_ENVIRON
+ && env_auto) {
+ /* Server has the same definitions */
+ old_env_var = OLD_ENV_VAR;
+ old_env_value = OLD_ENV_VALUE;
+ }
+ /* FALLTHROUGH */
+# endif
+ case OLD_ENV_VALUE:
+ /*
+ * Although OLD_ENV_VALUE is not legal, we will
+ * still recognize it, just in case it is an
+ * old server that has VAR & VALUE mixed up...
+ */
+ /* FALLTHROUGH */
+#else
+ case NEW_ENV_VAR:
+#endif
+ case ENV_USERVAR:
+ if (ep) {
+ *epc = 0;
+ env_opt_add(ep);
+ }
+ ep = epc = &buf[i+1];
+ break;
+ case ENV_ESC:
+ i++;
+ /*FALLTHROUGH*/
+ default:
+ if (epc)
+ *epc++ = buf[i];
+ break;
+ }
+ }
+ if (ep) {
+ *epc = 0;
+ env_opt_add(ep);
+ }
+ env_opt_end(1);
+ break;
+
+ case TELQUAL_IS:
+ case TELQUAL_INFO:
+ /* Ignore for now. We shouldn't get it anyway. */
+ break;
+
+ default:
+ break;
+ }
+}
+
+#define OPT_REPLY_SIZE (2 * SUBBUFSIZE)
+unsigned char *opt_reply = NULL;
+unsigned char *opt_replyp;
+unsigned char *opt_replyend;
+
+void
+env_opt_start(void)
+{
+ if (opt_reply)
+ opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
+ else
+ opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
+ if (opt_reply == NULL) {
+/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ return;
+ }
+ opt_replyp = opt_reply;
+ opt_replyend = opt_reply + OPT_REPLY_SIZE;
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SB;
+ *opt_replyp++ = telopt_environ;
+ *opt_replyp++ = TELQUAL_IS;
+}
+
+void
+env_opt_start_info(void)
+{
+ env_opt_start();
+ if (opt_replyp)
+ opt_replyp[-1] = TELQUAL_INFO;
+}
+
+void
+env_opt_add(unsigned char *ep)
+{
+ unsigned char *vp, c;
+
+ if (opt_reply == NULL) /*XXX*/
+ return; /*XXX*/
+
+ if (ep == NULL || *ep == '\0') {
+ /* Send user defined variables first. */
+ env_default(1, 0);
+ while ((ep = env_default(0, 0)))
+ env_opt_add(ep);
+
+ /* Now add the list of well know variables. */
+ env_default(1, 1);
+ while ((ep = env_default(0, 1)))
+ env_opt_add(ep);
+ return;
+ }
+ vp = env_getvalue(ep);
+ if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
+ 2 * strlen((char *)ep) + 6 > opt_replyend)
+ {
+ int len;
+#ifdef __APPLE__
+ // rdar://problem/4022837
+ opt_replyend += OPT_REPLY_SIZE + 2*strlen((char *)ep) + 2*(vp ? strlen((char *)vp) : 0);
+#else
+ opt_replyend += OPT_REPLY_SIZE;
+#endif
+ len = opt_replyend - opt_reply;
+ opt_reply = (unsigned char *)realloc(opt_reply, len);
+ if (opt_reply == NULL) {
+/*@*/ printf("env_opt_add: realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ return;
+ }
+ opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
+ opt_replyend = opt_reply + len;
+ }
+ if (opt_welldefined((const char *)ep))
+#ifdef OLD_ENVIRON
+ if (telopt_environ == TELOPT_OLD_ENVIRON)
+ *opt_replyp++ = old_env_var;
+ else
+#endif
+ *opt_replyp++ = NEW_ENV_VAR;
+ else
+ *opt_replyp++ = ENV_USERVAR;
+ for (;;) {
+ while ((c = *ep++)) {
+ if (opt_replyp + (2 + 2) > opt_replyend)
+ return;
+ switch(c&0xff) {
+ case IAC:
+ *opt_replyp++ = IAC;
+ break;
+ case NEW_ENV_VAR:
+ case NEW_ENV_VALUE:
+ case ENV_ESC:
+ case ENV_USERVAR:
+ *opt_replyp++ = ENV_ESC;
+ break;
+ }
+ *opt_replyp++ = c;
+ }
+ if ((ep = vp)) {
+ if (opt_replyp + (1 + 2 + 2) > opt_replyend)
+ return;
+#ifdef OLD_ENVIRON
+ if (telopt_environ == TELOPT_OLD_ENVIRON)
+ *opt_replyp++ = old_env_value;
+ else
+#endif
+ *opt_replyp++ = NEW_ENV_VALUE;
+ vp = NULL;
+ } else
+ break;
+ }
+}
+
+int
+opt_welldefined(const char *ep)
+{
+ if ((strcmp(ep, "USER") == 0) ||
+ (strcmp(ep, "DISPLAY") == 0) ||
+ (strcmp(ep, "PRINTER") == 0) ||
+ (strcmp(ep, "SYSTEMTYPE") == 0) ||
+ (strcmp(ep, "JOB") == 0) ||
+ (strcmp(ep, "ACCT") == 0))
+ return(1);
+ return(0);
+}
+
+void
+env_opt_end(int emptyok)
+{
+ int len;
+
+ if (opt_replyp + 2 > opt_replyend)
+ return;
+ len = opt_replyp + 2 - opt_reply;
+ if (emptyok || len > 6) {
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SE;
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, opt_reply, len);
+ printsub('>', &opt_reply[2], len - 2);
+ }
+/*@*/ else printf("slc_end_reply: not enough room\n");
+ }
+ if (opt_reply) {
+ free(opt_reply);
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ }
+}
+
+
+
+int
+telrcv(void)
+{
+ int c;
+ int scc;
+ unsigned char *sbp = NULL;
+ int count;
+ int returnValue = 0;
+
+ scc = 0;
+ count = 0;
+ while (TTYROOM() > 2) {
+ if (scc == 0) {
+ if (count) {
+ ring_consumed(&netiring, count);
+ returnValue = 1;
+ count = 0;
+ }
+ sbp = netiring.consume;
+ scc = ring_full_consecutive(&netiring);
+ if (scc == 0) {
+ /* No more data coming in */
+ break;
+ }
+ }
+
+ c = *sbp++ & 0xff, scc--; count++;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
+
+ switch (telrcv_state) {
+
+ case TS_CR:
+ telrcv_state = TS_DATA;
+ if (c == '\0') {
+ break; /* Ignore \0 after CR */
+ }
+ else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
+ TTYADD(c);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case TS_DATA:
+ if (c == IAC && telnetport >= 0) {
+ telrcv_state = TS_IAC;
+ break;
+ }
+ /*
+ * The 'crmod' hack (see following) is needed
+ * since we can't * set CRMOD on output only.
+ * Machines like MULTICS like to send \r without
+ * \n; since we must turn off CRMOD to get proper
+ * input, the mapping is done here (sigh).
+ */
+ if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
+ if (scc > 0) {
+ c = *sbp&0xff;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
+ if (c == 0) {
+ sbp++, scc--; count++;
+ /* a "true" CR */
+ TTYADD('\r');
+ } else if (my_want_state_is_dont(TELOPT_ECHO) &&
+ (c == '\n')) {
+ sbp++, scc--; count++;
+ TTYADD('\n');
+ } else {
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ (*decrypt_input)(-1);
+#endif /* ENCRYPTION */
+
+ TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
+ }
+ } else {
+ telrcv_state = TS_CR;
+ TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
+ }
+ } else {
+ TTYADD(c);
+ }
+ continue;
+
+ case TS_IAC:
+process_iac:
+ switch (c) {
+
+ case WILL:
+ telrcv_state = TS_WILL;
+ continue;
+
+ case WONT:
+ telrcv_state = TS_WONT;
+ continue;
+
+ case DO:
+ telrcv_state = TS_DO;
+ continue;
+
+ case DONT:
+ telrcv_state = TS_DONT;
+ continue;
+
+ case DM:
+ /*
+ * We may have missed an urgent notification,
+ * so make sure we flush whatever is in the
+ * buffer currently.
+ */
+ printoption("RCVD", IAC, DM);
+ SYNCHing = 1;
+ (void) ttyflush(1);
+ SYNCHing = stilloob();
+ settimer(gotDM);
+ break;
+
+ case SB:
+ SB_CLEAR();
+ telrcv_state = TS_SB;
+ continue;
+
+ case IAC:
+ TTYADD(IAC);
+ break;
+
+ case NOP:
+ case GA:
+ default:
+ printoption("RCVD", IAC, c);
+ break;
+ }
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_WILL:
+ printoption("RCVD", WILL, c);
+ willoption(c);
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_WONT:
+ printoption("RCVD", WONT, c);
+ wontoption(c);
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_DO:
+ printoption("RCVD", DO, c);
+ dooption(c);
+ if (c == TELOPT_NAWS) {
+ sendnaws();
+ } else if (c == TELOPT_LFLOW) {
+ localflow = 1;
+ setcommandmode();
+ setconnmode(0);
+ }
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_DONT:
+ printoption("RCVD", DONT, c);
+ dontoption(c);
+ flushline = 1;
+ setconnmode(0); /* set new tty mode (maybe) */
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_SB:
+ if (c == IAC) {
+ telrcv_state = TS_SE;
+ } else {
+ SB_ACCUM(c);
+ }
+ continue;
+
+ case TS_SE:
+ if (c != SE) {
+ if (c != IAC) {
+ /*
+ * This is an error. We only expect to get
+ * "IAC IAC" or "IAC SE". Several things may
+ * have happend. An IAC was not doubled, the
+ * IAC SE was left off, or another option got
+ * inserted into the suboption are all possibilities.
+ * If we assume that the IAC was not doubled,
+ * and really the IAC SE was left off, we could
+ * get into an infinate loop here. So, instead,
+ * we terminate the suboption, and process the
+ * partial suboption if we can.
+ */
+ SB_ACCUM(IAC);
+ SB_ACCUM(c);
+ subpointer -= 2;
+ SB_TERM();
+
+ printoption("In SUBOPTION processing, RCVD", IAC, c);
+ suboption(); /* handle sub-option */
+ telrcv_state = TS_IAC;
+ goto process_iac;
+ }
+ SB_ACCUM(c);
+ telrcv_state = TS_SB;
+ } else {
+ SB_ACCUM(IAC);
+ SB_ACCUM(SE);
+ subpointer -= 2;
+ SB_TERM();
+ suboption(); /* handle sub-option */
+ telrcv_state = TS_DATA;
+ }
+ }
+ }
+ if (count)
+ ring_consumed(&netiring, count);
+ return returnValue||count;
+}
+
+static int bol = 1, local = 0;
+
+int
+rlogin_susp(void)
+{
+ if (local) {
+ local = 0;
+ bol = 1;
+ command(0, "z\n", 2);
+ return(1);
+ }
+ return(0);
+}
+
+static int
+telsnd(void)
+{
+ int tcc;
+ int count;
+ int returnValue = 0;
+ unsigned char *tbp = NULL;
+
+ tcc = 0;
+ count = 0;
+ while (NETROOM() > 2) {
+ int sc;
+ int c;
+
+ if (tcc == 0) {
+ if (count) {
+ ring_consumed(&ttyiring, count);
+ returnValue = 1;
+ count = 0;
+ }
+ tbp = ttyiring.consume;
+ tcc = ring_full_consecutive(&ttyiring);
+ if (tcc == 0) {
+ break;
+ }
+ }
+ c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
+ if (rlogin != _POSIX_VDISABLE) {
+ if (bol) {
+ bol = 0;
+ if (sc == rlogin) {
+ local = 1;
+ continue;
+ }
+ } else if (local) {
+ local = 0;
+ if (sc == '.' || c == termEofChar) {
+ bol = 1;
+ command(0, "close\n", 6);
+ continue;
+ }
+ if (sc == termSuspChar) {
+ bol = 1;
+ command(0, "z\n", 2);
+ continue;
+ }
+ if (sc == escape) {
+ command(0, (const char *)tbp, tcc);
+ bol = 1;
+ count += tcc;
+ tcc = 0;
+ flushline = 1;
+ break;
+ }
+ if (sc != rlogin) {
+ ++tcc;
+ --tbp;
+ --count;
+ c = sc = rlogin;
+ }
+ }
+ if ((sc == '\n') || (sc == '\r'))
+ bol = 1;
+ } else if (escape != _POSIX_VDISABLE && sc == escape) {
+ /*
+ * Double escape is a pass through of a single escape character.
+ */
+ if (tcc && strip(*tbp) == escape) {
+ tbp++;
+ tcc--;
+ count++;
+ bol = 0;
+ } else {
+ command(0, (char *)tbp, tcc);
+ bol = 1;
+ count += tcc;
+ tcc = 0;
+ flushline = 1;
+ break;
+ }
+ } else
+ bol = 0;
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
+ if (tcc > 0 && strip(*tbp) == echoc) {
+ tcc--; tbp++; count++;
+ } else {
+ dontlecho = !dontlecho;
+ settimer(echotoggle);
+ setconnmode(0);
+ flushline = 1;
+ break;
+ }
+ }
+#endif
+ if (MODE_LOCAL_CHARS(globalmode)) {
+ if (TerminalSpecialChars(sc) == 0) {
+ bol = 1;
+ break;
+ }
+ }
+ if (my_want_state_is_wont(TELOPT_BINARY)) {
+ switch (c) {
+ case '\n':
+ /*
+ * If we are in CRMOD mode (\r ==> \n)
+ * on our local machine, then probably
+ * a newline (unix) is CRLF (TELNET).
+ */
+ if (MODE_LOCAL_CHARS(globalmode)) {
+ NETADD('\r');
+ }
+ NETADD('\n');
+ bol = flushline = 1;
+ break;
+ case '\r':
+ if (!crlf) {
+ NET2ADD('\r', '\0');
+ } else {
+ NET2ADD('\r', '\n');
+ }
+ bol = flushline = 1;
+ break;
+ case IAC:
+ NET2ADD(IAC, IAC);
+ break;
+ default:
+ NETADD(c);
+ break;
+ }
+ } else if (c == IAC) {
+ NET2ADD(IAC, IAC);
+ } else {
+ NETADD(c);
+ }
+ }
+ if (count)
+ ring_consumed(&ttyiring, count);
+ return returnValue||count; /* Non-zero if we did anything */
+}
+
+/*
+ * Scheduler()
+ *
+ * Try to do something.
+ *
+ * If we do something useful, return 1; else return 0.
+ *
+ */
+
+static int
+Scheduler(int block)
+{
+ /* One wants to be a bit careful about setting returnValue
+ * to one, since a one implies we did some useful work,
+ * and therefore probably won't be called to block next
+ */
+ int returnValue;
+ int netin, netout, netex, ttyin, ttyout;
+
+ /* Decide which rings should be processed */
+
+ netout = ring_full_count(&netoring) &&
+ (flushline ||
+ (my_want_state_is_wont(TELOPT_LINEMODE)
+#ifdef KLUDGELINEMODE
+ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
+#endif
+ ) ||
+ my_want_state_is_will(TELOPT_BINARY));
+ ttyout = ring_full_count(&ttyoring);
+
+ ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
+
+ netin = !ISend && ring_empty_count(&netiring);
+
+ netex = !SYNCHing;
+
+ /* Call to system code to process rings */
+
+ returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
+
+ /* Now, look at the input rings, looking for work to do. */
+
+ if (ring_full_count(&ttyiring)) {
+ returnValue |= telsnd();
+ }
+
+ if (ring_full_count(&netiring)) {
+ returnValue |= telrcv();
+ }
+ return returnValue;
+}
+
+#ifdef AUTHENTICATION
+#define __unusedhere
+#else
+#define __unusedhere __unused
+#endif
+/*
+ * Select from tty and network...
+ */
+void
+telnet(char *user __unusedhere)
+{
+ sys_telnet_init();
+
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ {
+ static char local_host[256] = { 0 };
+
+ if (!local_host[0]) {
+ gethostname(local_host, sizeof(local_host));
+ local_host[sizeof(local_host)-1] = 0;
+ }
+ auth_encrypt_init(local_host, hostname, "TELNET", 0);
+ auth_encrypt_user(user);
+ }
+#endif
+#endif
+ if (telnetport > 0) {
+#ifdef AUTHENTICATION
+ if (autologin)
+ send_will(TELOPT_AUTHENTICATION, 1);
+#endif
+#ifdef ENCRYPTION
+ send_do(TELOPT_ENCRYPT, 1);
+ send_will(TELOPT_ENCRYPT, 1);
+#endif /* ENCRYPTION */
+ send_do(TELOPT_SGA, 1);
+ send_will(TELOPT_TTYPE, 1);
+ send_will(TELOPT_NAWS, 1);
+ send_will(TELOPT_TSPEED, 1);
+ send_will(TELOPT_LFLOW, 1);
+ send_will(TELOPT_LINEMODE, 1);
+ send_will(TELOPT_NEW_ENVIRON, 1);
+ send_do(TELOPT_STATUS, 1);
+ if (env_getvalue((const unsigned char *)"DISPLAY"))
+ send_will(TELOPT_XDISPLOC, 1);
+ if (eight)
+ tel_enter_binary(eight);
+ }
+
+ for (;;) {
+ int schedValue;
+
+ while ((schedValue = Scheduler(0)) != 0) {
+ if (schedValue == -1) {
+ setcommandmode();
+ return;
+ }
+ }
+
+ if (Scheduler(1) == -1) {
+ setcommandmode();
+ return;
+ }
+ }
+}
+
+#if 0 /* XXX - this not being in is a bug */
+/*
+ * nextitem()
+ *
+ * Return the address of the next "item" in the TELNET data
+ * stream. This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
+
+static char *
+nextitem(char *current)
+{
+ if ((*current&0xff) != IAC) {
+ return current+1;
+ }
+ switch (*(current+1)&0xff) {
+ case DO:
+ case DONT:
+ case WILL:
+ case WONT:
+ return current+3;
+ case SB: /* loop forever looking for the SE */
+ {
+ char *look = current+2;
+
+ for (;;) {
+ if ((*look++&0xff) == IAC) {
+ if ((*look++&0xff) == SE) {
+ return look;
+ }
+ }
+ }
+ }
+ default:
+ return current+2;
+ }
+}
+#endif /* 0 */
+
+/*
+ * netclear()
+ *
+ * We are about to do a TELNET SYNCH operation. Clear
+ * the path to the network.
+ *
+ * Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ * A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer. The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
+ */
+
+static void
+netclear(void)
+{
+ /* Deleted */
+}
+
+/*
+ * These routines add various telnet commands to the data stream.
+ */
+
+static void
+doflush(void)
+{
+ NET2ADD(IAC, DO);
+ NETADD(TELOPT_TM);
+ flushline = 1;
+ flushout = 1;
+ (void) ttyflush(1); /* Flush/drop output */
+ /* do printoption AFTER flush, otherwise the output gets tossed... */
+ printoption("SENT", DO, TELOPT_TM);
+}
+
+void
+xmitAO(void)
+{
+ NET2ADD(IAC, AO);
+ printoption("SENT", IAC, AO);
+ if (autoflush) {
+ doflush();
+ }
+}
+
+void
+xmitEL(void)
+{
+ NET2ADD(IAC, EL);
+ printoption("SENT", IAC, EL);
+}
+
+void
+xmitEC(void)
+{
+ NET2ADD(IAC, EC);
+ printoption("SENT", IAC, EC);
+}
+
+int
+dosynch(char *ch __unused)
+{
+ netclear(); /* clear the path to the network */
+ NETADD(IAC);
+ setneturg();
+ NETADD(DM);
+ printoption("SENT", IAC, DM);
+ return 1;
+}
+
+int want_status_response = 0;
+
+int
+get_status(char *ch __unused)
+{
+ unsigned char tmp[16];
+ unsigned char *cp;
+
+ if (my_want_state_is_dont(TELOPT_STATUS)) {
+ printf("Remote side does not support STATUS option\n");
+ return 0;
+ }
+ cp = tmp;
+
+ *cp++ = IAC;
+ *cp++ = SB;
+ *cp++ = TELOPT_STATUS;
+ *cp++ = TELQUAL_SEND;
+ *cp++ = IAC;
+ *cp++ = SE;
+ if (NETROOM() >= cp - tmp) {
+ ring_supply_data(&netoring, tmp, cp-tmp);
+ printsub('>', tmp+2, cp - tmp - 2);
+ }
+ ++want_status_response;
+ return 1;
+}
+
+void
+intp(void)
+{
+ NET2ADD(IAC, IP);
+ printoption("SENT", IAC, IP);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendbrk(void)
+{
+ NET2ADD(IAC, BREAK);
+ printoption("SENT", IAC, BREAK);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendabort(void)
+{
+ NET2ADD(IAC, ABORT);
+ printoption("SENT", IAC, ABORT);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendsusp(void)
+{
+ NET2ADD(IAC, SUSP);
+ printoption("SENT", IAC, SUSP);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendeof(void)
+{
+ NET2ADD(IAC, xEOF);
+ printoption("SENT", IAC, xEOF);
+}
+
+void
+sendayt(void)
+{
+ NET2ADD(IAC, AYT);
+ printoption("SENT", IAC, AYT);
+}
+
+/*
+ * Send a window size update to the remote system.
+ */
+
+void
+sendnaws(void)
+{
+ long rows, cols;
+ unsigned char tmp[16];
+ unsigned char *cp;
+
+ if (my_state_is_wont(TELOPT_NAWS))
+ return;
+
+#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
+ if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
+
+ if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
+ return;
+ }
+
+ cp = tmp;
+
+ *cp++ = IAC;
+ *cp++ = SB;
+ *cp++ = TELOPT_NAWS;
+ PUTSHORT(cp, cols);
+ PUTSHORT(cp, rows);
+ *cp++ = IAC;
+ *cp++ = SE;
+ if (NETROOM() >= cp - tmp) {
+ ring_supply_data(&netoring, tmp, cp-tmp);
+ printsub('>', tmp+2, cp - tmp - 2);
+ }
+}
+
+void
+tel_enter_binary(int rw)
+{
+ if (rw&1)
+ send_do(TELOPT_BINARY, 1);
+ if (rw&2)
+ send_will(TELOPT_BINARY, 1);
+}
+
+void
+tel_leave_binary(int rw)
+{
+ if (rw&1)
+ send_dont(TELOPT_BINARY, 1);
+ if (rw&2)
+ send_wont(TELOPT_BINARY, 1);
+}
diff --git a/remote_cmds/telnet.tproj/terminal.c b/remote_cmds/telnet.tproj/terminal.c
new file mode 100644
index 0000000..96edc35
--- /dev/null
+++ b/remote_cmds/telnet.tproj/terminal.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/terminal.c,v 1.7 2003/05/04 02:54:48 obrien Exp $");
+
+#include <arpa/telnet.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+#include "ring.h"
+
+#include "externs.h"
+#include "types.h"
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+Ring ttyoring, ttyiring;
+unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ];
+
+int termdata; /* Debugging flag */
+
+#ifdef USE_TERMIO
+# ifndef VDISCARD
+cc_t termFlushChar;
+# endif
+# ifndef VLNEXT
+cc_t termLiteralNextChar;
+# endif
+# ifndef VSUSP
+cc_t termSuspChar;
+# endif
+# ifndef VWERASE
+cc_t termWerasChar;
+# endif
+# ifndef VREPRINT
+cc_t termRprntChar;
+# endif
+# ifndef VSTART
+cc_t termStartChar;
+# endif
+# ifndef VSTOP
+cc_t termStopChar;
+# endif
+# ifndef VEOL
+cc_t termForw1Char;
+# endif
+# ifndef VEOL2
+cc_t termForw2Char;
+# endif
+# ifndef VSTATUS
+cc_t termAytChar;
+# endif
+#else
+cc_t termForw2Char;
+cc_t termAytChar;
+#endif
+
+/*
+ * initialize the terminal data structures.
+ */
+
+void
+init_terminal(void)
+{
+ if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) {
+ exit(1);
+ }
+ if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) {
+ exit(1);
+ }
+ autoflush = TerminalAutoFlush();
+}
+
+/*
+ * Send as much data as possible to the terminal.
+ *
+ * Return value:
+ * -1: No useful work done, data waiting to go out.
+ * 0: No data was waiting, so nothing was done.
+ * 1: All waiting data was written out.
+ * n: All data - n was written out.
+ */
+
+int
+ttyflush(int drop)
+{
+ int n, n0, n1;
+
+ n0 = ring_full_count(&ttyoring);
+ if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) {
+ if (drop) {
+ TerminalFlushOutput();
+ /* we leave 'n' alone! */
+ } else {
+ n = TerminalWrite((char *)ttyoring.consume, n);
+ }
+ }
+ if (n > 0) {
+ if (termdata && n) {
+ Dump('>', ttyoring.consume, n);
+ }
+ /*
+ * If we wrote everything, and the full count is
+ * larger than what we wrote, then write the
+ * rest of the buffer.
+ */
+ if (n1 == n && n0 > n) {
+ n1 = n0 - n;
+ if (!drop)
+ n1 = TerminalWrite((char *)ttyoring.bottom, n1);
+ if (n1 > 0)
+ n += n1;
+ }
+ ring_consumed(&ttyoring, n);
+ }
+ if (n < 0)
+ return -1;
+ if (n == n0) {
+ if (n0)
+ return -1;
+ return 0;
+ }
+ return n0 - n + 1;
+}
+
+
+/*
+ * These routines decides on what the mode should be (based on the values
+ * of various global variables).
+ */
+
+
+int
+getconnmode(void)
+{
+ extern int linemode;
+ int mode = 0;
+#ifdef KLUDGELINEMODE
+ extern int kludgelinemode;
+#endif
+
+ if (my_want_state_is_dont(TELOPT_ECHO))
+ mode |= MODE_ECHO;
+
+ if (localflow)
+ mode |= MODE_FLOW;
+
+ if (my_want_state_is_will(TELOPT_BINARY))
+ mode |= MODE_INBIN;
+
+ if (his_want_state_is_will(TELOPT_BINARY))
+ mode |= MODE_OUTBIN;
+
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode) {
+ if (my_want_state_is_dont(TELOPT_SGA)) {
+ mode |= (MODE_TRAPSIG|MODE_EDIT);
+ if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
+ mode &= ~MODE_ECHO;
+ }
+ }
+ return(mode);
+ }
+#endif
+ if (my_want_state_is_will(TELOPT_LINEMODE))
+ mode |= linemode;
+ return(mode);
+}
+
+void
+setconnmode(int force)
+{
+#ifdef ENCRYPTION
+ static int enc_passwd = 0;
+#endif /* ENCRYPTION */
+ int newmode;
+
+ newmode = getconnmode()|(force?MODE_FORCE:0);
+
+ TerminalNewMode(newmode);
+
+#ifdef ENCRYPTION
+ if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) {
+ if (my_want_state_is_will(TELOPT_ENCRYPT)
+ && (enc_passwd == 0) && !encrypt_output) {
+ encrypt_request_start(0, 0);
+ enc_passwd = 1;
+ }
+ } else {
+ if (enc_passwd) {
+ encrypt_request_end();
+ enc_passwd = 0;
+ }
+ }
+#endif /* ENCRYPTION */
+
+}
+
+void
+setcommandmode(void)
+{
+ TerminalNewMode(-1);
+}
diff --git a/remote_cmds/telnet.tproj/tn3270.c b/remote_cmds/telnet.tproj/tn3270.c
new file mode 100644
index 0000000..c2bbd8f
--- /dev/null
+++ b/remote_cmds/telnet.tproj/tn3270.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <arpa/telnet.h>
+
+#include "general.h"
+
+#include "defines.h"
+#include "ring.h"
+#include "externs.h"
+#include "fdset.h"
+
+#if defined(TN3270)
+
+#include "../ctlr/screen.h"
+#include "../general/globals.h"
+
+#include "../sys_curses/telextrn.h"
+#include "../ctlr/externs.h"
+
+#if defined(unix) || defined(__APPLE__)
+int
+ HaveInput, /* There is input available to scan */
+ cursesdata, /* Do we dump curses data? */
+ sigiocount; /* Number of times we got a SIGIO */
+
+char tline[200];
+char *transcom = 0; /* transparent mode command (default: none) */
+#endif /* defined(unix) || defined(__APPLE__) */
+
+char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
+
+static char sb_terminal[] = { IAC, SB,
+ TELOPT_TTYPE, TELQUAL_IS,
+ 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
+ IAC, SE };
+#define SBTERMMODEL 13
+
+static int
+ Sent3270TerminalType; /* Have we said we are a 3270? */
+
+#endif /* defined(TN3270) */
+
+
+ void
+init_3270()
+{
+#if defined(TN3270)
+#if defined(unix) || defined(__APPLE__)
+ HaveInput = 0;
+ sigiocount = 0;
+#endif /* defined(unix) || defined(__APPLE__) */
+ Sent3270TerminalType = 0;
+ Ifrontp = Ibackp = Ibuf;
+ init_ctlr(); /* Initialize some things */
+ init_keyboard();
+ init_screen();
+ init_system();
+#endif /* defined(TN3270) */
+}
+
+
+#if defined(TN3270)
+
+/*
+ * DataToNetwork - queue up some data to go to network. If "done" is set,
+ * then when last byte is queued, we add on an IAC EOR sequence (so,
+ * don't call us with "done" until you want that done...)
+ *
+ * We actually do send all the data to the network buffer, since our
+ * only client needs for us to do that.
+ */
+
+ int
+DataToNetwork(buffer, count, done)
+ register char *buffer; /* where the data is */
+ register int count; /* how much to send */
+ int done; /* is this the last of a logical block */
+{
+ register int loop, c;
+ int origCount;
+
+ origCount = count;
+
+ while (count) {
+ /* If not enough room for EORs, IACs, etc., wait */
+ if (NETROOM() < 6) {
+ fd_set o;
+
+ FD_ZERO(&o);
+ netflush();
+ while (NETROOM() < 6) {
+ FD_SET(net, &o);
+ (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0);
+ netflush();
+ }
+ }
+ c = ring_empty_count(&netoring);
+ if (c > count) {
+ c = count;
+ }
+ loop = c;
+ while (loop) {
+ if (((unsigned char)*buffer) == IAC) {
+ break;
+ }
+ buffer++;
+ loop--;
+ }
+ if ((c = c-loop)) {
+ ring_supply_data(&netoring, buffer-c, c);
+ count -= c;
+ }
+ if (loop) {
+ NET2ADD(IAC, IAC);
+ count--;
+ buffer++;
+ }
+ }
+
+ if (done) {
+ NET2ADD(IAC, EOR);
+ netflush(); /* try to move along as quickly as ... */
+ }
+ return(origCount - count);
+}
+
+
+#if defined(unix) || defined(__APPLE__)
+ void
+inputAvailable(signo)
+ int signo;
+{
+ HaveInput = 1;
+ sigiocount++;
+}
+#endif /* defined(unix) || defined(__APPLE__) */
+
+ void
+outputPurge()
+{
+ (void) ttyflush(1);
+}
+
+
+/*
+ * The following routines are places where the various tn3270
+ * routines make calls into telnet.c.
+ */
+
+/*
+ * DataToTerminal - queue up some data to go to terminal.
+ *
+ * Note: there are people who call us and depend on our processing
+ * *all* the data at one time (thus the select).
+ */
+
+ int
+DataToTerminal(buffer, count)
+ register char *buffer; /* where the data is */
+ register int count; /* how much to send */
+{
+ register int c;
+ int origCount;
+
+ origCount = count;
+
+ while (count) {
+ if (TTYROOM() == 0) {
+#if defined(unix) || defined(__APPLE__)
+ fd_set o;
+
+ FD_ZERO(&o);
+#endif /* defined(unix) || defined(__APPLE__) */
+ (void) ttyflush(0);
+ while (TTYROOM() == 0) {
+#if defined(unix) || defined(__APPLE__)
+ FD_SET(tout, &o);
+ (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0);
+#endif /* defined(unix) || defined(__APPLE__) */
+ (void) ttyflush(0);
+ }
+ }
+ c = TTYROOM();
+ if (c > count) {
+ c = count;
+ }
+ ring_supply_data(&ttyoring, buffer, c);
+ count -= c;
+ buffer += c;
+ }
+ return(origCount);
+}
+
+
+/*
+ * Push3270 - Try to send data along the 3270 output (to screen) direction.
+ */
+
+ int
+Push3270()
+{
+ int save = ring_full_count(&netiring);
+
+ if (save) {
+ if (Ifrontp+save > Ibuf+sizeof Ibuf) {
+ if (Ibackp != Ibuf) {
+ memmove(Ibuf, Ibackp, Ifrontp-Ibackp);
+ Ifrontp -= (Ibackp-Ibuf);
+ Ibackp = Ibuf;
+ }
+ }
+ if (Ifrontp+save < Ibuf+sizeof Ibuf) {
+ (void)telrcv();
+ }
+ }
+ return save != ring_full_count(&netiring);
+}
+
+
+/*
+ * Finish3270 - get the last dregs of 3270 data out to the terminal
+ * before quitting.
+ */
+
+ void
+Finish3270()
+{
+ while (Push3270() || !DoTerminalOutput()) {
+#if defined(unix) || defined(__APPLE__)
+ HaveInput = 0;
+#endif /* defined(unix) || defined(__APPLE__) */
+ ;
+ }
+}
+
+
+/* StringToTerminal - output a null terminated string to the terminal */
+
+ void
+StringToTerminal(s)
+ char *s;
+{
+ int count;
+
+ count = strlen(s);
+ if (count) {
+ (void) DataToTerminal(s, count); /* we know it always goes... */
+ }
+}
+
+
+#if ((!defined(NOT43)) || defined(PUTCHAR))
+/* _putchar - output a single character to the terminal. This name is so that
+ * curses(3x) can call us to send out data.
+ */
+
+ void
+_putchar(c)
+ char c;
+{
+#if defined(sun) /* SunOS 4.0 bug */
+ c &= 0x7f;
+#endif /* defined(sun) */
+ if (cursesdata) {
+ Dump('>', &c, 1);
+ }
+ if (!TTYROOM()) {
+ (void) DataToTerminal(&c, 1);
+ } else {
+ TTYADD(c);
+ }
+}
+#endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */
+
+ void
+SetIn3270()
+{
+ if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
+ && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
+ if (!In3270) {
+ In3270 = 1;
+ Init3270(); /* Initialize 3270 functions */
+ /* initialize terminal key mapping */
+ InitTerminal(); /* Start terminal going */
+ setconnmode(0);
+ }
+ } else {
+ if (In3270) {
+ StopScreen(1);
+ In3270 = 0;
+ Stop3270(); /* Tell 3270 we aren't here anymore */
+ setconnmode(0);
+ }
+ }
+}
+
+/*
+ * tn3270_ttype()
+ *
+ * Send a response to a terminal type negotiation.
+ *
+ * Return '0' if no more responses to send; '1' if a response sent.
+ */
+
+ int
+tn3270_ttype()
+{
+ /*
+ * Try to send a 3270 type terminal name. Decide which one based
+ * on the format of our screen, and (in the future) color
+ * capaiblities.
+ */
+ InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */
+ if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
+ Sent3270TerminalType = 1;
+ if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
+ MaxNumberLines = 27;
+ MaxNumberColumns = 132;
+ sb_terminal[SBTERMMODEL] = '5';
+ } else if (MaxNumberLines >= 43) {
+ MaxNumberLines = 43;
+ MaxNumberColumns = 80;
+ sb_terminal[SBTERMMODEL] = '4';
+ } else if (MaxNumberLines >= 32) {
+ MaxNumberLines = 32;
+ MaxNumberColumns = 80;
+ sb_terminal[SBTERMMODEL] = '3';
+ } else {
+ MaxNumberLines = 24;
+ MaxNumberColumns = 80;
+ sb_terminal[SBTERMMODEL] = '2';
+ }
+ NumberLines = 24; /* before we start out... */
+ NumberColumns = 80;
+ ScreenSize = NumberLines*NumberColumns;
+ if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
+ ExitString("Programming error: MAXSCREENSIZE too small.\n",
+ 1);
+ /*NOTREACHED*/
+ }
+ printsub('>', sb_terminal+2, sizeof sb_terminal-2);
+ ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#if defined(unix) || defined(__APPLE__)
+ int
+settranscom(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+
+ if (argc == 1 && transcom) {
+ transcom = 0;
+ }
+ if (argc == 1) {
+ return 1;
+ }
+ transcom = tline;
+ (void) strcpy(transcom, argv[1]);
+ for (i = 2; i < argc; ++i) {
+ (void) strcat(transcom, " ");
+ (void) strcat(transcom, argv[i]);
+ }
+ return 1;
+}
+#endif /* defined(unix) || defined(__APPLE__) */
+
+#endif /* defined(TN3270) */
diff --git a/remote_cmds/telnet.tproj/types.h b/remote_cmds/telnet.tproj/types.h
new file mode 100644
index 0000000..191d311
--- /dev/null
+++ b/remote_cmds/telnet.tproj/types.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)types.h 8.1 (Berkeley) 6/6/93
+ */
+
+typedef struct {
+ char *modedescriptions;
+ char modetype;
+} Modelist;
+
+extern Modelist modelist[];
+
+typedef struct {
+ int
+ system, /* what the current time is */
+ echotoggle, /* last time user entered echo character */
+ modenegotiated, /* last time operating mode negotiated */
+ didnetreceive, /* last time we read data from network */
+ gotDM; /* when did we last see a data mark */
+} Clocks;
+
+extern Clocks clocks;
diff --git a/remote_cmds/telnet.tproj/utilities.c b/remote_cmds/telnet.tproj/utilities.c
new file mode 100644
index 0000000..418c982
--- /dev/null
+++ b/remote_cmds/telnet.tproj/utilities.c
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/utilities.c,v 1.8 2003/05/04 02:54:48 obrien Exp $");
+
+#define TELOPTS
+#define TELCMDS
+#define SLC_NAMES
+#include <arpa/telnet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "general.h"
+
+#include "fdset.h"
+
+#include "ring.h"
+
+#include "defines.h"
+
+#include "externs.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+FILE *NetTrace = 0; /* Not in bss, since needs to stay */
+int prettydump;
+
+/*
+ * upcase()
+ *
+ * Upcase (in place) the argument.
+ */
+
+void
+upcase(char *argument)
+{
+ int c;
+
+ while ((c = *argument) != 0) {
+ if (islower(c)) {
+ *argument = toupper(c);
+ }
+ argument++;
+ }
+}
+
+/*
+ * SetSockOpt()
+ *
+ * Compensate for differences in 4.2 and 4.3 systems.
+ */
+
+int
+SetSockOpt(int fd, int level, int option, int yesno)
+{
+ return setsockopt(fd, level, option,
+ (char *)&yesno, sizeof yesno);
+}
+
+/*
+ * The following are routines used to print out debugging information.
+ */
+
+unsigned char NetTraceFile[256] = "(standard output)";
+
+void
+SetNetTrace(char *file)
+{
+ if (NetTrace && NetTrace != stdout)
+ fclose(NetTrace);
+ if (file && (strcmp(file, "-") != 0)) {
+ NetTrace = fopen(file, "w");
+ if (NetTrace) {
+ strcpy((char *)NetTraceFile, file);
+ return;
+ }
+ fprintf(stderr, "Cannot open %s.\n", file);
+ }
+ NetTrace = stdout;
+ strcpy((char *)NetTraceFile, "(standard output)");
+}
+
+void
+Dump(char direction, unsigned char *buffer, int length)
+{
+# define BYTES_PER_LINE 32
+# define min(x,y) ((x<y)? x:y)
+ unsigned char *pThis;
+ int offset;
+
+ offset = 0;
+
+ while (length) {
+ /* print one line */
+ fprintf(NetTrace, "%c 0x%x\t", direction, offset);
+ pThis = buffer;
+ if (prettydump) {
+ buffer = buffer + min(length, BYTES_PER_LINE/2);
+ while (pThis < buffer) {
+ fprintf(NetTrace, "%c%.2x",
+ (((*pThis)&0xff) == 0xff) ? '*' : ' ',
+ (*pThis)&0xff);
+ pThis++;
+ }
+ length -= BYTES_PER_LINE/2;
+ offset += BYTES_PER_LINE/2;
+ } else {
+ buffer = buffer + min(length, BYTES_PER_LINE);
+ while (pThis < buffer) {
+ fprintf(NetTrace, "%.2x", (*pThis)&0xff);
+ pThis++;
+ }
+ length -= BYTES_PER_LINE;
+ offset += BYTES_PER_LINE;
+ }
+ if (NetTrace == stdout) {
+ fprintf(NetTrace, "\r\n");
+ } else {
+ fprintf(NetTrace, "\n");
+ }
+ if (length < 0) {
+ fflush(NetTrace);
+ return;
+ }
+ /* find next unique line */
+ }
+ fflush(NetTrace);
+}
+
+
+void
+printoption(const char *direction, int cmd, int option)
+{
+ if (!showoptions)
+ return;
+ if (cmd == IAC) {
+ if (TELCMD_OK(option))
+ fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
+ else
+ fprintf(NetTrace, "%s IAC %d", direction, option);
+ } else {
+ const char *fmt;
+ fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
+ (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
+ if (fmt) {
+ fprintf(NetTrace, "%s %s ", direction, fmt);
+ if (TELOPT_OK(option))
+ fprintf(NetTrace, "%s", TELOPT(option));
+ else if (option == TELOPT_EXOPL)
+ fprintf(NetTrace, "EXOPL");
+ else
+ fprintf(NetTrace, "%d", option);
+ } else
+ fprintf(NetTrace, "%s %d %d", direction, cmd, option);
+ }
+ if (NetTrace == stdout) {
+ fprintf(NetTrace, "\r\n");
+ fflush(NetTrace);
+ } else {
+ fprintf(NetTrace, "\n");
+ }
+ return;
+}
+
+void
+optionstatus(void)
+{
+ int i;
+ extern char will_wont_resp[], do_dont_resp[];
+
+ for (i = 0; i < 256; i++) {
+ if (do_dont_resp[i]) {
+ if (TELOPT_OK(i))
+ printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
+ else if (TELCMD_OK(i))
+ printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
+ else
+ printf("resp DO_DONT %d: %d\n", i,
+ do_dont_resp[i]);
+ if (my_want_state_is_do(i)) {
+ if (TELOPT_OK(i))
+ printf("want DO %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want DO %s\n", TELCMD(i));
+ else
+ printf("want DO %d\n", i);
+ } else {
+ if (TELOPT_OK(i))
+ printf("want DONT %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want DONT %s\n", TELCMD(i));
+ else
+ printf("want DONT %d\n", i);
+ }
+ } else {
+ if (my_state_is_do(i)) {
+ if (TELOPT_OK(i))
+ printf(" DO %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf(" DO %s\n", TELCMD(i));
+ else
+ printf(" DO %d\n", i);
+ }
+ }
+ if (will_wont_resp[i]) {
+ if (TELOPT_OK(i))
+ printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
+ else if (TELCMD_OK(i))
+ printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
+ else
+ printf("resp WILL_WONT %d: %d\n",
+ i, will_wont_resp[i]);
+ if (my_want_state_is_will(i)) {
+ if (TELOPT_OK(i))
+ printf("want WILL %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want WILL %s\n", TELCMD(i));
+ else
+ printf("want WILL %d\n", i);
+ } else {
+ if (TELOPT_OK(i))
+ printf("want WONT %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want WONT %s\n", TELCMD(i));
+ else
+ printf("want WONT %d\n", i);
+ }
+ } else {
+ if (my_state_is_will(i)) {
+ if (TELOPT_OK(i))
+ printf(" WILL %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf(" WILL %s\n", TELCMD(i));
+ else
+ printf(" WILL %d\n", i);
+ }
+ }
+ }
+
+}
+
+void
+printsub(char direction, unsigned char *pointer, int length)
+{
+ int i;
+#ifdef AUTHENTICATION
+ char buf[512];
+#endif
+ extern int want_status_response;
+
+ if (showoptions || direction == 0 ||
+ (want_status_response && (pointer[0] == TELOPT_STATUS))) {
+ if (direction) {
+ fprintf(NetTrace, "%s IAC SB ",
+ (direction == '<')? "RCVD":"SENT");
+ if (length >= 3) {
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if (i != IAC || j != SE) {
+ fprintf(NetTrace, "(terminated by ");
+ if (TELOPT_OK(i))
+ fprintf(NetTrace, "%s ", TELOPT(i));
+ else if (TELCMD_OK(i))
+ fprintf(NetTrace, "%s ", TELCMD(i));
+ else
+ fprintf(NetTrace, "%d ", i);
+ if (TELOPT_OK(j))
+ fprintf(NetTrace, "%s", TELOPT(j));
+ else if (TELCMD_OK(j))
+ fprintf(NetTrace, "%s", TELCMD(j));
+ else
+ fprintf(NetTrace, "%d", j);
+ fprintf(NetTrace, ", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if (length < 1) {
+ fprintf(NetTrace, "(Empty suboption??\?)");
+ if (NetTrace == stdout)
+ fflush(NetTrace);
+ return;
+ }
+ switch (pointer[0]) {
+ case TELOPT_TTYPE:
+ fprintf(NetTrace, "TERMINAL-TYPE ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ fprintf(NetTrace, "SEND");
+ break;
+ default:
+ fprintf(NetTrace,
+ "- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+ case TELOPT_TSPEED:
+ fprintf(NetTrace, "TERMINAL-SPEED");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, " IS ");
+ fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
+ break;
+ default:
+ if (pointer[1] == 1)
+ fprintf(NetTrace, " SEND");
+ else
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+ }
+ break;
+
+ case TELOPT_LFLOW:
+ fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case LFLOW_OFF:
+ fprintf(NetTrace, " OFF"); break;
+ case LFLOW_ON:
+ fprintf(NetTrace, " ON"); break;
+ case LFLOW_RESTART_ANY:
+ fprintf(NetTrace, " RESTART-ANY"); break;
+ case LFLOW_RESTART_XON:
+ fprintf(NetTrace, " RESTART-XON"); break;
+ default:
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ }
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+
+ case TELOPT_NAWS:
+ fprintf(NetTrace, "NAWS");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ if (length == 2) {
+ fprintf(NetTrace, " ?%d?", pointer[1]);
+ break;
+ }
+ fprintf(NetTrace, " %d %d (%d)",
+ pointer[1], pointer[2],
+ (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+ if (length == 4) {
+ fprintf(NetTrace, " ?%d?", pointer[3]);
+ break;
+ }
+ fprintf(NetTrace, " %d %d (%d)",
+ pointer[3], pointer[4],
+ (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+ for (i = 5; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ fprintf(NetTrace, "AUTHENTICATION");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_REPLY:
+ case TELQUAL_IS:
+ fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
+ "IS" : "REPLY");
+ if (AUTHTYPE_NAME_OK(pointer[2]))
+ fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
+ else
+ fprintf(NetTrace, "%d ", pointer[2]);
+ if (length < 3) {
+ fprintf(NetTrace, "(partial suboption??\?)");
+ break;
+ }
+ fprintf(NetTrace, "%s|%s",
+ ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+
+ auth_printsub(&pointer[1], length - 1, (unsigned char *)buf, sizeof(buf));
+ fprintf(NetTrace, "%s", buf);
+ break;
+
+ case TELQUAL_SEND:
+ i = 2;
+ fprintf(NetTrace, " SEND ");
+ while (i < length) {
+ if (AUTHTYPE_NAME_OK(pointer[i]))
+ fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
+ else
+ fprintf(NetTrace, "%d ", pointer[i]);
+ if (++i >= length) {
+ fprintf(NetTrace, "(partial suboption??\?)");
+ break;
+ }
+ fprintf(NetTrace, "%s|%s ",
+ ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+ ++i;
+ }
+ break;
+
+ case TELQUAL_NAME:
+ i = 2;
+ fprintf(NetTrace, " NAME \"");
+ while (i < length)
+ putc(pointer[i++], NetTrace);
+ putc('"', NetTrace);
+ break;
+
+ default:
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+ }
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ fprintf(NetTrace, "ENCRYPT");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case ENCRYPT_START:
+ fprintf(NetTrace, " START");
+ break;
+
+ case ENCRYPT_END:
+ fprintf(NetTrace, " END");
+ break;
+
+ case ENCRYPT_REQSTART:
+ fprintf(NetTrace, " REQUEST-START");
+ break;
+
+ case ENCRYPT_REQEND:
+ fprintf(NetTrace, " REQUEST-END");
+ break;
+
+ case ENCRYPT_IS:
+ case ENCRYPT_REPLY:
+ fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
+ "IS" : "REPLY");
+ if (length < 3) {
+ fprintf(NetTrace, " (partial suboption??\?)");
+ break;
+ }
+ if (ENCTYPE_NAME_OK(pointer[2]))
+ fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
+ else
+ fprintf(NetTrace, " %d (unknown)", pointer[2]);
+
+ encrypt_printsub(&pointer[1], length - 1, (unsigned char *)buf, sizeof(buf));
+ fprintf(NetTrace, "%s", buf);
+ break;
+
+ case ENCRYPT_SUPPORT:
+ i = 2;
+ fprintf(NetTrace, " SUPPORT ");
+ while (i < length) {
+ if (ENCTYPE_NAME_OK(pointer[i]))
+ fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
+ else
+ fprintf(NetTrace, "%d ", pointer[i]);
+ i++;
+ }
+ break;
+
+ case ENCRYPT_ENC_KEYID:
+ fprintf(NetTrace, " ENC_KEYID ");
+ goto encommon;
+
+ case ENCRYPT_DEC_KEYID:
+ fprintf(NetTrace, " DEC_KEYID ");
+ goto encommon;
+
+ default:
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ encommon:
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+
+ case TELOPT_LINEMODE:
+ fprintf(NetTrace, "LINEMODE ");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case WILL:
+ fprintf(NetTrace, "WILL ");
+ goto common;
+ case WONT:
+ fprintf(NetTrace, "WONT ");
+ goto common;
+ case DO:
+ fprintf(NetTrace, "DO ");
+ goto common;
+ case DONT:
+ fprintf(NetTrace, "DONT ");
+ common:
+ if (length < 3) {
+ fprintf(NetTrace, "(no option??\?)");
+ break;
+ }
+ switch (pointer[2]) {
+ case LM_FORWARDMASK:
+ fprintf(NetTrace, "Forward Mask");
+ for (i = 3; i < length; i++)
+ fprintf(NetTrace, " %x", pointer[i]);
+ break;
+ default:
+ fprintf(NetTrace, "%d (unknown)", pointer[2]);
+ for (i = 3; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ break;
+
+ case LM_SLC:
+ fprintf(NetTrace, "SLC");
+ for (i = 2; i < length - 2; i += 3) {
+ if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+ fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
+ else
+ fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
+ switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+ case SLC_NOSUPPORT:
+ fprintf(NetTrace, " NOSUPPORT"); break;
+ case SLC_CANTCHANGE:
+ fprintf(NetTrace, " CANTCHANGE"); break;
+ case SLC_VARIABLE:
+ fprintf(NetTrace, " VARIABLE"); break;
+ case SLC_DEFAULT:
+ fprintf(NetTrace, " DEFAULT"); break;
+ }
+ fprintf(NetTrace, "%s%s%s",
+ pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
+ if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+ SLC_FLUSHOUT| SLC_LEVELBITS))
+ fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
+ fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
+ if ((pointer[i+SLC_VALUE] == IAC) &&
+ (pointer[i+SLC_VALUE+1] == IAC))
+ i++;
+ }
+ for (; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+
+ case LM_MODE:
+ fprintf(NetTrace, "MODE ");
+ if (length < 3) {
+ fprintf(NetTrace, "(no mode??\?)");
+ break;
+ }
+ {
+ char tbuf[64];
+ sprintf(tbuf, "%s%s%s%s%s",
+ pointer[2]&MODE_EDIT ? "|EDIT" : "",
+ pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
+ pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
+ pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
+ pointer[2]&MODE_ACK ? "|ACK" : "");
+ fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
+ }
+ if (pointer[2]&~(MODE_MASK))
+ fprintf(NetTrace, " (0x%x)", pointer[2]);
+ for (i = 3; i < length; i++)
+ fprintf(NetTrace, " ?0x%x?", pointer[i]);
+ break;
+ default:
+ fprintf(NetTrace, "%d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ }
+ break;
+
+ case TELOPT_STATUS: {
+ const char *cp;
+ int j, k;
+
+ fprintf(NetTrace, "STATUS");
+
+ switch (pointer[1]) {
+ default:
+ if (pointer[1] == TELQUAL_SEND)
+ fprintf(NetTrace, " SEND");
+ else
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+ case TELQUAL_IS:
+ if (--want_status_response < 0)
+ want_status_response = 0;
+ if (NetTrace == stdout)
+ fprintf(NetTrace, " IS\r\n");
+ else
+ fprintf(NetTrace, " IS\n");
+
+ for (i = 2; i < length; i++) {
+ switch(pointer[i]) {
+ case DO: cp = "DO"; goto common2;
+ case DONT: cp = "DONT"; goto common2;
+ case WILL: cp = "WILL"; goto common2;
+ case WONT: cp = "WONT"; goto common2;
+ common2:
+ i++;
+ if (TELOPT_OK((int)pointer[i]))
+ fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
+ else
+ fprintf(NetTrace, " %s %d", cp, pointer[i]);
+
+ if (NetTrace == stdout)
+ fprintf(NetTrace, "\r\n");
+ else
+ fprintf(NetTrace, "\n");
+ break;
+
+ case SB:
+ fprintf(NetTrace, " SB ");
+ i++;
+ j = k = i;
+ while (j < length) {
+ if (pointer[j] == SE) {
+ if (j+1 == length)
+ break;
+ if (pointer[j+1] == SE)
+ j++;
+ else
+ break;
+ }
+ pointer[k++] = pointer[j++];
+ }
+ printsub(0, &pointer[i], k - i);
+ if (i < length) {
+ fprintf(NetTrace, " SE");
+ i = j;
+ } else
+ i = j - 1;
+
+ if (NetTrace == stdout)
+ fprintf(NetTrace, "\r\n");
+ else
+ fprintf(NetTrace, "\n");
+
+ break;
+
+ default:
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ case TELOPT_XDISPLOC:
+ fprintf(NetTrace, "X-DISPLAY-LOCATION ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ fprintf(NetTrace, "SEND");
+ break;
+ default:
+ fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+
+ case TELOPT_NEW_ENVIRON:
+ fprintf(NetTrace, "NEW-ENVIRON ");
+#ifdef OLD_ENVIRON
+ goto env_common1;
+ case TELOPT_OLD_ENVIRON:
+ fprintf(NetTrace, "OLD-ENVIRON");
+ env_common1:
+#endif
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, "IS ");
+ goto env_common;
+ case TELQUAL_SEND:
+ fprintf(NetTrace, "SEND ");
+ goto env_common;
+ case TELQUAL_INFO:
+ fprintf(NetTrace, "INFO ");
+ env_common:
+ {
+ int noquote = 2;
+#if defined(ENV_HACK) && defined(OLD_ENVIRON)
+ extern int old_env_var, old_env_value;
+#endif
+ for (i = 2; i < length; i++ ) {
+ switch (pointer[i]) {
+ case NEW_ENV_VALUE:
+#ifdef OLD_ENVIRON
+ /* case NEW_ENV_OVAR: */
+ if (pointer[0] == TELOPT_OLD_ENVIRON) {
+# ifdef ENV_HACK
+ if (old_env_var == OLD_ENV_VALUE)
+ fprintf(NetTrace, "\" (VALUE) " + noquote);
+ else
+# endif
+ fprintf(NetTrace, "\" VAR " + noquote);
+ } else
+#endif /* OLD_ENVIRON */
+ fprintf(NetTrace, "%s", "\" VALUE " + noquote);
+ noquote = 2;
+ break;
+
+ case NEW_ENV_VAR:
+#ifdef OLD_ENVIRON
+ /* case OLD_ENV_VALUE: */
+ if (pointer[0] == TELOPT_OLD_ENVIRON) {
+# ifdef ENV_HACK
+ if (old_env_value == OLD_ENV_VAR)
+ fprintf(NetTrace, "\" (VAR) " + noquote);
+ else
+# endif
+ fprintf(NetTrace, "\" VALUE " + noquote);
+ } else
+#endif /* OLD_ENVIRON */
+ fprintf(NetTrace, "%s", "\" VAR " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_ESC:
+ fprintf(NetTrace, "%s", "\" ESC " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_USERVAR:
+ fprintf(NetTrace, "%s", "\" USERVAR " + noquote);
+ noquote = 2;
+ break;
+
+ default:
+ if (isprint(pointer[i]) && pointer[i] != '"') {
+ if (noquote) {
+ putc('"', NetTrace);
+ noquote = 0;
+ }
+ putc(pointer[i], NetTrace);
+ } else {
+ fprintf(NetTrace, "\" %03o " + noquote,
+ pointer[i]);
+ noquote = 2;
+ }
+ break;
+ }
+ }
+ if (!noquote)
+ putc('"', NetTrace);
+ break;
+ }
+ }
+ break;
+
+ default:
+ if (TELOPT_OK(pointer[0]))
+ fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
+ else
+ fprintf(NetTrace, "%d (unknown)", pointer[0]);
+ for (i = 1; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ if (direction) {
+ if (NetTrace == stdout)
+ fprintf(NetTrace, "\r\n");
+ else
+ fprintf(NetTrace, "\n");
+ }
+ if (NetTrace == stdout)
+ fflush(NetTrace);
+ }
+}
+
+/* EmptyTerminal - called to make sure that the terminal buffer is empty.
+ * Note that we consider the buffer to run all the
+ * way to the kernel (thus the select).
+ */
+
+static void
+EmptyTerminal(void)
+{
+ fd_set o;
+
+ FD_ZERO(&o);
+
+ if (TTYBYTES() == 0) {
+ FD_SET(tout, &o);
+ (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0); /* wait for TTLOWAT */
+ } else {
+ while (TTYBYTES()) {
+ (void) ttyflush(0);
+ FD_SET(tout, &o);
+ (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0); /* wait for TTLOWAT */
+ }
+ }
+}
+
+static void
+SetForExit(void)
+{
+ setconnmode(0);
+ do {
+ (void)telrcv(); /* Process any incoming data */
+ EmptyTerminal();
+ } while (ring_full_count(&netiring)); /* While there is any */
+ setcommandmode();
+ fflush(stdout);
+ fflush(stderr);
+ setconnmode(0);
+ EmptyTerminal(); /* Flush the path to the tty */
+ setcommandmode();
+}
+
+void
+Exit(int returnCode)
+{
+ SetForExit();
+ exit(returnCode);
+}
+
+void
+ExitString(const char *string, int returnCode)
+{
+ SetForExit();
+ fwrite(string, 1, strlen(string), stderr);
+ exit(returnCode);
+}
diff --git a/remote_cmds/telnetd.tproj/Makefile b/remote_cmds/telnetd.tproj/Makefile
new file mode 100644
index 0000000..c3f7feb
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/Makefile
@@ -0,0 +1,50 @@
+Project = telnetd
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+Install_Dir = /usr/libexec
+else
+Install_Dir = /usr/local/libexec
+endif
+
+HFILES = defs.h ext.h pathnames.h telnetd.h
+CFILES = global.c slc.c state.c sys_term.c telnetd.c\
+ termstat.c utility.c
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+LAUNCHD_PLISTS = telnet.plist
+endif
+
+Extra_CC_Flags = -Wall -Werror -Wno-string-plus-int -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_CC_Flags += -DNO_UTMP -DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO \
+ -DDIAGNOSTICS -DOLD_ENVIRON -DENV_HACK -DINET6 \
+ # -DAUTHENTICATION -DENCRYPTION
+Extra_LD_Libraries = -lcurses -ltelnet
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+after_install:
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+ /usr/libexec/PlistBuddy -x \
+ -c "Delete :Disabled" \
+ -c "Add :PosixSpawnType string Interactive" \
+ -c "Delete :SessionCreate" \
+ -c "Set :Sockets:Listeners:Bonjour false" \
+ -c "Add :Sockets:Listeners:SockFamily string IPv4" \
+ -c "Add :Sockets:Listeners:SockNodeName string localhost" \
+ "$(DSTROOT)/System/Library/LaunchDaemons/telnet.plist"
+ifeq "$(RC_PLATFORM_NAME)" "BridgeOS"
+ /usr/libexec/PlistBuddy -x \
+ -c "Delete :Sockets:Listeners:SockNodeName" \
+ -c "Delete :Sockets:Listeners:SockFamily" \
+ "$(DSTROOT)/System/Library/LaunchDaemons/telnet.plist"
+endif
+ plutil -convert binary1 "$(DSTROOT)/System/Library/LaunchDaemons/$(LAUNCHD_PLISTS)"
+endif
+ /usr/bin/codesign --force --sign - --entitlements entitlements.plist $(DSTROOT)$(Install_Dir)/$(Project)
+
+# Install a special launchd plist for the DebugDiskImage (38885624)
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+ plutil -replace ProgramArguments -json '["/var/personalized_debug/usr/libexec/telnetd","-p","/var/personalized_debug/usr/bin/login"]' -o "$(DSTROOT)/System/Library/LaunchDaemons/telnet.debug.plist" "$(DSTROOT)/System/Library/LaunchDaemons/telnet.plist"
+ plutil -replace Label -string com.apple.telnetd.debug "$(DSTROOT)/System/Library/LaunchDaemons/telnet.debug.plist"
+endif
diff --git a/remote_cmds/telnetd.tproj/authenc.c b/remote_cmds/telnetd.tproj/authenc.c
new file mode 100644
index 0000000..10934ff
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/authenc.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/authenc.c,v 1.8 2003/05/04 02:54:49 obrien Exp $");
+
+#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#include "telnetd.h"
+#include <libtelnet/misc.h>
+
+int
+net_write(unsigned char *str, int len)
+{
+ if (nfrontp + len < netobuf + BUFSIZ) {
+ output_datalen(str, len);
+ return(len);
+ }
+ return(0);
+}
+
+void
+net_encrypt(void)
+{
+#ifdef ENCRYPTION
+ char *s = (nclearto > nbackp) ? nclearto : nbackp;
+ if (s < nfrontp && encrypt_output) {
+ (*encrypt_output)((unsigned char *)s, nfrontp - s);
+ }
+ nclearto = nfrontp;
+#endif /* ENCRYPTION */
+}
+
+int
+telnet_spin(void)
+{
+ ttloop();
+ return(0);
+}
+
+char *
+telnet_getenv(char *val)
+{
+ return(getenv(val));
+}
+
+char *
+telnet_gets(const char *prompt __unused, char *result __unused, int length __unused, int echo __unused)
+{
+ return(NULL);
+}
+#endif /* ENCRYPTION */
+#endif /* AUTHENTICATION */
diff --git a/remote_cmds/telnetd.tproj/defs.h b/remote_cmds/telnetd.tproj/defs.h
new file mode 100644
index 0000000..31ef2fb
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/defs.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/contrib/telnet/telnetd/defs.h,v 1.2 2001/08/29 14:16:15 markm Exp $
+ */
+
+/*
+ * Telnet server defines
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifndef BSD
+# define BSD 43
+#endif
+
+#if defined(PRINTOPTIONS) && defined(DIAGNOSTICS)
+#define TELOPTS
+#define TELCMDS
+#define SLC_NAMES
+#endif
+
+#if defined(SYSV_TERMIO) && !defined(USE_TERMIO)
+# define USE_TERMIO
+#endif
+
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#ifndef FILIO_H
+#include <sys/ioctl.h>
+#else
+#include <sys/filio.h>
+#endif
+
+#include <netinet/in.h>
+
+#include <arpa/telnet.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+#include <syslog.h>
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+#ifndef LOG_ODELAY
+#define LOG_ODELAY 0
+#endif
+#include <ctype.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifndef USE_TERMIO
+#include <sgtty.h>
+#else
+# ifdef SYSV_TERMIO
+# include <termio.h>
+# else
+# include <termios.h>
+# endif
+#endif
+#if !defined(USE_TERMIO) || defined(NO_CC_T)
+typedef unsigned char cc_t;
+#endif
+
+#ifdef __STDC__
+#include <unistd.h>
+#endif
+
+#ifndef _POSIX_VDISABLE
+# ifdef VDISABLE
+# define _POSIX_VDISABLE VDISABLE
+# else
+# define _POSIX_VDISABLE ((unsigned char)'\377')
+# endif
+#endif
+
+#if !defined(TIOCSCTTY) && defined(TCSETCTTY)
+# define TIOCSCTTY TCSETCTTY
+#endif
+
+#ifndef FD_SET
+#ifndef HAVE_fd_set
+typedef struct fd_set { int fds_bits[1]; } fd_set;
+#endif
+
+#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
+#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
+#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
+#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
+#endif /* FD_SET */
+
+/*
+ * I/O data buffers defines
+ */
+#define NETSLOP 64
+
+#define NIACCUM(c) { *netip++ = c; \
+ ncc++; \
+ }
+
+/* clock manipulations */
+#define settimer(x) (clocks.x = ++clocks.system)
+#define sequenceIs(x,y) (clocks.x < clocks.y)
+
+/*
+ * Linemode support states, in decreasing order of importance
+ */
+#define REAL_LINEMODE 0x04
+#define KLUDGE_OK 0x03
+#define NO_AUTOKLUDGE 0x02
+#define KLUDGE_LINEMODE 0x01
+#define NO_LINEMODE 0x00
+
+/*
+ * Structures of information for each special character function.
+ */
+typedef struct {
+ unsigned char flag; /* the flags for this function */
+ cc_t val; /* the value of the special character */
+} slcent, *Slcent;
+
+typedef struct {
+ slcent defset; /* the default settings */
+ slcent current; /* the current settings */
+ cc_t *sptr; /* a pointer to the char in */
+ /* system data structures */
+} slcfun, *Slcfun;
+
+#ifdef DIAGNOSTICS
+/*
+ * Diagnostics capabilities
+ */
+#define TD_REPORT 0x01 /* Report operations to client */
+#define TD_EXERCISE 0x02 /* Exercise client's implementation */
+#define TD_NETDATA 0x04 /* Display received data stream */
+#define TD_PTYDATA 0x08 /* Display data passed to pty */
+#define TD_OPTIONS 0x10 /* Report just telnet options */
+#endif /* DIAGNOSTICS */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define MY_STATE_WILL 0x01
+#define MY_WANT_STATE_WILL 0x02
+#define MY_STATE_DO 0x04
+#define MY_WANT_STATE_DO 0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define my_state_is_do(opt) (options[opt]&MY_STATE_DO)
+#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL)
+
+#define my_state_is_dont(opt) (!my_state_is_do(opt))
+#define my_state_is_wont(opt) (!my_state_is_will(opt))
+#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt))
+
+#define set_my_state_do(opt) (options[opt] |= MY_STATE_DO)
+#define set_my_state_will(opt) (options[opt] |= MY_STATE_WILL)
+#define set_my_want_state_do(opt) (options[opt] |= MY_WANT_STATE_DO)
+#define set_my_want_state_will(opt) (options[opt] |= MY_WANT_STATE_WILL)
+
+#define set_my_state_dont(opt) (options[opt] &= ~MY_STATE_DO)
+#define set_my_state_wont(opt) (options[opt] &= ~MY_STATE_WILL)
+#define set_my_want_state_dont(opt) (options[opt] &= ~MY_WANT_STATE_DO)
+#define set_my_want_state_wont(opt) (options[opt] &= ~MY_WANT_STATE_WILL)
+
+/*
+ * Tricky code here. What we want to know is if the MY_STATE_WILL
+ * and MY_WANT_STATE_WILL bits have the same value. Since the two
+ * bits are adjacent, a little arithmatic will show that by adding
+ * in the lower bit, the upper bit will be set if the two bits were
+ * different, and clear if they were the same.
+ */
+#define my_will_wont_is_changing(opt) \
+ ((options[opt]+MY_STATE_WILL) & MY_WANT_STATE_WILL)
+
+#define my_do_dont_is_changing(opt) \
+ ((options[opt]+MY_STATE_DO) & MY_WANT_STATE_DO)
+
+/*
+ * Make everything symetrical
+ */
+
+#define HIS_STATE_WILL MY_STATE_DO
+#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO
+#define HIS_STATE_DO MY_STATE_WILL
+#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL
+
+#define his_state_is_do my_state_is_will
+#define his_state_is_will my_state_is_do
+#define his_want_state_is_do my_want_state_is_will
+#define his_want_state_is_will my_want_state_is_do
+
+#define his_state_is_dont my_state_is_wont
+#define his_state_is_wont my_state_is_dont
+#define his_want_state_is_dont my_want_state_is_wont
+#define his_want_state_is_wont my_want_state_is_dont
+
+#define set_his_state_do set_my_state_will
+#define set_his_state_will set_my_state_do
+#define set_his_want_state_do set_my_want_state_will
+#define set_his_want_state_will set_my_want_state_do
+
+#define set_his_state_dont set_my_state_wont
+#define set_his_state_wont set_my_state_dont
+#define set_his_want_state_dont set_my_want_state_wont
+#define set_his_want_state_wont set_my_want_state_dont
+
+#define his_will_wont_is_changing my_do_dont_is_changing
+#define his_do_dont_is_changing my_will_wont_is_changing
diff --git a/remote_cmds/telnetd.tproj/entitlements.plist b/remote_cmds/telnetd.tproj/entitlements.plist
new file mode 100644
index 0000000..4d3ae68
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.network.server</key>
+ <true/>
+</dict>
+</plist>
diff --git a/remote_cmds/telnetd.tproj/ext.h b/remote_cmds/telnetd.tproj/ext.h
new file mode 100644
index 0000000..0905b61
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/ext.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ext.h 8.2 (Berkeley) 12/15/93
+ * $FreeBSD: src/contrib/telnet/telnetd/ext.h,v 1.11 2001/11/30 22:28:07 markm Exp $
+ */
+
+/*
+ * Telnet server variable declarations
+ */
+extern char options[256];
+extern char do_dont_resp[256];
+extern char will_wont_resp[256];
+extern int linemode; /* linemode on/off */
+#ifdef LINEMODE
+extern int uselinemode; /* what linemode to use (on/off) */
+extern int editmode; /* edit modes in use */
+extern int useeditmode; /* edit modes to use */
+extern int alwayslinemode; /* command line option */
+extern int lmodetype; /* Client support for linemode */
+#endif /* LINEMODE */
+extern int flowmode; /* current flow control state */
+extern int restartany; /* restart output on any character state */
+#ifdef DIAGNOSTICS
+extern int diagnostic; /* telnet diagnostic capabilities */
+#endif /* DIAGNOSTICS */
+#ifdef BFTPDAEMON
+extern int bftpd; /* behave as bftp daemon */
+#endif /* BFTPDAEMON */
+#ifdef AUTHENTICATION
+extern int auth_level;
+#endif
+
+extern slcfun slctab[NSLC + 1]; /* slc mapping table */
+
+extern char *terminaltype;
+
+/*
+ * I/O data buffers, pointers, and counters.
+ */
+extern char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
+
+extern char netibuf[BUFSIZ], *netip;
+
+extern char netobuf[BUFSIZ], *nfrontp, *nbackp;
+extern char *neturg; /* one past last bye of urgent data */
+
+extern int pcc, ncc;
+
+extern int mpty, spty, net;
+extern char line[16];
+extern int SYNCHing; /* we are in TELNET SYNCH mode */
+
+extern void
+ _termstat(void),
+ add_slc(char, char, cc_t),
+ check_slc(void),
+ change_slc(char, char, cc_t),
+ cleanup(int),
+ clientstat(int, int, int),
+ copy_termbuf(char *, size_t),
+ deferslc(void),
+ defer_terminit(void),
+ do_opt_slc(unsigned char *, int),
+ doeof(void),
+ dooption(int),
+ dontoption(int),
+ edithost(char *, char *),
+ fatal(int, const char *),
+ fatalperror(int, const char *),
+ get_slc_defaults(void),
+ init_env(void),
+ init_termbuf(void),
+ interrupt(void),
+ localstat(void),
+ flowstat(void),
+ netclear(void),
+ netflush(void),
+#ifdef DIAGNOSTICS
+ printoption(const char *, int),
+ printdata(const char *, char *, int),
+ printsub(char, unsigned char *, int),
+#endif
+ process_slc(unsigned char, unsigned char, cc_t),
+ ptyflush(void),
+ putchr(int),
+ putf(char *, char *),
+ recv_ayt(void),
+ send_do(int, int),
+ send_dont(int, int),
+ send_slc(void),
+ send_status(void),
+ send_will(int, int),
+ send_wont(int, int),
+ sendbrk(void),
+ sendsusp(void),
+ set_termbuf(void),
+ start_login(char *, int, char *),
+ start_slc(int),
+#ifdef AUTHENTICATION
+ start_slave(char *),
+#else
+ start_slave(char *, int, char *),
+#endif
+ suboption(void),
+ telrcv(void),
+ ttloop(void),
+ tty_binaryin(int),
+ tty_binaryout(int);
+
+extern int
+ end_slc(unsigned char **),
+ getnpty(void),
+#ifndef convex
+ getpty(int *, int *),
+#endif
+ login_tty(int),
+ spcset(int, cc_t *, cc_t **),
+ stilloob(int),
+ terminit(void),
+ termstat(void),
+ tty_flowmode(void),
+ tty_restartany(void),
+ tty_isbinaryin(void),
+ tty_isbinaryout(void),
+ tty_iscrnl(void),
+ tty_isecho(void),
+ tty_isediting(void),
+ tty_islitecho(void),
+ tty_isnewmap(void),
+ tty_israw(void),
+ tty_issofttab(void),
+ tty_istrapsig(void),
+ tty_linemode(void);
+
+extern void
+ tty_rspeed(int),
+ tty_setecho(int),
+ tty_setedit(int),
+ tty_setlinemode(int),
+ tty_setlitecho(int),
+ tty_setsig(int),
+ tty_setsofttab(int),
+ tty_tspeed(int),
+ willoption(int),
+ wontoption(int);
+
+int output_data(const char *, ...) __printflike(1, 2);
+void output_datalen(const char *, int);
+void startslave(char *, int, char *);
+
+#ifdef ENCRYPTION
+extern void (*encrypt_output)(unsigned char *, int);
+extern int (*decrypt_input)(int);
+extern char *nclearto;
+#endif /* ENCRYPTION */
+
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+extern struct {
+ int
+ system, /* what the current time is */
+ echotoggle, /* last time user entered echo character */
+ modenegotiated, /* last time operating mode negotiated */
+ didnetreceive, /* last time we read data from network */
+ ttypesubopt, /* ttype subopt is received */
+ tspeedsubopt, /* tspeed subopt is received */
+ environsubopt, /* environ subopt is received */
+ oenvironsubopt, /* old environ subopt is received */
+ xdisplocsubopt, /* xdisploc subopt is received */
+ baseline, /* time started to do timed action */
+ gotDM; /* when did we last see a data mark */
+} clocks;
+
+#ifndef DEFAULT_IM
+#ifdef __APPLE__
+# define DEFAULT_IM "\r\n\r\nFreeBSD (%h) (%t)\r\n\r\r\n\r"
+#else
+# ifdef ultrix
+# define DEFAULT_IM "\r\n\r\nULTRIX (%h) (%t)\r\n\r\r\n\r"
+# else
+# ifdef __FreeBSD__
+# define DEFAULT_IM "\r\n\r\nFreeBSD (%h) (%t)\r\n\r\r\n\r"
+# else
+# define DEFAULT_IM "\r\n\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r"
+# endif
+# endif
+#endif /* __APPLE__ */
+#endif
diff --git a/remote_cmds/telnetd.tproj/global.c b/remote_cmds/telnetd.tproj/global.c
new file mode 100644
index 0000000..eefd129
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/global.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/global.c,v 1.6 2003/05/04 02:54:49 obrien Exp $");
+
+/*
+ * Allocate global variables. We do this
+ * by including the header file that defines
+ * them all as externs, but first we define
+ * the keyword "extern" to be nothing, so that
+ * we will actually allocate the space.
+ */
+
+#include "defs.h"
+#define extern
+#include "ext.h"
diff --git a/remote_cmds/telnetd.tproj/pathnames.h b/remote_cmds/telnetd.tproj/pathnames.h
new file mode 100644
index 0000000..43fce7e
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/pathnames.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/contrib/telnet/telnetd/pathnames.h,v 1.3 2001/08/20 12:28:40 markm Exp $
+ */
+
+#if BSD > 43
+
+# include <paths.h>
+
+# ifndef _PATH_LOGIN
+# define _PATH_LOGIN "/usr/bin/login"
+# endif
+
+#else
+
+# define _PATH_TTY "/dev/tty"
+# ifndef _PATH_LOGIN
+# define _PATH_LOGIN "/bin/login"
+# endif
+
+#endif
+
+#ifdef BFTPDAEMON
+#define BFTPPATH "/usr/ucb/bftp"
+#endif /* BFTPDAEMON */
diff --git a/remote_cmds/telnetd.tproj/slc.c b/remote_cmds/telnetd.tproj/slc.c
new file mode 100644
index 0000000..eb31ef8
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/slc.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/slc.c,v 1.9 2003/05/04 02:54:49 obrien Exp $");
+
+#include "telnetd.h"
+
+#ifdef LINEMODE
+/*
+ * local variables
+ */
+static unsigned char *def_slcbuf = (unsigned char *)0;
+static int def_slclen = 0;
+static int slcchange; /* change to slc is requested */
+static unsigned char *slcptr; /* pointer into slc buffer */
+static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */
+
+/*
+ * send_slc
+ *
+ * Write out the current special characters to the client.
+ */
+void
+send_slc(void)
+{
+ int i;
+
+ /*
+ * Send out list of triplets of special characters
+ * to client. We only send info on the characters
+ * that are currently supported.
+ */
+ for (i = 1; i <= NSLC; i++) {
+ if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
+ continue;
+ add_slc((unsigned char)i, slctab[i].current.flag,
+ slctab[i].current.val);
+ }
+
+} /* end of send_slc */
+
+/*
+ * default_slc
+ *
+ * Set pty special characters to all the defaults.
+ */
+static void
+default_slc(void)
+{
+ int i;
+
+ for (i = 1; i <= NSLC; i++) {
+ slctab[i].current.val = slctab[i].defset.val;
+ if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE))
+ slctab[i].current.flag = SLC_NOSUPPORT;
+ else
+ slctab[i].current.flag = slctab[i].defset.flag;
+ if (slctab[i].sptr) {
+ *(slctab[i].sptr) = slctab[i].defset.val;
+ }
+ }
+ slcchange = 1;
+
+} /* end of default_slc */
+#endif /* LINEMODE */
+
+/*
+ * get_slc_defaults
+ *
+ * Initialize the slc mapping table.
+ */
+void
+get_slc_defaults(void)
+{
+ int i;
+
+ init_termbuf();
+
+ for (i = 1; i <= NSLC; i++) {
+ slctab[i].defset.flag =
+ spcset(i, &slctab[i].defset.val, &slctab[i].sptr);
+ slctab[i].current.flag = SLC_NOSUPPORT;
+ slctab[i].current.val = 0;
+ }
+
+} /* end of get_slc_defaults */
+
+#ifdef LINEMODE
+/*
+ * add_slc
+ *
+ * Add an slc triplet to the slc buffer.
+ */
+void
+add_slc(char func, char flag, cc_t val)
+{
+
+ if ((*slcptr++ = (unsigned char)func) == 0xff)
+ *slcptr++ = 0xff;
+
+ if ((*slcptr++ = (unsigned char)flag) == 0xff)
+ *slcptr++ = 0xff;
+
+ if ((*slcptr++ = (unsigned char)val) == 0xff)
+ *slcptr++ = 0xff;
+
+} /* end of add_slc */
+
+/*
+ * start_slc
+ *
+ * Get ready to process incoming slc's and respond to them.
+ *
+ * The parameter getit is non-zero if it is necessary to grab a copy
+ * of the terminal control structures.
+ */
+void
+start_slc(int getit)
+{
+
+ slcchange = 0;
+ if (getit)
+ init_termbuf();
+ (void) sprintf((char *)slcbuf, "%c%c%c%c",
+ IAC, SB, TELOPT_LINEMODE, LM_SLC);
+ slcptr = slcbuf + 4;
+
+} /* end of start_slc */
+
+/*
+ * end_slc
+ *
+ * Finish up the slc negotiation. If something to send, then send it.
+ */
+int
+end_slc(unsigned char **bufp)
+{
+ int len;
+
+ /*
+ * If a change has occured, store the new terminal control
+ * structures back to the terminal driver.
+ */
+ if (slcchange) {
+ set_termbuf();
+ }
+
+ /*
+ * If the pty state has not yet been fully processed and there is a
+ * deferred slc request from the client, then do not send any
+ * sort of slc negotiation now. We will respond to the client's
+ * request very soon.
+ */
+ if (def_slcbuf && (terminit() == 0)) {
+ return(0);
+ }
+
+ if (slcptr > (slcbuf + 4)) {
+ if (bufp) {
+ *bufp = &slcbuf[4];
+ return(slcptr - slcbuf - 4);
+ } else {
+ (void) sprintf((char *)slcptr, "%c%c", IAC, SE);
+ slcptr += 2;
+ len = slcptr - slcbuf;
+ output_datalen((const char*)slcbuf, len);
+ netflush(); /* force it out immediately */
+ DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
+ }
+ }
+ return (0);
+
+} /* end of end_slc */
+
+/*
+ * process_slc
+ *
+ * Figure out what to do about the client's slc
+ */
+void
+process_slc(unsigned char func, unsigned char flag, cc_t val)
+{
+ int hislevel, mylevel, ack;
+
+ /*
+ * Ensure that we know something about this function
+ */
+ if (func > NSLC) {
+ add_slc(func, SLC_NOSUPPORT, 0);
+ return;
+ }
+
+ /*
+ * Process the special case requests of 0 SLC_DEFAULT 0
+ * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't
+ * worry about whether the value is actually 0 or not.
+ */
+ if (func == 0) {
+ if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
+ default_slc();
+ send_slc();
+ } else if (flag == SLC_VARIABLE) {
+ send_slc();
+ }
+ return;
+ }
+
+ /*
+ * Appears to be a function that we know something about. So
+ * get on with it and see what we know.
+ */
+
+ hislevel = flag & SLC_LEVELBITS;
+ mylevel = slctab[func].current.flag & SLC_LEVELBITS;
+ ack = flag & SLC_ACK;
+ /*
+ * ignore the command if:
+ * the function value and level are the same as what we already have;
+ * or the level is the same and the ack bit is set
+ */
+ if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
+ return;
+ } else if (ack) {
+ /*
+ * If we get here, we got an ack, but the levels don't match.
+ * This shouldn't happen. If it does, it is probably because
+ * we have sent two requests to set a variable without getting
+ * a response between them, and this is the first response.
+ * So, ignore it, and wait for the next response.
+ */
+ return;
+ } else {
+ change_slc(func, flag, val);
+ }
+
+} /* end of process_slc */
+
+/*
+ * change_slc
+ *
+ * Process a request to change one of our special characters.
+ * Compare client's request with what we are capable of supporting.
+ */
+void
+change_slc(char func, char flag, cc_t val)
+{
+ int hislevel, mylevel;
+
+ hislevel = flag & SLC_LEVELBITS;
+ mylevel = slctab[(int)func].defset.flag & SLC_LEVELBITS;
+ /*
+ * If client is setting a function to NOSUPPORT
+ * or DEFAULT, then we can easily and directly
+ * accomodate the request.
+ */
+ if (hislevel == SLC_NOSUPPORT) {
+ slctab[(int)func].current.flag = flag;
+ slctab[(int)func].current.val = (cc_t)_POSIX_VDISABLE;
+ flag |= SLC_ACK;
+ add_slc(func, flag, val);
+ return;
+ }
+ if (hislevel == SLC_DEFAULT) {
+ /*
+ * Special case here. If client tells us to use
+ * the default on a function we don't support, then
+ * return NOSUPPORT instead of what we may have as a
+ * default level of DEFAULT.
+ */
+ if (mylevel == SLC_DEFAULT) {
+ slctab[(int)func].current.flag = SLC_NOSUPPORT;
+ } else {
+ slctab[(int)func].current.flag = slctab[(int)func].defset.flag;
+ }
+ slctab[(int)func].current.val = slctab[(int)func].defset.val;
+ add_slc(func, slctab[(int)func].current.flag,
+ slctab[(int)func].current.val);
+ return;
+ }
+
+ /*
+ * Client wants us to change to a new value or he
+ * is telling us that he can't change to our value.
+ * Some of the slc's we support and can change,
+ * some we do support but can't change,
+ * and others we don't support at all.
+ * If we can change it then we have a pointer to
+ * the place to put the new value, so change it,
+ * otherwise, continue the negotiation.
+ */
+ if (slctab[(int)func].sptr) {
+ /*
+ * We can change this one.
+ */
+ slctab[(int)func].current.val = val;
+ *(slctab[(int)func].sptr) = val;
+ slctab[(int)func].current.flag = flag;
+ flag |= SLC_ACK;
+ slcchange = 1;
+ add_slc(func, flag, val);
+ } else {
+ /*
+ * It is not possible for us to support this
+ * request as he asks.
+ *
+ * If our level is DEFAULT, then just ack whatever was
+ * sent.
+ *
+ * If he can't change and we can't change,
+ * then degenerate to NOSUPPORT.
+ *
+ * Otherwise we send our level back to him, (CANTCHANGE
+ * or NOSUPPORT) and if CANTCHANGE, send
+ * our value as well.
+ */
+ if (mylevel == SLC_DEFAULT) {
+ slctab[(int)func].current.flag = flag;
+ slctab[(int)func].current.val = val;
+ flag |= SLC_ACK;
+ } else if (hislevel == SLC_CANTCHANGE &&
+ mylevel == SLC_CANTCHANGE) {
+ flag &= ~SLC_LEVELBITS;
+ flag |= SLC_NOSUPPORT;
+ slctab[(int)func].current.flag = flag;
+ } else {
+ flag &= ~SLC_LEVELBITS;
+ flag |= mylevel;
+ slctab[(int)func].current.flag = flag;
+ if (mylevel == SLC_CANTCHANGE) {
+ slctab[(int)func].current.val =
+ slctab[(int)func].defset.val;
+ val = slctab[(int)func].current.val;
+ }
+ }
+ add_slc(func, flag, val);
+ }
+
+} /* end of change_slc */
+
+#if defined(USE_TERMIO) && (VEOF == VMIN)
+cc_t oldeofc = '\004';
+#endif
+
+/*
+ * check_slc
+ *
+ * Check the special characters in use and notify the client if any have
+ * changed. Only those characters that are capable of being changed are
+ * likely to have changed. If a local change occurs, kick the support level
+ * and flags up to the defaults.
+ */
+void
+check_slc(void)
+{
+ int i;
+
+ for (i = 1; i <= NSLC; i++) {
+#if defined(USE_TERMIO) && (VEOF == VMIN)
+ /*
+ * In a perfect world this would be a neat little
+ * function. But in this world, we should not notify
+ * client of changes to the VEOF char when
+ * ICANON is off, because it is not representing
+ * a special character.
+ */
+ if (i == SLC_EOF) {
+ if (!tty_isediting())
+ continue;
+ else if (slctab[i].sptr)
+ oldeofc = *(slctab[i].sptr);
+ }
+#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
+ if (slctab[i].sptr &&
+ (*(slctab[i].sptr) != slctab[i].current.val)) {
+ slctab[i].current.val = *(slctab[i].sptr);
+ if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE)
+ slctab[i].current.flag = SLC_NOSUPPORT;
+ else
+ slctab[i].current.flag = slctab[i].defset.flag;
+ add_slc((unsigned char)i, slctab[i].current.flag,
+ slctab[i].current.val);
+ }
+ }
+} /* check_slc */
+
+/*
+ * do_opt_slc
+ *
+ * Process an slc option buffer. Defer processing of incoming slc's
+ * until after the terminal state has been processed. Save the first slc
+ * request that comes along, but discard all others.
+ *
+ * ptr points to the beginning of the buffer, len is the length.
+ */
+void
+do_opt_slc(unsigned char *ptr, int len)
+{
+ unsigned char func, flag;
+ cc_t val;
+ unsigned char *end = ptr + len;
+
+ if (terminit()) { /* go ahead */
+ while (ptr < end) {
+ func = *ptr++;
+ if (ptr >= end) break;
+ flag = *ptr++;
+ if (ptr >= end) break;
+ val = (cc_t)*ptr++;
+
+ process_slc(func, flag, val);
+
+ }
+ } else {
+ /*
+ * save this slc buffer if it is the first, otherwise dump
+ * it.
+ */
+ if (def_slcbuf == (unsigned char *)0) {
+ def_slclen = len;
+ def_slcbuf = (unsigned char *)malloc((unsigned)len);
+ if (def_slcbuf == (unsigned char *)0)
+ return; /* too bad */
+ memmove(def_slcbuf, ptr, len);
+ }
+ }
+
+} /* end of do_opt_slc */
+
+/*
+ * deferslc
+ *
+ * Do slc stuff that was deferred.
+ */
+void
+deferslc(void)
+{
+ if (def_slcbuf) {
+ start_slc(1);
+ do_opt_slc(def_slcbuf, def_slclen);
+ (void) end_slc(0);
+ free(def_slcbuf);
+ def_slcbuf = (unsigned char *)0;
+ def_slclen = 0;
+ }
+
+} /* end of deferslc */
+
+#endif /* LINEMODE */
diff --git a/remote_cmds/telnetd.tproj/state.c b/remote_cmds/telnetd.tproj/state.c
new file mode 100644
index 0000000..a4dc138
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/state.c
@@ -0,0 +1,1631 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/state.c,v 1.14 2003/05/04 02:54:49 obrien Exp $");
+
+#include <stdarg.h>
+#include "telnetd.h"
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+unsigned char doopt[] = { IAC, DO, '%', 'c', 0 };
+unsigned char dont[] = { IAC, DONT, '%', 'c', 0 };
+unsigned char will[] = { IAC, WILL, '%', 'c', 0 };
+unsigned char wont[] = { IAC, WONT, '%', 'c', 0 };
+int not42 = 1;
+
+/*
+ * Buffer for sub-options, and macros
+ * for suboptions buffer manipulations
+ */
+unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
+
+#define SB_CLEAR() subpointer = subbuffer
+#define SB_TERM() { subend = subpointer; SB_CLEAR(); }
+#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
+ *subpointer++ = (c); \
+ }
+#define SB_GET() ((*subpointer++)&0xff)
+#define SB_EOF() (subpointer >= subend)
+#define SB_LEN() (subend - subpointer)
+
+#ifdef ENV_HACK
+unsigned char *subsave;
+#define SB_SAVE() subsave = subpointer;
+#define SB_RESTORE() subpointer = subsave;
+#endif
+
+
+/*
+ * State for recv fsm
+ */
+#define TS_DATA 0 /* base state */
+#define TS_IAC 1 /* look for double IAC's */
+#define TS_CR 2 /* CR-LF ->'s CR */
+#define TS_SB 3 /* throw away begin's... */
+#define TS_SE 4 /* ...end's (suboption negotiation) */
+#define TS_WILL 5 /* will option negotiation */
+#define TS_WONT 6 /* wont " */
+#define TS_DO 7 /* do " */
+#define TS_DONT 8 /* dont " */
+
+static void doclientstat(void);
+
+void
+telrcv(void)
+{
+ int c;
+ static int state = TS_DATA;
+
+ while (ncc > 0) {
+ if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
+ break;
+ c = *netip++ & 0377, ncc--;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
+ switch (state) {
+
+ case TS_CR:
+ state = TS_DATA;
+ /* Strip off \n or \0 after a \r */
+ if ((c == 0) || (c == '\n')) {
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case TS_DATA:
+ if (c == IAC) {
+ state = TS_IAC;
+ break;
+ }
+ /*
+ * We now map \r\n ==> \r for pragmatic reasons.
+ * Many client implementations send \r\n when
+ * the user hits the CarriageReturn key.
+ *
+ * We USED to map \r\n ==> \n, since \r\n says
+ * that we want to be in column 1 of the next
+ * printable line, and \n is the standard
+ * unix way of saying that (\r is only good
+ * if CRMOD is set, which it normally is).
+ */
+ if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
+ int nc = *netip;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ nc = (*decrypt_input)(nc & 0xff);
+#endif /* ENCRYPTION */
+#ifdef LINEMODE
+ /*
+ * If we are operating in linemode,
+ * convert to local end-of-line.
+ */
+ if (linemode && (ncc > 0) && (('\n' == nc) ||
+ ((0 == nc) && tty_iscrnl())) ) {
+ netip++; ncc--;
+ c = '\n';
+ } else
+#endif
+ {
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ (void)(*decrypt_input)(-1);
+#endif /* ENCRYPTION */
+ state = TS_CR;
+ }
+ }
+ *pfrontp++ = c;
+ break;
+
+ case TS_IAC:
+gotiac: switch (c) {
+
+ /*
+ * Send the process on the pty side an
+ * interrupt. Do this with a NULL or
+ * interrupt char; depending on the tty mode.
+ */
+ case IP:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ interrupt();
+ break;
+
+ case BREAK:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ sendbrk();
+ break;
+
+ /*
+ * Are You There?
+ */
+ case AYT:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ recv_ayt();
+ break;
+
+ /*
+ * Abort Output
+ */
+ case AO:
+ {
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ ptyflush(); /* half-hearted */
+ init_termbuf();
+
+ if (slctab[SLC_AO].sptr &&
+ *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
+ *pfrontp++ =
+ (unsigned char)*slctab[SLC_AO].sptr;
+ }
+
+ netclear(); /* clear buffer back */
+ output_data("%c%c", IAC, DM);
+ neturg = nfrontp-1; /* off by one XXX */
+ DIAG(TD_OPTIONS,
+ printoption("td: send IAC", DM));
+ break;
+ }
+
+ /*
+ * Erase Character and
+ * Erase Line
+ */
+ case EC:
+ case EL:
+ {
+ cc_t ch;
+
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ ptyflush(); /* half-hearted */
+ init_termbuf();
+ if (c == EC)
+ ch = *slctab[SLC_EC].sptr;
+ else
+ ch = *slctab[SLC_EL].sptr;
+ if (ch != (cc_t)(_POSIX_VDISABLE))
+ *pfrontp++ = (unsigned char)ch;
+ break;
+ }
+
+ /*
+ * Check for urgent data...
+ */
+ case DM:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ SYNCHing = stilloob(net);
+ settimer(gotDM);
+ break;
+
+
+ /*
+ * Begin option subnegotiation...
+ */
+ case SB:
+ state = TS_SB;
+ SB_CLEAR();
+ continue;
+
+ case WILL:
+ state = TS_WILL;
+ continue;
+
+ case WONT:
+ state = TS_WONT;
+ continue;
+
+ case DO:
+ state = TS_DO;
+ continue;
+
+ case DONT:
+ state = TS_DONT;
+ continue;
+ case EOR:
+ if (his_state_is_will(TELOPT_EOR))
+ doeof();
+ break;
+
+ /*
+ * Handle RFC 10xx Telnet linemode option additions
+ * to command stream (EOF, SUSP, ABORT).
+ */
+ case xEOF:
+ doeof();
+ break;
+
+ case SUSP:
+ sendsusp();
+ break;
+
+ case ABORT:
+ sendbrk();
+ break;
+
+ case IAC:
+ *pfrontp++ = c;
+ break;
+ }
+ state = TS_DATA;
+ break;
+
+ case TS_SB:
+ if (c == IAC) {
+ state = TS_SE;
+ } else {
+ SB_ACCUM(c);
+ }
+ break;
+
+ case TS_SE:
+ if (c != SE) {
+ if (c != IAC) {
+ /*
+ * bad form of suboption negotiation.
+ * handle it in such a way as to avoid
+ * damage to local state. Parse
+ * suboption buffer found so far,
+ * then treat remaining stream as
+ * another command sequence.
+ */
+
+ /* for DIAGNOSTICS */
+ SB_ACCUM(IAC);
+ SB_ACCUM(c);
+ subpointer -= 2;
+
+ SB_TERM();
+ suboption();
+ state = TS_IAC;
+ goto gotiac;
+ }
+ SB_ACCUM(c);
+ state = TS_SB;
+ } else {
+ /* for DIAGNOSTICS */
+ SB_ACCUM(IAC);
+ SB_ACCUM(SE);
+ subpointer -= 2;
+
+ SB_TERM();
+ suboption(); /* handle sub-option */
+ state = TS_DATA;
+ }
+ break;
+
+ case TS_WILL:
+ willoption(c);
+ state = TS_DATA;
+ continue;
+
+ case TS_WONT:
+ wontoption(c);
+ state = TS_DATA;
+ continue;
+
+ case TS_DO:
+ dooption(c);
+ state = TS_DATA;
+ continue;
+
+ case TS_DONT:
+ dontoption(c);
+ state = TS_DATA;
+ continue;
+
+ default:
+ syslog(LOG_ERR, "panic state=%d", state);
+ printf("telnetd: panic state=%d\n", state);
+ exit(1);
+ }
+ }
+} /* end of telrcv */
+
+/*
+ * The will/wont/do/dont state machines are based on Dave Borman's
+ * Telnet option processing state machine.
+ *
+ * These correspond to the following states:
+ * my_state = the last negotiated state
+ * want_state = what I want the state to go to
+ * want_resp = how many requests I have sent
+ * All state defaults are negative, and resp defaults to 0.
+ *
+ * When initiating a request to change state to new_state:
+ *
+ * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
+ * do nothing;
+ * } else {
+ * want_state = new_state;
+ * send new_state;
+ * want_resp++;
+ * }
+ *
+ * When receiving new_state:
+ *
+ * if (want_resp) {
+ * want_resp--;
+ * if (want_resp && (new_state == my_state))
+ * want_resp--;
+ * }
+ * if ((want_resp == 0) && (new_state != want_state)) {
+ * if (ok_to_switch_to new_state)
+ * want_state = new_state;
+ * else
+ * want_resp++;
+ * send want_state;
+ * }
+ * my_state = new_state;
+ *
+ * Note that new_state is implied in these functions by the function itself.
+ * will and do imply positive new_state, wont and dont imply negative.
+ *
+ * Finally, there is one catch. If we send a negative response to a
+ * positive request, my_state will be the positive while want_state will
+ * remain negative. my_state will revert to negative when the negative
+ * acknowlegment arrives from the peer. Thus, my_state generally tells
+ * us not only the last negotiated state, but also tells us what the peer
+ * wants to be doing as well. It is important to understand this difference
+ * as we may wish to be processing data streams based on our desired state
+ * (want_state) or based on what the peer thinks the state is (my_state).
+ *
+ * This all works fine because if the peer sends a positive request, the data
+ * that we receive prior to negative acknowlegment will probably be affected
+ * by the positive state, and we can process it as such (if we can; if we
+ * can't then it really doesn't matter). If it is that important, then the
+ * peer probably should be buffering until this option state negotiation
+ * is complete.
+ *
+ */
+void
+send_do(int option, int init)
+{
+ if (init) {
+ if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
+ his_want_state_is_will(option))
+ return;
+ /*
+ * Special case for TELOPT_TM: We send a DO, but pretend
+ * that we sent a DONT, so that we can send more DOs if
+ * we want to.
+ */
+ if (option == TELOPT_TM)
+ set_his_want_state_wont(option);
+ else
+ set_his_want_state_will(option);
+ do_dont_resp[option]++;
+ }
+ output_data((const char *)doopt, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send do", option));
+}
+
+void
+willoption(int option)
+{
+ int changeok = 0;
+ void (*func)(void) = 0;
+
+ /*
+ * process input from peer.
+ */
+
+ DIAG(TD_OPTIONS, printoption("td: recv will", option));
+
+ if (do_dont_resp[option]) {
+ do_dont_resp[option]--;
+ if (do_dont_resp[option] && his_state_is_will(option))
+ do_dont_resp[option]--;
+ }
+ if (do_dont_resp[option] == 0) {
+ if (his_want_state_is_wont(option)) {
+ switch (option) {
+
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryin(1);
+ set_termbuf();
+ changeok++;
+ break;
+
+ case TELOPT_ECHO:
+ /*
+ * See comments below for more info.
+ */
+ not42 = 0; /* looks like a 4.2 system */
+ break;
+
+ case TELOPT_TM:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * This telnetd implementation does not really
+ * support timing marks, it just uses them to
+ * support the kludge linemode stuff. If we
+ * receive a will or wont TM in response to our
+ * do TM request that may have been sent to
+ * determine kludge linemode support, process
+ * it, otherwise TM should get a negative
+ * response back.
+ */
+ /*
+ * Handle the linemode kludge stuff.
+ * If we are not currently supporting any
+ * linemode at all, then we assume that this
+ * is the client telling us to use kludge
+ * linemode in response to our query. Set the
+ * linemode type that is to be supported, note
+ * that the client wishes to use linemode, and
+ * eat the will TM as though it never arrived.
+ */
+ if (lmodetype < KLUDGE_LINEMODE) {
+ lmodetype = KLUDGE_LINEMODE;
+ clientstat(TELOPT_LINEMODE, WILL, 0);
+ send_wont(TELOPT_SGA, 1);
+ } else if (lmodetype == NO_AUTOKLUDGE) {
+ lmodetype = KLUDGE_OK;
+ }
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ /*
+ * We never respond to a WILL TM, and
+ * we leave the state WONT.
+ */
+ return;
+
+ case TELOPT_LFLOW:
+ /*
+ * If we are going to support flow control
+ * option, then don't worry peer that we can't
+ * change the flow control characters.
+ */
+ slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
+ slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
+ case TELOPT_TTYPE:
+ case TELOPT_SGA:
+ case TELOPT_NAWS:
+ case TELOPT_TSPEED:
+ case TELOPT_XDISPLOC:
+ case TELOPT_NEW_ENVIRON:
+ case TELOPT_OLD_ENVIRON:
+ changeok++;
+ break;
+
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+# ifdef KLUDGELINEMODE
+ /*
+ * Note client's desire to use linemode.
+ */
+ lmodetype = REAL_LINEMODE;
+# endif /* KLUDGELINEMODE */
+ func = doclientstat;
+ changeok++;
+ break;
+#endif /* LINEMODE */
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ func = auth_request;
+ changeok++;
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ func = encrypt_send_support;
+ changeok++;
+ break;
+#endif /* ENCRYPTION */
+
+ default:
+ break;
+ }
+ if (changeok) {
+ set_his_want_state_will(option);
+ send_do(option, 0);
+ } else {
+ do_dont_resp[option]++;
+ send_dont(option, 0);
+ }
+ } else {
+ /*
+ * Option processing that should happen when
+ * we receive conformation of a change in
+ * state that we had requested.
+ */
+ switch (option) {
+ case TELOPT_ECHO:
+ not42 = 0; /* looks like a 4.2 system */
+ /*
+ * Egads, he responded "WILL ECHO". Turn
+ * it off right now!
+ */
+ send_dont(option, 1);
+ /*
+ * "WILL ECHO". Kludge upon kludge!
+ * A 4.2 client is now echoing user input at
+ * the tty. This is probably undesireable and
+ * it should be stopped. The client will
+ * respond WONT TM to the DO TM that we send to
+ * check for kludge linemode. When the WONT TM
+ * arrives, linemode will be turned off and a
+ * change propogated to the pty. This change
+ * will cause us to process the new pty state
+ * in localstat(), which will notice that
+ * linemode is off and send a WILL ECHO
+ * so that we are properly in character mode and
+ * all is well.
+ */
+ break;
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+# ifdef KLUDGELINEMODE
+ /*
+ * Note client's desire to use linemode.
+ */
+ lmodetype = REAL_LINEMODE;
+# endif /* KLUDGELINEMODE */
+ func = doclientstat;
+ break;
+#endif /* LINEMODE */
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ func = auth_request;
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ func = encrypt_send_support;
+ break;
+#endif /* ENCRYPTION */
+ case TELOPT_LFLOW:
+ func = flowstat;
+ break;
+ }
+ }
+ }
+ set_his_state_will(option);
+ if (func)
+ (*func)();
+} /* end of willoption */
+
+void
+send_dont(int option, int init)
+{
+ if (init) {
+ if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
+ his_want_state_is_wont(option))
+ return;
+ set_his_want_state_wont(option);
+ do_dont_resp[option]++;
+ }
+ output_data((const char *)dont, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send dont", option));
+}
+
+void
+wontoption(int option)
+{
+ /*
+ * Process client input.
+ */
+
+ DIAG(TD_OPTIONS, printoption("td: recv wont", option));
+
+ if (do_dont_resp[option]) {
+ do_dont_resp[option]--;
+ if (do_dont_resp[option] && his_state_is_wont(option))
+ do_dont_resp[option]--;
+ }
+ if (do_dont_resp[option] == 0) {
+ if (his_want_state_is_will(option)) {
+ /* it is always ok to change to negative state */
+ switch (option) {
+ case TELOPT_ECHO:
+ not42 = 1; /* doesn't seem to be a 4.2 system */
+ break;
+
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryin(0);
+ set_termbuf();
+ break;
+
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+# ifdef KLUDGELINEMODE
+ /*
+ * If real linemode is supported, then client is
+ * asking to turn linemode off.
+ */
+ if (lmodetype != REAL_LINEMODE)
+ break;
+ lmodetype = KLUDGE_LINEMODE;
+# endif /* KLUDGELINEMODE */
+ clientstat(TELOPT_LINEMODE, WONT, 0);
+ break;
+#endif /* LINEMODE */
+
+ case TELOPT_TM:
+ /*
+ * If we get a WONT TM, and had sent a DO TM,
+ * don't respond with a DONT TM, just leave it
+ * as is. Short circut the state machine to
+ * achive this.
+ */
+ set_his_want_state_wont(TELOPT_TM);
+ return;
+
+ case TELOPT_LFLOW:
+ /*
+ * If we are not going to support flow control
+ * option, then let peer know that we can't
+ * change the flow control characters.
+ */
+ slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
+ slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ auth_finished(0, AUTH_REJECT);
+ break;
+#endif
+
+ /*
+ * For options that we might spin waiting for
+ * sub-negotiation, if the client turns off the
+ * option rather than responding to the request,
+ * we have to treat it here as if we got a response
+ * to the sub-negotiation, (by updating the timers)
+ * so that we'll break out of the loop.
+ */
+ case TELOPT_TTYPE:
+ settimer(ttypesubopt);
+ break;
+
+ case TELOPT_TSPEED:
+ settimer(tspeedsubopt);
+ break;
+
+ case TELOPT_XDISPLOC:
+ settimer(xdisplocsubopt);
+ break;
+
+ case TELOPT_OLD_ENVIRON:
+ settimer(oenvironsubopt);
+ break;
+
+ case TELOPT_NEW_ENVIRON:
+ settimer(environsubopt);
+ break;
+
+ default:
+ break;
+ }
+ set_his_want_state_wont(option);
+ if (his_state_is_will(option))
+ send_dont(option, 0);
+ } else {
+ switch (option) {
+ case TELOPT_TM:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ if (lmodetype < NO_AUTOKLUDGE) {
+ lmodetype = NO_LINEMODE;
+ clientstat(TELOPT_LINEMODE, WONT, 0);
+ send_will(TELOPT_SGA, 1);
+ send_will(TELOPT_ECHO, 1);
+ }
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ auth_finished(0, AUTH_REJECT);
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ }
+ set_his_state_wont(option);
+
+} /* end of wontoption */
+
+void
+send_will(int option, int init)
+{
+ if (init) {
+ if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
+ my_want_state_is_will(option))
+ return;
+ set_my_want_state_will(option);
+ will_wont_resp[option]++;
+ }
+ output_data((const char *)will, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send will", option));
+}
+
+#if !defined(LINEMODE) || !defined(KLUDGELINEMODE)
+/*
+ * When we get a DONT SGA, we will try once to turn it
+ * back on. If the other side responds DONT SGA, we
+ * leave it at that. This is so that when we talk to
+ * clients that understand KLUDGELINEMODE but not LINEMODE,
+ * we'll keep them in char-at-a-time mode.
+ */
+int turn_on_sga = 0;
+#endif
+
+void
+dooption(int option)
+{
+ int changeok = 0;
+
+ /*
+ * Process client input.
+ */
+
+ DIAG(TD_OPTIONS, printoption("td: recv do", option));
+
+ if (will_wont_resp[option]) {
+ will_wont_resp[option]--;
+ if (will_wont_resp[option] && my_state_is_will(option))
+ will_wont_resp[option]--;
+ }
+ if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
+ switch (option) {
+ case TELOPT_ECHO:
+#ifdef LINEMODE
+# ifdef KLUDGELINEMODE
+ if (lmodetype == NO_LINEMODE)
+# else
+ if (his_state_is_wont(TELOPT_LINEMODE))
+# endif
+#endif
+ {
+ init_termbuf();
+ tty_setecho(1);
+ set_termbuf();
+ }
+ changeok++;
+ break;
+
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryout(1);
+ set_termbuf();
+ changeok++;
+ break;
+
+ case TELOPT_SGA:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * If kludge linemode is in use, then we must
+ * process an incoming do SGA for linemode
+ * purposes.
+ */
+ if (lmodetype == KLUDGE_LINEMODE) {
+ /*
+ * Receipt of "do SGA" in kludge
+ * linemode is the peer asking us to
+ * turn off linemode. Make note of
+ * the request.
+ */
+ clientstat(TELOPT_LINEMODE, WONT, 0);
+ /*
+ * If linemode did not get turned off
+ * then don't tell peer that we did.
+ * Breaking here forces a wont SGA to
+ * be returned.
+ */
+ if (linemode)
+ break;
+ }
+#else
+ turn_on_sga = 0;
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ changeok++;
+ break;
+
+ case TELOPT_STATUS:
+ changeok++;
+ break;
+
+ case TELOPT_TM:
+ /*
+ * Special case for TM. We send a WILL, but
+ * pretend we sent a WONT.
+ */
+ send_will(option, 0);
+ set_my_want_state_wont(option);
+ set_my_state_wont(option);
+ return;
+
+ case TELOPT_LOGOUT:
+ /*
+ * When we get a LOGOUT option, respond
+ * with a WILL LOGOUT, make sure that
+ * it gets written out to the network,
+ * and then just go away...
+ */
+ set_my_want_state_will(TELOPT_LOGOUT);
+ send_will(TELOPT_LOGOUT, 0);
+ set_my_state_will(TELOPT_LOGOUT);
+ (void)netflush();
+ cleanup(0);
+ /* NOT REACHED */
+ break;
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ changeok++;
+ break;
+#endif /* ENCRYPTION */
+ case TELOPT_LINEMODE:
+ case TELOPT_TTYPE:
+ case TELOPT_NAWS:
+ case TELOPT_TSPEED:
+ case TELOPT_LFLOW:
+ case TELOPT_XDISPLOC:
+#ifdef TELOPT_ENVIRON
+ case TELOPT_NEW_ENVIRON:
+#endif
+ case TELOPT_OLD_ENVIRON:
+ default:
+ break;
+ }
+ if (changeok) {
+ set_my_want_state_will(option);
+ send_will(option, 0);
+ } else {
+ will_wont_resp[option]++;
+ send_wont(option, 0);
+ }
+ }
+ set_my_state_will(option);
+
+} /* end of dooption */
+
+void
+send_wont(int option, int init)
+{
+ if (init) {
+ if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
+ my_want_state_is_wont(option))
+ return;
+ set_my_want_state_wont(option);
+ will_wont_resp[option]++;
+ }
+ output_data((const char *)wont, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send wont", option));
+}
+
+void
+dontoption(int option)
+{
+ /*
+ * Process client input.
+ */
+
+
+ DIAG(TD_OPTIONS, printoption("td: recv dont", option));
+
+ if (will_wont_resp[option]) {
+ will_wont_resp[option]--;
+ if (will_wont_resp[option] && my_state_is_wont(option))
+ will_wont_resp[option]--;
+ }
+ if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
+ switch (option) {
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryout(0);
+ set_termbuf();
+ break;
+
+ case TELOPT_ECHO: /* we should stop echoing */
+#ifdef LINEMODE
+# ifdef KLUDGELINEMODE
+ if ((lmodetype != REAL_LINEMODE) &&
+ (lmodetype != KLUDGE_LINEMODE))
+# else
+ if (his_state_is_wont(TELOPT_LINEMODE))
+# endif
+#endif
+ {
+ init_termbuf();
+ tty_setecho(0);
+ set_termbuf();
+ }
+ break;
+
+ case TELOPT_SGA:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * If kludge linemode is in use, then we
+ * must process an incoming do SGA for
+ * linemode purposes.
+ */
+ if ((lmodetype == KLUDGE_LINEMODE) ||
+ (lmodetype == KLUDGE_OK)) {
+ /*
+ * The client is asking us to turn
+ * linemode on.
+ */
+ lmodetype = KLUDGE_LINEMODE;
+ clientstat(TELOPT_LINEMODE, WILL, 0);
+ /*
+ * If we did not turn line mode on,
+ * then what do we say? Will SGA?
+ * This violates design of telnet.
+ * Gross. Very Gross.
+ */
+ }
+ break;
+#else
+ set_my_want_state_wont(option);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
+ set_my_state_wont(option);
+ if (turn_on_sga ^= 1)
+ send_will(option, 1);
+ return;
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+ default:
+ break;
+ }
+
+ set_my_want_state_wont(option);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
+ }
+ set_my_state_wont(option);
+
+} /* end of dontoption */
+
+#ifdef ENV_HACK
+int env_ovar = -1;
+int env_ovalue = -1;
+#else /* ENV_HACK */
+# define env_ovar OLD_ENV_VAR
+# define env_ovalue OLD_ENV_VALUE
+#endif /* ENV_HACK */
+
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ * Currently we recognize:
+ *
+ * Terminal type is
+ * Linemode
+ * Window size
+ * Terminal speed
+ */
+void
+suboption(void)
+{
+ int subchar;
+
+ DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
+
+ subchar = SB_GET();
+ switch (subchar) {
+ case TELOPT_TSPEED: {
+ int xspeed, rspeed;
+
+ if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */
+ break;
+
+ settimer(tspeedsubopt);
+
+ if (SB_EOF() || SB_GET() != TELQUAL_IS)
+ return;
+
+ xspeed = atoi((char *)subpointer);
+
+ while (SB_GET() != ',' && !SB_EOF());
+ if (SB_EOF())
+ return;
+
+ rspeed = atoi((char *)subpointer);
+ clientstat(TELOPT_TSPEED, xspeed, rspeed);
+
+ break;
+
+ } /* end of case TELOPT_TSPEED */
+
+ case TELOPT_TTYPE: { /* Yaaaay! */
+ static char terminalname[41];
+
+ if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */
+ break;
+ settimer(ttypesubopt);
+
+ if (SB_EOF() || SB_GET() != TELQUAL_IS) {
+ return; /* ??? XXX but, this is the most robust */
+ }
+
+ terminaltype = terminalname;
+
+ while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
+ !SB_EOF()) {
+ int c;
+
+ c = SB_GET();
+ if (isupper(c)) {
+ c = tolower(c);
+ }
+ *terminaltype++ = c; /* accumulate name */
+ }
+ *terminaltype = 0;
+ terminaltype = terminalname;
+ break;
+ } /* end of case TELOPT_TTYPE */
+
+ case TELOPT_NAWS: {
+ int xwinsize, ywinsize;
+
+ if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */
+ break;
+
+ if (SB_EOF())
+ return;
+ xwinsize = SB_GET() << 8;
+ if (SB_EOF())
+ return;
+ xwinsize |= SB_GET();
+ if (SB_EOF())
+ return;
+ ywinsize = SB_GET() << 8;
+ if (SB_EOF())
+ return;
+ ywinsize |= SB_GET();
+ clientstat(TELOPT_NAWS, xwinsize, ywinsize);
+
+ break;
+
+ } /* end of case TELOPT_NAWS */
+
+#ifdef LINEMODE
+ case TELOPT_LINEMODE: {
+ int request;
+
+ if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
+ break;
+ /*
+ * Process linemode suboptions.
+ */
+ if (SB_EOF())
+ break; /* garbage was sent */
+ request = SB_GET(); /* get will/wont */
+
+ if (SB_EOF())
+ break; /* another garbage check */
+
+ if (request == LM_SLC) { /* SLC is not preceded by WILL or WONT */
+ /*
+ * Process suboption buffer of slc's
+ */
+ start_slc(1);
+ do_opt_slc(subpointer, subend - subpointer);
+ (void) end_slc(0);
+ break;
+ } else if (request == LM_MODE) {
+ if (SB_EOF())
+ return;
+ useeditmode = SB_GET(); /* get mode flag */
+ clientstat(LM_MODE, 0, 0);
+ break;
+ }
+
+ if (SB_EOF())
+ break;
+ switch (SB_GET()) { /* what suboption? */
+ case LM_FORWARDMASK:
+ /*
+ * According to spec, only server can send request for
+ * forwardmask, and client can only return a positive response.
+ * So don't worry about it.
+ */
+
+ default:
+ break;
+ }
+ break;
+ } /* end of case TELOPT_LINEMODE */
+#endif
+ case TELOPT_STATUS: {
+ int mode;
+
+ if (SB_EOF())
+ break;
+ mode = SB_GET();
+ switch (mode) {
+ case TELQUAL_SEND:
+ if (my_state_is_will(TELOPT_STATUS))
+ send_status();
+ break;
+
+ case TELQUAL_IS:
+ break;
+
+ default:
+ break;
+ }
+ break;
+ } /* end of case TELOPT_STATUS */
+
+ case TELOPT_XDISPLOC: {
+ if (SB_EOF() || SB_GET() != TELQUAL_IS)
+ return;
+ settimer(xdisplocsubopt);
+ subpointer[SB_LEN()] = '\0';
+ (void)setenv("DISPLAY", (char *)subpointer, 1);
+ break;
+ } /* end of case TELOPT_XDISPLOC */
+
+#ifdef TELOPT_NEW_ENVIRON
+ case TELOPT_NEW_ENVIRON:
+#endif
+ case TELOPT_OLD_ENVIRON: {
+ int c;
+ char *cp, *varp, *valp;
+
+ if (SB_EOF())
+ return;
+ c = SB_GET();
+ if (c == TELQUAL_IS) {
+ if (subchar == TELOPT_OLD_ENVIRON)
+ settimer(oenvironsubopt);
+ else
+ settimer(environsubopt);
+ } else if (c != TELQUAL_INFO) {
+ return;
+ }
+
+#ifdef TELOPT_NEW_ENVIRON
+ if (subchar == TELOPT_NEW_ENVIRON) {
+ while (!SB_EOF()) {
+ c = SB_GET();
+ if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
+ break;
+ }
+ } else
+#endif
+ {
+#ifdef ENV_HACK
+ /*
+ * We only want to do this if we haven't already decided
+ * whether or not the other side has its VALUE and VAR
+ * reversed.
+ */
+ if (env_ovar < 0) {
+ int last = -1; /* invalid value */
+ int empty = 0;
+ int got_var = 0, got_value = 0, got_uservar = 0;
+
+ /*
+ * The other side might have its VALUE and VAR values
+ * reversed. To be interoperable, we need to determine
+ * which way it is. If the first recognized character
+ * is a VAR or VALUE, then that will tell us what
+ * type of client it is. If the fist recognized
+ * character is a USERVAR, then we continue scanning
+ * the suboption looking for two consecutive
+ * VAR or VALUE fields. We should not get two
+ * consecutive VALUE fields, so finding two
+ * consecutive VALUE or VAR fields will tell us
+ * what the client is.
+ */
+ SB_SAVE();
+ while (!SB_EOF()) {
+ c = SB_GET();
+ switch(c) {
+ case OLD_ENV_VAR:
+ if (last < 0 || last == OLD_ENV_VAR
+ || (empty && (last == OLD_ENV_VALUE)))
+ goto env_ovar_ok;
+ got_var++;
+ last = OLD_ENV_VAR;
+ break;
+ case OLD_ENV_VALUE:
+ if (last < 0 || last == OLD_ENV_VALUE
+ || (empty && (last == OLD_ENV_VAR)))
+ goto env_ovar_wrong;
+ got_value++;
+ last = OLD_ENV_VALUE;
+ break;
+ case ENV_USERVAR:
+ /* count strings of USERVAR as one */
+ if (last != ENV_USERVAR)
+ got_uservar++;
+ if (empty) {
+ if (last == OLD_ENV_VALUE)
+ goto env_ovar_ok;
+ if (last == OLD_ENV_VAR)
+ goto env_ovar_wrong;
+ }
+ last = ENV_USERVAR;
+ break;
+ case ENV_ESC:
+ if (!SB_EOF())
+ c = SB_GET();
+ /* FALLTHROUGH */
+ default:
+ empty = 0;
+ continue;
+ }
+ empty = 1;
+ }
+ if (empty) {
+ if (last == OLD_ENV_VALUE)
+ goto env_ovar_ok;
+ if (last == OLD_ENV_VAR)
+ goto env_ovar_wrong;
+ }
+ /*
+ * Ok, the first thing was a USERVAR, and there
+ * are not two consecutive VAR or VALUE commands,
+ * and none of the VAR or VALUE commands are empty.
+ * If the client has sent us a well-formed option,
+ * then the number of VALUEs received should always
+ * be less than or equal to the number of VARs and
+ * USERVARs received.
+ *
+ * If we got exactly as many VALUEs as VARs and
+ * USERVARs, the client has the same definitions.
+ *
+ * If we got exactly as many VARs as VALUEs and
+ * USERVARS, the client has reversed definitions.
+ */
+ if (got_uservar + got_var == got_value) {
+ env_ovar_ok:
+ env_ovar = OLD_ENV_VAR;
+ env_ovalue = OLD_ENV_VALUE;
+ } else if (got_uservar + got_value == got_var) {
+ env_ovar_wrong:
+ env_ovar = OLD_ENV_VALUE;
+ env_ovalue = OLD_ENV_VAR;
+ DIAG(TD_OPTIONS,
+ output_data("ENVIRON VALUE and VAR are reversed!\r\n"));
+
+ }
+ }
+ SB_RESTORE();
+#endif
+
+ while (!SB_EOF()) {
+ c = SB_GET();
+ if ((c == env_ovar) || (c == ENV_USERVAR))
+ break;
+ }
+ }
+
+ if (SB_EOF())
+ return;
+
+ cp = varp = (char *)subpointer;
+ valp = 0;
+
+ while (!SB_EOF()) {
+ c = SB_GET();
+ if (subchar == TELOPT_OLD_ENVIRON) {
+ if (c == env_ovar)
+ c = NEW_ENV_VAR;
+ else if (c == env_ovalue)
+ c = NEW_ENV_VALUE;
+ }
+ switch (c) {
+
+ case NEW_ENV_VALUE:
+ *cp = '\0';
+ cp = valp = (char *)subpointer;
+ break;
+
+ case NEW_ENV_VAR:
+ case ENV_USERVAR:
+ *cp = '\0';
+ if (valp)
+ (void)setenv(varp, valp, 1);
+ else
+ unsetenv(varp);
+ cp = varp = (char *)subpointer;
+ valp = 0;
+ break;
+
+ case ENV_ESC:
+ if (SB_EOF())
+ break;
+ c = SB_GET();
+ /* FALLTHROUGH */
+ default:
+ *cp++ = c;
+ break;
+ }
+ }
+ *cp = '\0';
+ if (valp)
+ (void)setenv(varp, valp, 1);
+ else
+ unsetenv(varp);
+ break;
+ } /* end of case TELOPT_NEW_ENVIRON */
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (SB_EOF())
+ break;
+ switch(SB_GET()) {
+ case TELQUAL_SEND:
+ case TELQUAL_REPLY:
+ /*
+ * These are sent by us and cannot be sent by
+ * the client.
+ */
+ break;
+ case TELQUAL_IS:
+ auth_is(subpointer, SB_LEN());
+ break;
+ case TELQUAL_NAME:
+ auth_name(subpointer, SB_LEN());
+ break;
+ }
+ break;
+#endif
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ if (SB_EOF())
+ break;
+ switch(SB_GET()) {
+ case ENCRYPT_SUPPORT:
+ encrypt_support(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_IS:
+ encrypt_is(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REPLY:
+ encrypt_reply(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_START:
+ encrypt_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_END:
+ encrypt_end();
+ break;
+ case ENCRYPT_REQSTART:
+ encrypt_request_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQEND:
+ /*
+ * We can always send an REQEND so that we cannot
+ * get stuck encrypting. We should only get this
+ * if we have been able to get in the correct mode
+ * anyhow.
+ */
+ encrypt_request_end();
+ break;
+ case ENCRYPT_ENC_KEYID:
+ encrypt_enc_keyid(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_DEC_KEYID:
+ encrypt_dec_keyid(subpointer, SB_LEN());
+ break;
+ default:
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+
+ default:
+ break;
+ } /* end of switch */
+
+} /* end of suboption */
+
+static void
+doclientstat(void)
+{
+ clientstat(TELOPT_LINEMODE, WILL, 0);
+}
+
+#define ADD(c) *ncp++ = c
+#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
+void
+send_status(void)
+{
+ unsigned char statusbuf[256];
+ unsigned char *ncp;
+ unsigned char i;
+
+ ncp = statusbuf;
+
+ netflush(); /* get rid of anything waiting to go out */
+
+ ADD(IAC);
+ ADD(SB);
+ ADD(TELOPT_STATUS);
+ ADD(TELQUAL_IS);
+
+ /*
+ * We check the want_state rather than the current state,
+ * because if we received a DO/WILL for an option that we
+ * don't support, and the other side didn't send a DONT/WONT
+ * in response to our WONT/DONT, then the "state" will be
+ * WILL/DO, and the "want_state" will be WONT/DONT. We
+ * need to go by the latter.
+ */
+ for (i = 0; i < (unsigned char)NTELOPTS; i++) {
+ if (my_want_state_is_will(i)) {
+ ADD(WILL);
+ ADD_DATA(i);
+ if (i == IAC)
+ ADD(IAC);
+ }
+ if (his_want_state_is_will(i)) {
+ ADD(DO);
+ ADD_DATA(i);
+ if (i == IAC)
+ ADD(IAC);
+ }
+ }
+
+ if (his_want_state_is_will(TELOPT_LFLOW)) {
+ ADD(SB);
+ ADD(TELOPT_LFLOW);
+ if (flowmode) {
+ ADD(LFLOW_ON);
+ } else {
+ ADD(LFLOW_OFF);
+ }
+ ADD(SE);
+
+ if (restartany >= 0) {
+ ADD(SB);
+ ADD(TELOPT_LFLOW);
+ if (restartany) {
+ ADD(LFLOW_RESTART_ANY);
+ } else {
+ ADD(LFLOW_RESTART_XON);
+ }
+ ADD(SE);
+ }
+ }
+
+#ifdef LINEMODE
+ if (his_want_state_is_will(TELOPT_LINEMODE)) {
+ unsigned char *cp, *cpe;
+ int len;
+
+ ADD(SB);
+ ADD(TELOPT_LINEMODE);
+ ADD(LM_MODE);
+ ADD_DATA(editmode);
+ ADD(SE);
+
+ ADD(SB);
+ ADD(TELOPT_LINEMODE);
+ ADD(LM_SLC);
+ start_slc(0);
+ send_slc();
+ len = end_slc(&cp);
+ for (cpe = cp + len; cp < cpe; cp++)
+ ADD_DATA(*cp);
+ ADD(SE);
+ }
+#endif /* LINEMODE */
+
+ ADD(IAC);
+ ADD(SE);
+
+ output_datalen((const char *)statusbuf, ncp - statusbuf);
+ netflush(); /* Send it on its way */
+
+ DIAG(TD_OPTIONS,
+ {printsub('>', statusbuf, ncp - statusbuf); netflush();});
+}
+
+/*
+ * This function appends data to nfrontp and advances nfrontp.
+ * Returns the number of characters written altogether (the
+ * buffer may have been flushed in the process).
+ */
+
+int
+output_data(const char *format, ...)
+{
+ va_list args;
+ int len;
+ char *buf;
+
+ va_start(args, format);
+ if ((len = vasprintf(&buf, format, args)) == -1)
+ return -1;
+ output_datalen(buf, len);
+ va_end(args);
+ free(buf);
+ return (len);
+}
+
+void
+output_datalen(const char *buf, int len)
+{
+ int remaining, copied;
+
+ remaining = BUFSIZ - (nfrontp - netobuf);
+ while (len > 0) {
+ /* Free up enough space if the room is too low*/
+ if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
+ netflush();
+ remaining = BUFSIZ - (nfrontp - netobuf);
+ }
+
+ /* Copy out as much as will fit */
+ copied = remaining > len ? len : remaining;
+ memmove(nfrontp, buf, copied);
+ nfrontp += copied;
+ len -= copied;
+ remaining -= copied;
+ buf += copied;
+ }
+ return;
+}
diff --git a/remote_cmds/telnetd.tproj/strlcpy.c b/remote_cmds/telnetd.tproj/strlcpy.c
new file mode 100644
index 0000000..9b39b41
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/strlcpy.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.3 2001/05/24 08:47:41 obrien Exp $";
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/remote_cmds/telnetd.tproj/sys_term.c b/remote_cmds/telnetd.tproj/sys_term.c
new file mode 100644
index 0000000..23da55b
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/sys_term.c
@@ -0,0 +1,1410 @@
+ /*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/sys_term.c,v 1.18 2003/05/04 02:54:49 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/tty.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <stdlib.h>
+#ifndef __APPLE__
+#include <utmp.h>
+#endif
+
+#include "telnetd.h"
+#include "pathnames.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+
+int cleanopen(char *);
+void scrub_env(void);
+
+#ifdef UTMPX
+#include <utmpx.h>
+struct utmpx wtmp;
+#endif /* UTMPX */
+
+#ifndef NO_UTMP
+# include <utmp.h>
+struct utmp wtmp;
+
+#ifdef _PATH_WTMP
+char wtmpf[] = _PATH_WTMP;
+#else
+char wtmpf[] = "/var/log/wtmp";
+#endif
+#ifdef _PATH_UTMP
+char utmpf[] = _PATH_UTMP;
+#else
+char utmpf[] = "/var/run/utmp";
+#endif
+#endif /* NO_UTMP */
+
+char *envinit[3];
+extern char **environ;
+
+#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
+#define SCMPN(a, b) strncmp(a, b, sizeof(a))
+
+#ifdef t_erase
+#undef t_erase
+#undef t_kill
+#undef t_intrc
+#undef t_quitc
+#undef t_startc
+#undef t_stopc
+#undef t_eofc
+#undef t_brkc
+#undef t_suspc
+#undef t_dsuspc
+#undef t_rprntc
+#undef t_flushc
+#undef t_werasc
+#undef t_lnextc
+#endif
+
+#ifndef USE_TERMIO
+struct termbuf {
+ struct sgttyb sg;
+ struct tchars tc;
+ struct ltchars ltc;
+ int state;
+ int lflags;
+} termbuf, termbuf2;
+# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
+# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
+# define cfgetospeed(tp) (tp)->sg.sg_ospeed
+# define cfgetispeed(tp) (tp)->sg.sg_ispeed
+#else /* USE_TERMIO */
+# ifndef TCSANOW
+# ifdef TCSETS
+# define TCSANOW TCSETS
+# define TCSADRAIN TCSETSW
+# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+# else
+# ifdef TCSETA
+# define TCSANOW TCSETA
+# define TCSADRAIN TCSETAW
+# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
+# else
+# define TCSANOW TIOCSETA
+# define TCSADRAIN TIOCSETAW
+# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
+# endif
+# endif
+# define tcsetattr(f, a, t) ioctl(f, a, t)
+# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
+ (tp)->c_cflag |= (val)
+# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
+# ifdef CIBAUD
+# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
+ (tp)->c_cflag |= ((val)<<IBSHIFT)
+# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
+# else
+# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
+ (tp)->c_cflag |= (val)
+# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
+# endif
+# endif /* TCSANOW */
+struct termios termbuf, termbuf2; /* pty control structure */
+#endif /* USE_TERMIO */
+
+#include <sys/types.h>
+#ifndef __APPLE__
+#include <libutil.h>
+#endif
+
+int cleanopen(char *);
+void scrub_env(void);
+static char **addarg(char **, const char *);
+
+/*
+ * init_termbuf()
+ * copy_termbuf(cp)
+ * set_termbuf()
+ *
+ * These three routines are used to get and set the "termbuf" structure
+ * to and from the kernel. init_termbuf() gets the current settings.
+ * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
+ * set_termbuf() writes the structure into the kernel.
+ */
+
+void
+init_termbuf(void)
+{
+#ifndef USE_TERMIO
+ if (ioctl(spty, TIOCGETP, (char *)&termbuf.sg) == -1)
+ perror("ioctl TIOCGETP");
+ if (ioctl(spty, TIOCGETC, (char *)&termbuf.tc) == -1)
+ perror("ioctl TIOCGETC");
+ if (ioctl(spty, TIOCGLTC, (char *)&termbuf.ltc) == -1)
+ perror("ioctl TIOCGLTC");
+# ifdef TIOCGSTATE
+ if (-1 == ioctl(spty, TIOCGSTATE, (char *)&termbuf.state))
+ perror("ioctl TIOCGSTATE");
+# endif
+#else
+ if (-1 == tcgetattr(spty, &termbuf))
+ perror("tcgetattr");
+#endif
+ termbuf2 = termbuf;
+}
+
+#if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
+void
+copy_termbuf(char *cp, size_t len)
+{
+ if (len > sizeof(termbuf))
+ len = sizeof(termbuf);
+ memmove((char *)&termbuf, cp, len);
+ termbuf2 = termbuf;
+}
+#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
+
+void
+set_termbuf(void)
+{
+ /*
+ * Only make the necessary changes.
+ */
+#ifndef USE_TERMIO
+ if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
+ sizeof(termbuf.sg))) {
+ if (-1 == ioctl(spty, TIOCSETN, (char *)&termbuf.sg))
+ perror("ioctl TIOSETN");
+ }
+ if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
+ sizeof(termbuf.tc))) {
+ if (-1 == ioctl(spty, TIOCSETC, (char *)&termbuf.tc))
+ perror("ioctl TIOSETC");
+ }
+ if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+ sizeof(termbuf.ltc))) {
+ if (-1 == ioctl(spty, TIOCSLTC, (char *)&termbuf.ltc))
+ perror("ioctl TIOCSLTC");
+ }
+ if (termbuf.lflags != termbuf2.lflags) {
+ (void) ioctl(spty, TIOCLSET, (char *)&termbuf.lflags);
+ }
+#else /* USE_TERMIO */
+ if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) {
+ if (-1 == tcsetattr(spty, TCSANOW, &termbuf))
+ perror("tcsetattr");
+ }
+#endif /* USE_TERMIO */
+}
+
+
+/*
+ * spcset(func, valp, valpp)
+ *
+ * This function takes various special characters (func), and
+ * sets *valp to the current value of that character, and
+ * *valpp to point to where in the "termbuf" structure that
+ * value is kept.
+ *
+ * It returns the SLC_ level of support for this function.
+ */
+
+#ifndef USE_TERMIO
+int
+spcset(int func, cc_t *valp, cc_t **valpp)
+{
+ switch(func) {
+ case SLC_EOF:
+ *valp = termbuf.tc.t_eofc;
+ *valpp = (cc_t *)&termbuf.tc.t_eofc;
+ return(SLC_VARIABLE);
+ case SLC_EC:
+ *valp = termbuf.sg.sg_erase;
+ *valpp = (cc_t *)&termbuf.sg.sg_erase;
+ return(SLC_VARIABLE);
+ case SLC_EL:
+ *valp = termbuf.sg.sg_kill;
+ *valpp = (cc_t *)&termbuf.sg.sg_kill;
+ return(SLC_VARIABLE);
+ case SLC_IP:
+ *valp = termbuf.tc.t_intrc;
+ *valpp = (cc_t *)&termbuf.tc.t_intrc;
+ return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_ABORT:
+ *valp = termbuf.tc.t_quitc;
+ *valpp = (cc_t *)&termbuf.tc.t_quitc;
+ return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_XON:
+ *valp = termbuf.tc.t_startc;
+ *valpp = (cc_t *)&termbuf.tc.t_startc;
+ return(SLC_VARIABLE);
+ case SLC_XOFF:
+ *valp = termbuf.tc.t_stopc;
+ *valpp = (cc_t *)&termbuf.tc.t_stopc;
+ return(SLC_VARIABLE);
+ case SLC_AO:
+ *valp = termbuf.ltc.t_flushc;
+ *valpp = (cc_t *)&termbuf.ltc.t_flushc;
+ return(SLC_VARIABLE);
+ case SLC_SUSP:
+ *valp = termbuf.ltc.t_suspc;
+ *valpp = (cc_t *)&termbuf.ltc.t_suspc;
+ return(SLC_VARIABLE);
+ case SLC_EW:
+ *valp = termbuf.ltc.t_werasc;
+ *valpp = (cc_t *)&termbuf.ltc.t_werasc;
+ return(SLC_VARIABLE);
+ case SLC_RP:
+ *valp = termbuf.ltc.t_rprntc;
+ *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
+ return(SLC_VARIABLE);
+ case SLC_LNEXT:
+ *valp = termbuf.ltc.t_lnextc;
+ *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
+ return(SLC_VARIABLE);
+ case SLC_FORW1:
+ *valp = termbuf.tc.t_brkc;
+ *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
+ return(SLC_VARIABLE);
+ case SLC_BRK:
+ case SLC_SYNCH:
+ case SLC_AYT:
+ case SLC_EOR:
+ *valp = (cc_t)0;
+ *valpp = (cc_t *)0;
+ return(SLC_DEFAULT);
+ default:
+ *valp = (cc_t)0;
+ *valpp = (cc_t *)0;
+ return(SLC_NOSUPPORT);
+ }
+}
+
+#else /* USE_TERMIO */
+
+
+#define setval(a, b) *valp = termbuf.c_cc[a]; \
+ *valpp = &termbuf.c_cc[a]; \
+ return(b);
+#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
+
+int
+spcset(int func, cc_t *valp, cc_t **valpp)
+{
+ switch(func) {
+ case SLC_EOF:
+ setval(VEOF, SLC_VARIABLE);
+ case SLC_EC:
+ setval(VERASE, SLC_VARIABLE);
+ case SLC_EL:
+ setval(VKILL, SLC_VARIABLE);
+ case SLC_IP:
+ setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_ABORT:
+ setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_XON:
+#ifdef VSTART
+ setval(VSTART, SLC_VARIABLE);
+#else
+ defval(0x13);
+#endif
+ case SLC_XOFF:
+#ifdef VSTOP
+ setval(VSTOP, SLC_VARIABLE);
+#else
+ defval(0x11);
+#endif
+ case SLC_EW:
+#ifdef VWERASE
+ setval(VWERASE, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+ case SLC_RP:
+#ifdef VREPRINT
+ setval(VREPRINT, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+ case SLC_LNEXT:
+#ifdef VLNEXT
+ setval(VLNEXT, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+ case SLC_AO:
+#if !defined(VDISCARD) && defined(VFLUSHO)
+# define VDISCARD VFLUSHO
+#endif
+#ifdef VDISCARD
+ setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
+#else
+ defval(0);
+#endif
+ case SLC_SUSP:
+#ifdef VSUSP
+ setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
+#else
+ defval(0);
+#endif
+#ifdef VEOL
+ case SLC_FORW1:
+ setval(VEOL, SLC_VARIABLE);
+#endif
+#ifdef VEOL2
+ case SLC_FORW2:
+ setval(VEOL2, SLC_VARIABLE);
+#endif
+ case SLC_AYT:
+#ifdef VSTATUS
+ setval(VSTATUS, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+
+ case SLC_BRK:
+ case SLC_SYNCH:
+ case SLC_EOR:
+ defval(0);
+
+ default:
+ *valp = 0;
+ *valpp = 0;
+ return(SLC_NOSUPPORT);
+ }
+}
+#endif /* USE_TERMIO */
+
+/*
+ * getpty()
+ *
+ * Allocate a pty. As a side effect, the external character
+ * array "line" contains the name of the slave side.
+ *
+ * Returns the file descriptor of the opened pty.
+ */
+char alpha[] = "0123456789abcdefghijklmnopqrstuv";
+char line[16];
+
+int
+getpty(int *ptynum __unused, int *slavepty)
+{
+ int p;
+#ifdef __APPLE__
+ // rdar://problem/5169227
+ p = open("/dev/ptmx", 2);
+ if (p >= 0) {
+ grantpt(p);
+ unlockpt(p);
+ strcpy(line, ptsname(p));
+ *slavepty = cleanopen(line);
+ return(p);
+ }
+
+#else /* !__APPLE__ */
+ const char *cp;
+ char *p1, *p2;
+ int i;
+
+ (void) strcpy(line, _PATH_DEV);
+ (void) strcat(line, "ptyXX");
+ p1 = &line[8];
+ p2 = &line[9];
+
+ for (cp = "pqrsPQRS"; *cp; cp++) {
+ struct stat stb;
+
+ *p1 = *cp;
+ *p2 = '0';
+ /*
+ * This stat() check is just to keep us from
+ * looping through all 256 combinations if there
+ * aren't that many ptys available.
+ */
+ if (stat(line, &stb) < 0)
+ break;
+ for (i = 0; i < 32; i++) {
+ *p2 = alpha[i];
+ p = open(line, 2);
+ if (p > 0) {
+ line[5] = 't';
+ chown(line, 0, 0);
+ chmod(line, 0600);
+ return(p);
+ }
+ }
+ }
+#endif /* __APPLE__ */
+ return(-1);
+}
+
+#ifdef LINEMODE
+/*
+ * tty_flowmode() Find out if flow control is enabled or disabled.
+ * tty_linemode() Find out if linemode (external processing) is enabled.
+ * tty_setlinemod(on) Turn on/off linemode.
+ * tty_isecho() Find out if echoing is turned on.
+ * tty_setecho(on) Enable/disable character echoing.
+ * tty_israw() Find out if terminal is in RAW mode.
+ * tty_binaryin(on) Turn on/off BINARY on input.
+ * tty_binaryout(on) Turn on/off BINARY on output.
+ * tty_isediting() Find out if line editing is enabled.
+ * tty_istrapsig() Find out if signal trapping is enabled.
+ * tty_setedit(on) Turn on/off line editing.
+ * tty_setsig(on) Turn on/off signal trapping.
+ * tty_issofttab() Find out if tab expansion is enabled.
+ * tty_setsofttab(on) Turn on/off soft tab expansion.
+ * tty_islitecho() Find out if typed control chars are echoed literally
+ * tty_setlitecho() Turn on/off literal echo of control chars
+ * tty_tspeed(val) Set transmit speed to val.
+ * tty_rspeed(val) Set receive speed to val.
+ */
+
+
+int
+tty_linemode(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.state & TS_EXTPROC);
+#else
+ return(termbuf.c_lflag & EXTPROC);
+#endif
+}
+
+void
+tty_setlinemode(int on)
+{
+#ifdef TIOCEXT
+ set_termbuf();
+ if (-1 == ioctl(spty, TIOCEXT, (char *)&on))
+ perror("ioctl TIOCEXT");
+ init_termbuf();
+#else /* !TIOCEXT */
+# ifdef EXTPROC
+ if (on)
+ termbuf.c_lflag |= EXTPROC;
+ else
+ termbuf.c_lflag &= ~EXTPROC;
+# endif
+#endif /* TIOCEXT */
+}
+#endif /* LINEMODE */
+
+int
+tty_isecho(void)
+{
+#ifndef USE_TERMIO
+ return (termbuf.sg.sg_flags & ECHO);
+#else
+ return (termbuf.c_lflag & ECHO);
+#endif
+}
+
+int
+tty_flowmode(void)
+{
+#ifndef USE_TERMIO
+ return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
+#else
+ return((termbuf.c_iflag & IXON) ? 1 : 0);
+#endif
+}
+
+int
+tty_restartany(void)
+{
+#ifndef USE_TERMIO
+# ifdef DECCTQ
+ return((termbuf.lflags & DECCTQ) ? 0 : 1);
+# else
+ return(-1);
+# endif
+#else
+ return((termbuf.c_iflag & IXANY) ? 1 : 0);
+#endif
+}
+
+void
+tty_setecho(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags |= ECHO|CRMOD;
+ else
+ termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
+#else
+ if (on)
+ termbuf.c_lflag |= ECHO;
+ else
+ termbuf.c_lflag &= ~ECHO;
+#endif
+}
+
+int
+tty_israw(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.sg.sg_flags & RAW);
+#else
+ return(!(termbuf.c_lflag & ICANON));
+#endif
+}
+
+#ifdef AUTHENTICATION
+#if defined(NO_LOGIN_F) && defined(LOGIN_R)
+int
+tty_setraw(int on)
+{
+# ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags |= RAW;
+ else
+ termbuf.sg.sg_flags &= ~RAW;
+# else
+ if (on)
+ termbuf.c_lflag &= ~ICANON;
+ else
+ termbuf.c_lflag |= ICANON;
+# endif
+}
+#endif
+#endif /* AUTHENTICATION */
+
+void
+tty_binaryin(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.lflags |= LPASS8;
+ else
+ termbuf.lflags &= ~LPASS8;
+#else
+ if (on) {
+ termbuf.c_iflag &= ~ISTRIP;
+ } else {
+ termbuf.c_iflag |= ISTRIP;
+ }
+#endif
+}
+
+void
+tty_binaryout(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.lflags |= LLITOUT;
+ else
+ termbuf.lflags &= ~LLITOUT;
+#else
+ if (on) {
+ termbuf.c_cflag &= ~(CSIZE|PARENB);
+ termbuf.c_cflag |= CS8;
+ termbuf.c_oflag &= ~OPOST;
+ } else {
+ termbuf.c_cflag &= ~CSIZE;
+ termbuf.c_cflag |= CS7|PARENB;
+ termbuf.c_oflag |= OPOST;
+ }
+#endif
+}
+
+int
+tty_isbinaryin(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.lflags & LPASS8);
+#else
+ return(!(termbuf.c_iflag & ISTRIP));
+#endif
+}
+
+int
+tty_isbinaryout(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.lflags & LLITOUT);
+#else
+ return(!(termbuf.c_oflag&OPOST));
+#endif
+}
+
+#ifdef LINEMODE
+int
+tty_isediting(void)
+{
+#ifndef USE_TERMIO
+ return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
+#else
+ return(termbuf.c_lflag & ICANON);
+#endif
+}
+
+int
+tty_istrapsig(void)
+{
+#ifndef USE_TERMIO
+ return(!(termbuf.sg.sg_flags&RAW));
+#else
+ return(termbuf.c_lflag & ISIG);
+#endif
+}
+
+void
+tty_setedit(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags &= ~CBREAK;
+ else
+ termbuf.sg.sg_flags |= CBREAK;
+#else
+ if (on)
+ termbuf.c_lflag |= ICANON;
+ else
+ termbuf.c_lflag &= ~ICANON;
+#endif
+}
+
+void
+tty_setsig(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ ;
+#else
+ if (on)
+ termbuf.c_lflag |= ISIG;
+ else
+ termbuf.c_lflag &= ~ISIG;
+#endif
+}
+#endif /* LINEMODE */
+
+int
+tty_issofttab(void)
+{
+#ifndef USE_TERMIO
+ return (termbuf.sg.sg_flags & XTABS);
+#else
+# ifdef OXTABS
+ return (termbuf.c_oflag & OXTABS);
+# endif
+# ifdef TABDLY
+ return ((termbuf.c_oflag & TABDLY) == TAB3);
+# endif
+#endif
+}
+
+void
+tty_setsofttab(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags |= XTABS;
+ else
+ termbuf.sg.sg_flags &= ~XTABS;
+#else
+ if (on) {
+# ifdef OXTABS
+ termbuf.c_oflag |= OXTABS;
+# endif
+# ifdef TABDLY
+ termbuf.c_oflag &= ~TABDLY;
+ termbuf.c_oflag |= TAB3;
+# endif
+ } else {
+# ifdef OXTABS
+ termbuf.c_oflag &= ~OXTABS;
+# endif
+# ifdef TABDLY
+ termbuf.c_oflag &= ~TABDLY;
+ termbuf.c_oflag |= TAB0;
+# endif
+ }
+#endif
+}
+
+int
+tty_islitecho(void)
+{
+#ifndef USE_TERMIO
+ return (!(termbuf.lflags & LCTLECH));
+#else
+# ifdef ECHOCTL
+ return (!(termbuf.c_lflag & ECHOCTL));
+# endif
+# ifdef TCTLECH
+ return (!(termbuf.c_lflag & TCTLECH));
+# endif
+# if !defined(ECHOCTL) && !defined(TCTLECH)
+ return (0); /* assumes ctl chars are echoed '^x' */
+# endif
+#endif
+}
+
+void
+tty_setlitecho(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.lflags &= ~LCTLECH;
+ else
+ termbuf.lflags |= LCTLECH;
+#else
+# ifdef ECHOCTL
+ if (on)
+ termbuf.c_lflag &= ~ECHOCTL;
+ else
+ termbuf.c_lflag |= ECHOCTL;
+# endif
+# ifdef TCTLECH
+ if (on)
+ termbuf.c_lflag &= ~TCTLECH;
+ else
+ termbuf.c_lflag |= TCTLECH;
+# endif
+#endif
+}
+
+int
+tty_iscrnl(void)
+{
+#ifndef USE_TERMIO
+ return (termbuf.sg.sg_flags & CRMOD);
+#else
+ return (termbuf.c_iflag & ICRNL);
+#endif
+}
+
+/*
+ * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
+ */
+#if B4800 != 4800
+#define DECODE_BAUD
+#endif
+
+#ifdef DECODE_BAUD
+
+/*
+ * A table of available terminal speeds
+ */
+struct termspeeds {
+ int speed;
+ int value;
+} termspeeds[] = {
+ { 0, B0 }, { 50, B50 }, { 75, B75 },
+ { 110, B110 }, { 134, B134 }, { 150, B150 },
+ { 200, B200 }, { 300, B300 }, { 600, B600 },
+ { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
+ { 4800, B4800 },
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+ { 9600, B9600 },
+#ifdef B14400
+ { 14400, B14400 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B28800
+ { 28800, B28800 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+ { -1, 0 }
+};
+#endif /* DECODE_BAUD */
+
+void
+tty_tspeed(int val)
+{
+#ifdef DECODE_BAUD
+ struct termspeeds *tp;
+
+ for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
+ ;
+ if (tp->speed == -1) /* back up to last valid value */
+ --tp;
+ cfsetospeed(&termbuf, tp->value);
+#else /* DECODE_BAUD */
+ cfsetospeed(&termbuf, val);
+#endif /* DECODE_BAUD */
+}
+
+void
+tty_rspeed(int val)
+{
+#ifdef DECODE_BAUD
+ struct termspeeds *tp;
+
+ for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
+ ;
+ if (tp->speed == -1) /* back up to last valid value */
+ --tp;
+ cfsetispeed(&termbuf, tp->value);
+#else /* DECODE_BAUD */
+ cfsetispeed(&termbuf, val);
+#endif /* DECODE_BAUD */
+}
+
+/*
+ * getptyslave()
+ *
+ * Open the slave side of the pty, and do any initialization
+ * that is necessary.
+ */
+static void
+getptyslave(void)
+{
+ int t = -1;
+ char erase;
+
+# ifdef LINEMODE
+ int waslm;
+# endif
+# ifdef TIOCGWINSZ
+ struct winsize ws;
+ extern int def_row, def_col;
+# endif
+ extern int def_tspeed, def_rspeed;
+ /*
+ * Opening the slave side may cause initilization of the
+ * kernel tty structure. We need remember the state of
+ * if linemode was turned on
+ * terminal window size
+ * terminal speed
+ * erase character
+ * so that we can re-set them if we need to.
+ */
+# ifdef LINEMODE
+ waslm = tty_linemode();
+# endif
+ erase = termbuf.c_cc[VERASE];
+
+ /*
+ * Make sure that we don't have a controlling tty, and
+ * that we are the session (process group) leader.
+ */
+# ifdef TIOCNOTTY
+ t = open(_PATH_TTY, O_RDWR);
+ if (t >= 0) {
+ (void) ioctl(t, TIOCNOTTY, (char *)0);
+ (void) close(t);
+ }
+# endif
+
+ t = spty;
+ if (t < 0)
+ fatalperror(net, line);
+
+
+ /*
+ * set up the tty modes as we like them to be.
+ */
+ init_termbuf();
+# ifdef TIOCGWINSZ
+ if (def_row || def_col) {
+ memset((char *)&ws, 0, sizeof(ws));
+ ws.ws_col = def_col;
+ ws.ws_row = def_row;
+ (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
+ }
+# endif
+
+ /*
+ * Settings for sgtty based systems
+ */
+# ifndef USE_TERMIO
+ termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
+# endif /* USE_TERMIO */
+
+ /*
+ * Settings for all other termios/termio based
+ * systems, other than 4.4BSD. In 4.4BSD the
+ * kernel does the initial terminal setup.
+ */
+ tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
+ tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
+ if (erase)
+ termbuf.c_cc[VERASE] = erase;
+# ifdef LINEMODE
+ if (waslm)
+ tty_setlinemode(1);
+# endif /* LINEMODE */
+
+ /*
+ * Set the tty modes, and make this our controlling tty.
+ */
+ set_termbuf();
+ if (login_tty(t) == -1)
+ fatalperror(net, "login_tty");
+ if (net > 2)
+ (void) close(net);
+#ifdef AUTHENTICATION
+#if defined(NO_LOGIN_F) && defined(LOGIN_R)
+ /*
+ * Leave the pty open so that we can write out the rlogin
+ * protocol for /bin/login, if the authentication works.
+ */
+#else
+ if (pty > 2) {
+ (void) close(pty);
+ pty = -1;
+ }
+#endif
+#endif /* AUTHENTICATION */
+}
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+/*
+ * Open the specified slave side of the pty,
+ * making sure that we have a clean tty.
+ */
+int
+cleanopen(char *li)
+{
+ int t;
+
+ /*
+ * Make sure that other people can't open the
+ * slave side of the connection.
+ */
+ (void) chown(li, 0, 0);
+ (void) chmod(li, 0600);
+
+ (void) revoke(li);
+
+ t = open(line, O_RDWR|O_NOCTTY);
+
+ if (t < 0)
+ return(-1);
+
+ return(t);
+}
+
+/*
+ * startslave(host)
+ *
+ * Given a hostname, do whatever
+ * is necessary to startup the login process on the slave side of the pty.
+ */
+
+/* ARGSUSED */
+void
+startslave(char *host, int autologin, char *autoname)
+{
+ int i;
+
+#ifdef AUTHENTICATION
+ if (!autoname || !autoname[0])
+ autologin = 0;
+
+ if (autologin < auth_level) {
+ fatal(net, "Authorization failed");
+ exit(1);
+ }
+#endif
+
+
+ if ((i = fork()) < 0)
+ fatalperror(net, "fork");
+ if (i) {
+ } else {
+ getptyslave();
+ start_login(host, autologin, autoname);
+ /*NOTREACHED*/
+ }
+}
+
+void
+init_env(void)
+{
+ char **envp;
+
+ envp = envinit;
+ if ((*envp = getenv("TZ")))
+ *envp++ -= 3;
+ *envp = 0;
+ environ = envinit;
+}
+
+
+/*
+ * start_login(host)
+ *
+ * Assuming that we are now running as a child processes, this
+ * function will turn us into the login process.
+ */
+
+#ifndef AUTHENTICATION
+#define undef1 __unused
+#else
+#define undef1
+#endif
+
+void
+start_login(char *host undef1, int autologin undef1, char *name undef1)
+{
+ char **argv;
+#ifdef UTMPX
+ // rdar://problem/4433603
+ int pid = getpid();
+ struct utmpx utmpx;
+
+ /*
+ * Create utmp entry for child
+ */
+
+ bzero(&utmpx, sizeof(utmpx));
+ SCPYN(utmpx.ut_user, ".telnet");
+ SCPYN(utmpx.ut_line, line + sizeof(_PATH_DEV) - 1);
+ utmpx.ut_pid = pid;
+ utmpx.ut_id[0] = 't';
+ utmpx.ut_id[1] = 'n';
+ utmpx.ut_id[2] = SC_WILDC;
+ utmpx.ut_id[3] = SC_WILDC;
+ utmpx.ut_type = LOGIN_PROCESS;
+ (void) time(&utmpx.ut_tv.tv_sec);
+ if (makeutx(&utmpx) == NULL)
+ fatal(net, "makeutx failed");
+#endif /* UTMPX */
+
+ scrub_env();
+
+ /*
+ * -h : pass on name of host.
+ * WARNING: -h is accepted by login if and only if
+ * getuid() == 0.
+ * -p : don't clobber the environment (so terminal type stays set).
+ *
+ * -f : force this login, he has already been authenticated
+ */
+ argv = addarg(0, "login");
+
+#if !defined(NO_LOGIN_H)
+#ifdef AUTHENTICATION
+# if defined(NO_LOGIN_F) && defined(LOGIN_R)
+ /*
+ * Don't add the "-h host" option if we are going
+ * to be adding the "-r host" option down below...
+ */
+ if ((auth_level < 0) || (autologin != AUTH_VALID))
+# endif
+ {
+ argv = addarg(argv, "-h");
+ argv = addarg(argv, host);
+ }
+#endif /* AUTHENTICATION */
+#endif
+#if !defined(NO_LOGIN_P)
+ argv = addarg(argv, "-p");
+#endif
+#ifdef LINEMODE
+ /*
+ * Set the environment variable "LINEMODE" to either
+ * "real" or "kludge" if we are operating in either
+ * real or kludge linemode.
+ */
+ if (lmodetype == REAL_LINEMODE)
+ setenv("LINEMODE", "real", 1);
+# ifdef KLUDGELINEMODE
+ else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
+ setenv("LINEMODE", "kludge", 1);
+# endif
+#endif
+#ifdef BFTPDAEMON
+ /*
+ * Are we working as the bftp daemon? If so, then ask login
+ * to start bftp instead of shell.
+ */
+ if (bftpd) {
+ argv = addarg(argv, "-e");
+ argv = addarg(argv, BFTPPATH);
+ } else
+#endif
+#ifdef AUTHENTICATION
+ if (auth_level >= 0 && autologin == AUTH_VALID) {
+# if !defined(NO_LOGIN_F)
+ argv = addarg(argv, "-f");
+ argv = addarg(argv, "--");
+ argv = addarg(argv, name);
+# else
+# if defined(LOGIN_R)
+ /*
+ * We don't have support for "login -f", but we
+ * can fool /bin/login into thinking that we are
+ * rlogind, and allow us to log in without a
+ * password. The rlogin protocol expects
+ * local-user\0remote-user\0term/speed\0
+ */
+
+ if (pty > 2) {
+ char *cp;
+ char speed[128];
+ int isecho, israw, xpty, len;
+ extern int def_rspeed;
+# ifndef LOGIN_HOST
+ /*
+ * Tell login that we are coming from "localhost".
+ * If we passed in the real host name, then the
+ * user would have to allow .rhost access from
+ * every machine that they want authenticated
+ * access to work from, which sort of defeats
+ * the purpose of an authenticated login...
+ * So, we tell login that the session is coming
+ * from "localhost", and the user will only have
+ * to have "localhost" in their .rhost file.
+ */
+# define LOGIN_HOST "localhost"
+# endif
+ argv = addarg(argv, "-r");
+ argv = addarg(argv, LOGIN_HOST);
+
+ xpty = pty;
+ pty = 0;
+ init_termbuf();
+ isecho = tty_isecho();
+ israw = tty_israw();
+ if (isecho || !israw) {
+ tty_setecho(0); /* Turn off echo */
+ tty_setraw(1); /* Turn on raw */
+ set_termbuf();
+ }
+ len = strlen(name)+1;
+ write(xpty, name, len);
+ write(xpty, name, len);
+ snprintf(speed, sizeof(speed),
+ "%s/%d", (cp = getenv("TERM")) ? cp : "",
+ (def_rspeed > 0) ? def_rspeed : 9600);
+ len = strlen(speed)+1;
+ write(xpty, speed, len);
+
+ if (isecho || !israw) {
+ init_termbuf();
+ tty_setecho(isecho);
+ tty_setraw(israw);
+ set_termbuf();
+ if (!israw) {
+ /*
+ * Write a newline to ensure
+ * that login will be able to
+ * read the line...
+ */
+ write(xpty, "\n", 1);
+ }
+ }
+ pty = xpty;
+ }
+# else
+ argv = addarg(argv, "--");
+ argv = addarg(argv, name);
+# endif
+# endif
+ } else
+#endif
+ if (getenv("USER")) {
+ argv = addarg(argv, "--");
+ argv = addarg(argv, getenv("USER"));
+#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
+ {
+ char **cpp;
+ for (cpp = environ; *cpp; cpp++)
+ argv = addarg(argv, *cpp);
+ }
+#endif
+ /*
+ * Assume that login will set the USER variable
+ * correctly. For SysV systems, this means that
+ * USER will no longer be set, just LOGNAME by
+ * login. (The problem is that if the auto-login
+ * fails, and the user then specifies a different
+ * account name, he can get logged in with both
+ * LOGNAME and USER in his environment, but the
+ * USER value will be wrong.
+ */
+ unsetenv("USER");
+ }
+#ifdef AUTHENTICATION
+#if defined(NO_LOGIN_F) && defined(LOGIN_R)
+ if (pty > 2)
+ close(pty);
+#endif
+#endif /* AUTHENTICATION */
+ closelog();
+
+ if (altlogin == NULL) {
+ altlogin = _PATH_LOGIN;
+ }
+ execv(altlogin, argv);
+
+ syslog(LOG_ERR, "%s: %m", altlogin);
+ fatalperror(net, altlogin);
+ /*NOTREACHED*/
+}
+
+static char **
+addarg(char **argv, const char *val)
+{
+ char **cpp;
+
+ if (argv == NULL) {
+ /*
+ * 10 entries, a leading length, and a null
+ */
+ argv = (char **)malloc(sizeof(*argv) * 12);
+ if (argv == NULL)
+ return(NULL);
+ *argv++ = (char *)10;
+ *argv = (char *)0;
+ }
+ for (cpp = argv; *cpp; cpp++)
+ ;
+ if (cpp == &argv[(long)argv[-1]]) {
+ --argv;
+ *argv = (char *)((long)(*argv) + 10);
+ argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
+ if (argv == NULL)
+ return(NULL);
+ argv++;
+ cpp = &argv[(long)argv[-1] - 10];
+ }
+ *cpp++ = strdup(val);
+ *cpp = 0;
+ return(argv);
+}
+
+/*
+ * scrub_env()
+ *
+ * We only accept the environment variables listed below.
+ */
+void
+scrub_env(void)
+{
+ static const char *rej[] = {
+ "TERMCAP=/",
+ NULL
+ };
+
+ static const char *acc[] = {
+ "XAUTH=", "XAUTHORITY=", "DISPLAY=",
+ "TERM=",
+ "EDITOR=",
+ "PAGER=",
+ "LOGNAME=",
+ "POSIXLY_CORRECT=",
+ "PRINTER=",
+ NULL
+ };
+
+ char **cpp, **cpp2;
+ const char **p;
+
+ for (cpp2 = cpp = environ; *cpp; cpp++) {
+ int reject_it = 0;
+
+ for(p = rej; *p; p++)
+ if(strncmp(*cpp, *p, strlen(*p)) == 0) {
+ reject_it = 1;
+ break;
+ }
+ if (reject_it)
+ continue;
+
+ for(p = acc; *p; p++)
+ if(strncmp(*cpp, *p, strlen(*p)) == 0)
+ break;
+ if(*p != NULL)
+ *cpp2++ = *cpp;
+ }
+ *cpp2 = NULL;
+}
+
+/*
+ * cleanup()
+ *
+ * This is the routine to call when we are all through, to
+ * clean up anything that needs to be cleaned up.
+ */
+/* ARGSUSED */
+void
+cleanup(int sig __unused)
+{
+#ifdef __APPLE__
+ // rdar://problem/5169227
+ (void) shutdown(net, SHUT_RDWR);
+#else /* !__APPLE__ */
+ char *p;
+ sigset_t mask;
+
+ p = line + sizeof(_PATH_DEV) - 1;
+ /*
+ * Block all signals before clearing the utmp entry. We don't want to
+ * be called again after calling logout() and then not add the wtmp
+ * entry because of not finding the corresponding entry in utmp.
+ */
+ sigfillset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ if (logout(p))
+ logwtmp(p, "", "");
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ *p = 'p';
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ (void) shutdown(net, 2);
+#endif
+ _exit(1);
+}
diff --git a/remote_cmds/telnetd.tproj/telnet.plist b/remote_cmds/telnetd.tproj/telnet.plist
new file mode 100644
index 0000000..6dff1eb
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnet.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.telnetd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/telnetd</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <false/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>telnet</string>
+ <key>Bonjour</key>
+ <true/>
+ </dict>
+ </dict>
+ <key>SessionCreate</key>
+ <true/>
+ <key>EnablePressuredExit</key>
+ <false/>
+ <key>EnableTransactions</key>
+ <false/>
+</dict>
+</plist>
diff --git a/remote_cmds/telnetd.tproj/telnetd.8 b/remote_cmds/telnetd.tproj/telnetd.8
new file mode 100644
index 0000000..3bf2f51
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnetd.8
@@ -0,0 +1,607 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94
+.\" $FreeBSD: src/contrib/telnet/telnetd/telnetd.8,v 1.21 2005/01/21 21:57:05 ru Exp $
+.\"
+.Dd January 9, 2005
+.Dt TELNETD 8
+.Os
+.Sh NAME
+.Nm telnetd
+.Nd DARPA
+.Tn TELNET
+protocol server
+.Sh SYNOPSIS
+.Nm /usr/libexec/telnetd
+.Op Fl 46BUhlkns
+.Op Fl D Ar debugmode
+.Op Fl S Ar tos
+.Op Fl X Ar authtype
+.Op Fl a Ar authmode
+.Op Fl edebug
+.Op Fl p Ar loginprog
+.Op Fl u Ar len
+.Op Fl debug Op Ar port
+.Sh DESCRIPTION
+The
+.Nm
+command is a server which supports the
+.Tn DARPA
+standard
+.Tn TELNET
+virtual terminal protocol.
+.Nm Telnetd
+is normally invoked by the internet server (see
+.Xr inetd 8 )
+for requests to connect to the
+.Tn TELNET
+port as indicated by the
+.Pa /etc/services
+file (see
+.Xr services 5 ) .
+The
+.Fl debug
+option may be used to start up
+.Nm
+manually, instead of through
+.Xr inetd 8 .
+If started up this way,
+.Ar port
+may be specified to run
+.Nm
+on an alternate
+.Tn TCP
+port number.
+.Pp
+The
+.Nm
+command accepts the following options:
+.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl a Ar authmode
+This option may be used for specifying what mode should
+be used for authentication.
+Note that this option is only useful if
+.Nm
+has been compiled with support for the
+.Dv AUTHENTICATION
+option.
+There are several valid values for
+.Ar authmode :
+.Bl -tag -width debug
+.It Cm debug
+Turn on authentication debugging code.
+.It Cm user
+Only allow connections when the remote user
+can provide valid authentication information
+to identify the remote user,
+and is allowed access to the specified account
+without providing a password.
+.It Cm valid
+Only allow connections when the remote user
+can provide valid authentication information
+to identify the remote user.
+The
+.Xr login 1
+command will provide any additional user verification
+needed if the remote user is not allowed automatic
+access to the specified account.
+.It Cm other
+Only allow connections that supply some authentication information.
+This option is currently not supported
+by any of the existing authentication mechanisms,
+and is thus the same as specifying
+.Fl a
+.Cm valid .
+.It Cm none
+This is the default state.
+Authentication information is not required.
+If no or insufficient authentication information
+is provided, then the
+.Xr login 1
+program will provide the necessary user
+verification.
+.It Cm off
+Disable the authentication code.
+All user verification will happen through the
+.Xr login 1
+program.
+.El
+.It Fl B
+Specify bftp server mode.
+In this mode,
+.Nm
+causes login to start a
+.Xr bftp 1
+session rather than the user's
+normal shell.
+In bftp daemon mode normal
+logins are not supported, and it must be used
+on a port other than the normal
+.Tn TELNET
+port.
+.It Fl D Ar debugmode
+This option may be used for debugging purposes.
+This allows
+.Nm
+to print out debugging information
+to the connection, allowing the user to see what
+.Nm
+is doing.
+There are several possible values for
+.Ar debugmode :
+.Bl -tag -width exercise
+.It Cm options
+Print information about the negotiation of
+.Tn TELNET
+options.
+.It Cm report
+Print the
+.Cm options
+information, plus some additional information
+about what processing is going on.
+.It Cm netdata
+Display the data stream received by
+.Nm .
+.It Cm ptydata
+Display data written to the pty.
+.It Cm exercise
+Has not been implemented yet.
+.El
+.It Fl debug
+Enable debugging on each socket created by
+.Nm
+(see
+.Dv SO_DEBUG
+in
+.Xr socket 2 ) .
+.It Fl edebug
+If
+.Nm
+has been compiled with support for data encryption, then the
+.Fl edebug
+option may be used to enable encryption debugging code.
+.It Fl p Ar loginprog
+Specify an alternate
+.Xr login 1
+command to run to complete the login. The alternate command must
+understand the same command arguments as the standard login.
+.It Fl h
+Disable the printing of host-specific information before
+login has been completed.
+.It Fl k
+This option is only useful if
+.Nm
+has been compiled with both linemode and kludge linemode
+support.
+If the
+.Fl k
+option is specified, then if the remote client does not
+support the
+.Dv LINEMODE
+option, then
+.Nm
+will operate in character at a time mode.
+It will still support kludge linemode, but will only
+go into kludge linemode if the remote client requests
+it.
+(This is done by the client sending
+.Dv DONT SUPPRESS-GO-AHEAD
+and
+.Dv DONT ECHO . )
+The
+.Fl k
+option is most useful when there are remote clients
+that do not support kludge linemode, but pass the heuristic
+(if they respond with
+.Dv WILL TIMING-MARK
+in response to a
+.Dv DO TIMING-MARK )
+for kludge linemode support.
+.It Fl l
+Specify line mode.
+Try to force clients to use line-at-a-time mode.
+If the
+.Dv LINEMODE
+option is not supported, it will go
+into kludge linemode.
+.It Fl n
+Disable
+.Dv TCP
+keep-alives.
+Normally
+.Nm
+enables the
+.Tn TCP
+keep-alive mechanism to probe connections that
+have been idle for some period of time to determine
+if the client is still there, so that idle connections
+from machines that have crashed or can no longer
+be reached may be cleaned up.
+.It Fl S Ar tos
+Sets the IP type-of-service (TOS) option for the telnet
+connection to the value
+.Ar tos ,
+which can be a numeric TOS value or, on systems that support it, a symbolic
+TOS name found in the
+.Pa /etc/iptos
+file.
+.It Fl u Ar len
+This option is used to specify the size of the field
+in the
+.Dv utmpx
+structure that holds the remote host name.
+If the resolved host name is longer than
+.Ar len ,
+the dotted decimal value will be used instead.
+This allows hosts with very long host names that
+overflow this field to still be uniquely identified.
+Specifying
+.Fl u0
+indicates that only dotted decimal addresses
+should be put into the
+.Pa utmpx
+file.
+.It Fl U
+This option causes
+.Nm
+to refuse connections from addresses that
+cannot be mapped back into a symbolic name
+via the
+.Xr gethostbyaddr 3
+routine.
+.It Fl X Ar authtype
+This option is only valid if
+.Nm
+has been built with support for the authentication option.
+It disables the use of
+.Ar authtype
+authentication, and
+can be used to temporarily disable
+a specific authentication type without having to recompile
+.Nm .
+.El
+.Pp
+.Nm Telnetd
+operates by allocating a pseudo-terminal device (see
+.Xr pty 4 )
+for a client, then creating a login process which has
+the slave side of the pseudo-terminal as
+.Dv stdin ,
+.Dv stdout
+and
+.Dv stderr .
+.Nm Telnetd
+manipulates the master side of the pseudo-terminal,
+implementing the
+.Tn TELNET
+protocol and passing characters
+between the remote client and the login process.
+.Pp
+When a
+.Tn TELNET
+session is started up,
+.Nm
+sends
+.Tn TELNET
+options to the client side indicating
+a willingness to do the
+following
+.Tn TELNET
+options, which are described in more detail below:
+.Bd -literal -offset indent
+DO AUTHENTICATION
+WILL ENCRYPT
+DO TERMINAL TYPE
+DO TSPEED
+DO XDISPLOC
+DO NEW-ENVIRON
+DO ENVIRON
+WILL SUPPRESS GO AHEAD
+DO ECHO
+DO LINEMODE
+DO NAWS
+WILL STATUS
+DO LFLOW
+DO TIMING-MARK
+.Ed
+.Pp
+The pseudo-terminal allocated to the client is configured
+to operate in
+.Dq cooked
+mode, and with
+.Dv XTABS and
+.Dv CRMOD
+enabled (see
+.Xr tty 4 ) .
+.Pp
+.Nm Telnetd
+has support for enabling locally the following
+.Tn TELNET
+options:
+.Bl -tag -width "DO AUTHENTICATION"
+.It "WILL ECHO"
+When the
+.Dv LINEMODE
+option is enabled, a
+.Dv WILL ECHO
+or
+.Dv WONT ECHO
+will be sent to the client to indicate the
+current state of terminal echoing.
+When terminal echo is not desired, a
+.Dv WILL ECHO
+is sent to indicate that
+.Nm
+will take care of echoing any data that needs to be
+echoed to the terminal, and then nothing is echoed.
+When terminal echo is desired, a
+.Dv WONT ECHO
+is sent to indicate that
+.Nm
+will not be doing any terminal echoing, so the
+client should do any terminal echoing that is needed.
+.It "WILL BINARY"
+Indicate that the client is willing to send a
+8 bits of data, rather than the normal 7 bits
+of the Network Virtual Terminal.
+.It "WILL SGA"
+Indicate that it will not be sending
+.Dv IAC GA ,
+go ahead, commands.
+.It "WILL STATUS"
+Indicate a willingness to send the client, upon
+request, of the current status of all
+.Tn TELNET
+options.
+.It "WILL TIMING-MARK"
+Whenever a
+.Dv DO TIMING-MARK
+command is received, it is always responded
+to with a
+.Dv WILL TIMING-MARK .
+.It "WILL LOGOUT"
+When a
+.Dv DO LOGOUT
+is received, a
+.Dv WILL LOGOUT
+is sent in response, and the
+.Tn TELNET
+session is shut down.
+.It "WILL ENCRYPT"
+Only sent if
+.Nm
+is compiled with support for data encryption, and
+indicates a willingness to decrypt
+the data stream.
+.El
+.Pp
+.Nm Telnetd
+has support for enabling remotely the following
+.Tn TELNET
+options:
+.Bl -tag -width "DO AUTHENTICATION"
+.It "DO BINARY"
+Sent to indicate that
+.Nm
+is willing to receive an 8 bit data stream.
+.It "DO LFLOW"
+Requests that the client handle flow control
+characters remotely.
+.It "DO ECHO"
+This is not really supported, but is sent to identify a
+.Bx 4.2
+.Xr telnet 1
+client, which will improperly respond with
+.Dv WILL ECHO .
+If a
+.Dv WILL ECHO
+is received, a
+.Dv DONT ECHO
+will be sent in response.
+.It "DO TERMINAL-TYPE"
+Indicate a desire to be able to request the
+name of the type of terminal that is attached
+to the client side of the connection.
+.It "DO SGA"
+Indicate that it does not need to receive
+.Dv IAC GA ,
+the go ahead command.
+.It "DO NAWS"
+Requests that the client inform the server when
+the window (display) size changes.
+.It "DO TERMINAL-SPEED"
+Indicate a desire to be able to request information
+about the speed of the serial line to which
+the client is attached.
+.It "DO XDISPLOC"
+Indicate a desire to be able to request the name
+of the X Window System display that is associated with
+the telnet client.
+.It "DO NEW-ENVIRON"
+Indicate a desire to be able to request environment
+variable information, as described in RFC 1572.
+.It "DO ENVIRON"
+Indicate a desire to be able to request environment
+variable information, as described in RFC 1408.
+.It "DO LINEMODE"
+Only sent if
+.Nm
+is compiled with support for linemode, and
+requests that the client do line by line processing.
+.It "DO TIMING-MARK"
+Only sent if
+.Nm
+is compiled with support for both linemode and
+kludge linemode, and the client responded with
+.Dv WONT LINEMODE .
+If the client responds with
+.Dv WILL TM ,
+the it is assumed that the client supports
+kludge linemode.
+Note that the
+.Op Fl k
+option can be used to disable this.
+.It "DO AUTHENTICATION"
+Only sent if
+.Nm
+is compiled with support for authentication, and
+indicates a willingness to receive authentication
+information for automatic login.
+.It "DO ENCRYPT"
+Only sent if
+.Nm
+is compiled with support for data encryption, and
+indicates a willingness to decrypt
+the data stream.
+.El
+.Sh NOTES
+By default
+.Nm
+will read the
+.Em \&he ,
+.Em \&hn ,
+and
+.Em \&im
+capabilities from
+.Pa /etc/gettytab
+and use that information (if present) to determine
+what to display before the login: prompt.
+You can
+also use a System V style
+.Pa /etc/issue
+file by using the
+.Em \&if
+capability, which will override
+.Em \&im .
+The information specified in either
+.Em \&im
+or
+.Em \&if
+will be displayed to both console and remote logins.
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width /usr/ucb/bftp -compact
+.It Pa /etc/services
+.It Pa /etc/gettytab
+.It Pa /etc/iptos
+(if supported)
+.It Pa /usr/ucb/bftp
+(if supported)
+.El
+.Sh "SEE ALSO"
+.Xr bftp 1 ,
+.Xr login 1 ,
+.Xr telnet 1
+(if supported),
+.Xr gettytab 5
+.Sh STANDARDS
+.Bl -tag -compact -width RFC-1572
+.It Cm RFC-854
+.Tn TELNET
+PROTOCOL SPECIFICATION
+.It Cm RFC-855
+TELNET OPTION SPECIFICATIONS
+.It Cm RFC-856
+TELNET BINARY TRANSMISSION
+.It Cm RFC-857
+TELNET ECHO OPTION
+.It Cm RFC-858
+TELNET SUPPRESS GO AHEAD OPTION
+.It Cm RFC-859
+TELNET STATUS OPTION
+.It Cm RFC-860
+TELNET TIMING MARK OPTION
+.It Cm RFC-861
+TELNET EXTENDED OPTIONS - LIST OPTION
+.It Cm RFC-885
+TELNET END OF RECORD OPTION
+.It Cm RFC-1073
+Telnet Window Size Option
+.It Cm RFC-1079
+Telnet Terminal Speed Option
+.It Cm RFC-1091
+Telnet Terminal-Type Option
+.It Cm RFC-1096
+Telnet X Display Location Option
+.It Cm RFC-1123
+Requirements for Internet Hosts -- Application and Support
+.It Cm RFC-1184
+Telnet Linemode Option
+.It Cm RFC-1372
+Telnet Remote Flow Control Option
+.It Cm RFC-1416
+Telnet Authentication Option
+.It Cm RFC-1411
+Telnet Authentication: Kerberos Version 4
+.It Cm RFC-1412
+Telnet Authentication: SPX
+.It Cm RFC-1571
+Telnet Environment Option Interoperability Issues
+.It Cm RFC-1572
+Telnet Environment Option
+.El
+.Sh HISTORY
+IPv6 support was added by WIDE/KAME project.
+.Sh BUGS
+Some
+.Tn TELNET
+commands are only partially implemented.
+.Pp
+Because of bugs in the original
+.Bx 4.2
+.Xr telnet 1 ,
+.Nm
+performs some dubious protocol exchanges to try to discover if the remote
+client is, in fact, a
+.Bx 4.2
+.Xr telnet 1 .
+.Pp
+Binary mode
+has no common interpretation except between similar operating systems
+(Unix in this case).
+.Pp
+The terminal type name received from the remote client is converted to
+lower case.
+.Pp
+.Nm Telnetd
+never sends
+.Tn TELNET
+.Dv IAC GA
+(go ahead) commands.
diff --git a/remote_cmds/telnetd.tproj/telnetd.c b/remote_cmds/telnetd.tproj/telnetd.c
new file mode 100644
index 0000000..a952a93
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnetd.c
@@ -0,0 +1,1330 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/telnetd.c,v 1.29 2006/09/26 21:46:11 ru Exp $");
+
+#include "telnetd.h"
+#include "pathnames.h"
+
+#include <sys/mman.h>
+#include <err.h>
+#ifndef __APPLE__
+#include <libutil.h>
+#endif
+#include <paths.h>
+#include <termcap.h>
+#ifndef __APPLE__
+#include <utmp.h>
+#endif
+
+#include <arpa/inet.h>
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+int auth_level = 0;
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+#include <libtelnet/misc.h>
+
+char remote_hostname[MAXHOSTNAMELEN];
+size_t utmp_len = sizeof(remote_hostname) - 1;
+int registerd_host_only = 0;
+
+
+/*
+ * I/O data buffers,
+ * pointers, and counters.
+ */
+char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char ptyibuf2[BUFSIZ];
+
+int readstream(int, char *, int);
+void doit(struct sockaddr *);
+int terminaltypeok(char *);
+
+int hostinfo = 1; /* do we print login banner? */
+
+static int debug = 0;
+int keepalive = 1;
+const char *altlogin;
+
+void doit(struct sockaddr *);
+int terminaltypeok(char *);
+void startslave(char *, int, char *);
+extern void usage(void);
+static void _gettermname(void);
+
+/*
+ * The string to pass to getopt(). We do it this way so
+ * that only the actual options that we support will be
+ * passed off to getopt().
+ */
+char valid_opts[] = {
+ 'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
+ '4', '6',
+#ifdef AUTHENTICATION
+ 'a', ':', 'X', ':',
+#endif
+#ifdef BFTPDAEMON
+ 'B',
+#endif
+#ifdef DIAGNOSTICS
+ 'D', ':',
+#endif
+#ifdef ENCRYPTION
+ 'e', ':',
+#endif
+#ifdef LINEMODE
+ 'l',
+#endif
+ '\0'
+};
+
+int family = AF_INET;
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif /* MAXHOSTNAMELEN */
+
+char *hostname;
+char host_name[MAXHOSTNAMELEN];
+
+extern void telnet(int, int, char *);
+
+int level;
+char user_name[256];
+
+int
+main(int argc, char *argv[])
+{
+ u_long ultmp;
+ struct sockaddr_storage from;
+#ifdef __APPLE__
+ int on = 1;
+ socklen_t fromlen;
+#else
+ int on = 1, fromlen;
+#endif
+ int ch;
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ int tos = -1;
+#endif
+ char *ep;
+
+ // radar:17828581
+ (void)signal(SIGTERM, SIG_DFL);
+
+ pfrontp = pbackp = ptyobuf;
+ netip = netibuf;
+ nfrontp = nbackp = netobuf;
+#ifdef ENCRYPTION
+ nclearto = 0;
+#endif /* ENCRYPTION */
+
+ /*
+ * This initialization causes linemode to default to a configuration
+ * that works on all telnet clients, including the FreeBSD client.
+ * This is not quite the same as the telnet client issuing a "mode
+ * character" command, but has most of the same benefits, and is
+ * preferable since some clients (like usofts) don't have the
+ * mode character command anyway and linemode breaks things.
+ * The most notable symptom of fix is that csh "set filec" operations
+ * like <ESC> (filename completion) and ^D (choices) keys now work
+ * in telnet sessions and can be used more than once on the same line.
+ * CR/LF handling is also corrected in some termio modes. This
+ * change resolves problem reports bin/771 and bin/1037.
+ */
+
+ linemode=1; /*Default to mode that works on bulk of clients*/
+
+ while ((ch = getopt(argc, argv, valid_opts)) != -1) {
+ switch(ch) {
+
+#ifdef AUTHENTICATION
+ case 'a':
+ /*
+ * Check for required authentication level
+ */
+ if (strcmp(optarg, "debug") == 0) {
+ extern int auth_debug_mode;
+ auth_debug_mode = 1;
+ } else if (strcasecmp(optarg, "none") == 0) {
+ auth_level = 0;
+ } else if (strcasecmp(optarg, "other") == 0) {
+ auth_level = AUTH_OTHER;
+ } else if (strcasecmp(optarg, "user") == 0) {
+ auth_level = AUTH_USER;
+ } else if (strcasecmp(optarg, "valid") == 0) {
+ auth_level = AUTH_VALID;
+ } else if (strcasecmp(optarg, "off") == 0) {
+ /*
+ * This hack turns off authentication
+ */
+ auth_level = -1;
+ } else {
+ warnx("unknown authorization level for -a");
+ }
+ break;
+#endif /* AUTHENTICATION */
+
+#ifdef BFTPDAEMON
+ case 'B':
+ bftpd++;
+ break;
+#endif /* BFTPDAEMON */
+
+ case 'd':
+ if (strcmp(optarg, "ebug") == 0) {
+ debug++;
+ break;
+ }
+ usage();
+ /* NOTREACHED */
+ break;
+
+#ifdef DIAGNOSTICS
+ case 'D':
+ /*
+ * Check for desired diagnostics capabilities.
+ */
+ if (!strcmp(optarg, "report")) {
+ diagnostic |= TD_REPORT|TD_OPTIONS;
+ } else if (!strcmp(optarg, "exercise")) {
+ diagnostic |= TD_EXERCISE;
+ } else if (!strcmp(optarg, "netdata")) {
+ diagnostic |= TD_NETDATA;
+ } else if (!strcmp(optarg, "ptydata")) {
+ diagnostic |= TD_PTYDATA;
+ } else if (!strcmp(optarg, "options")) {
+ diagnostic |= TD_OPTIONS;
+ } else {
+ usage();
+ /* NOT REACHED */
+ }
+ break;
+#endif /* DIAGNOSTICS */
+
+#ifdef ENCRYPTION
+ case 'e':
+ if (strcmp(optarg, "debug") == 0) {
+ extern int encrypt_debug_mode;
+ encrypt_debug_mode = 1;
+ break;
+ }
+ usage();
+ /* NOTREACHED */
+ break;
+#endif /* ENCRYPTION */
+
+ case 'h':
+ hostinfo = 0;
+ break;
+
+#ifdef LINEMODE
+ case 'l':
+ alwayslinemode = 1;
+ break;
+#endif /* LINEMODE */
+
+ case 'k':
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ lmodetype = NO_AUTOKLUDGE;
+#else
+ /* ignore -k option if built without kludge linemode */
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ break;
+
+ case 'n':
+ keepalive = 0;
+ break;
+
+ case 'p':
+ altlogin = optarg;
+ break;
+
+ case 'S':
+#ifdef HAS_GETTOS
+ if ((tos = parsetos(optarg, "tcp")) < 0)
+ warnx("%s%s%s",
+ "bad TOS argument '", optarg,
+ "'; will try to use default TOS");
+#else
+#define MAXTOS 255
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTOS)
+ warnx("%s%s%s",
+ "bad TOS argument '", optarg,
+ "'; will try to use default TOS");
+ else
+ tos = ultmp;
+#endif
+ break;
+
+ case 'u':
+ utmp_len = (size_t)atoi(optarg);
+ if (utmp_len >= sizeof(remote_hostname))
+ utmp_len = sizeof(remote_hostname) - 1;
+ break;
+
+ case 'U':
+ registerd_host_only = 1;
+ break;
+
+#ifdef AUTHENTICATION
+ case 'X':
+ /*
+ * Check for invalid authentication types
+ */
+ auth_disable_name(optarg);
+ break;
+#endif /* AUTHENTICATION */
+
+ case '4':
+ family = AF_INET;
+ break;
+
+#ifdef INET6
+ case '6':
+ family = AF_INET6;
+ break;
+#endif
+
+ default:
+ warnx("%c: unknown option", ch);
+ /* FALLTHROUGH */
+ case '?':
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (debug) {
+#ifdef __APPLE__
+ int s, ns, error;
+ socklen_t foo;
+#else
+ int s, ns, foo, error;
+#endif
+ const char *service = "telnet";
+ struct addrinfo hints, *res;
+
+ if (argc > 1) {
+ usage();
+ /* NOT REACHED */
+ } else if (argc == 1)
+ service = *argv;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(NULL, service, &hints, &res);
+
+ if (error) {
+ errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ errx(1, "tcp/%s: %s\n", service, strerror(errno));
+ usage();
+ }
+
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s < 0)
+ err(1, "socket");
+ (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on));
+ if (debug > 1)
+ (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
+ err(1, "bind");
+ if (listen(s, 1) < 0)
+ err(1, "listen");
+ foo = res->ai_addrlen;
+ ns = accept(s, res->ai_addr, &foo);
+ if (ns < 0)
+ err(1, "accept");
+ (void) setsockopt(ns, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ (void) dup2(ns, 0);
+ (void) close(ns);
+ (void) close(s);
+#ifdef convex
+ } else if (argc == 1) {
+ ; /* VOID*/ /* Just ignore the host/port name */
+#endif
+ } else if (argc > 0) {
+ usage();
+ /* NOT REACHED */
+ }
+
+ openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ fromlen = sizeof (from);
+ if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ warn("getpeername");
+ _exit(1);
+ }
+ if (keepalive &&
+ setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof (on)) < 0) {
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+ }
+
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ if (from.ss_family == AF_INET) {
+# if defined(HAS_GETTOS)
+ struct tosent *tp;
+ if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+ tos = tp->t_tos;
+# endif
+ if (tos < 0)
+ tos = 020; /* Low Delay bit */
+ if (tos
+ && (setsockopt(0, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(tos)) < 0)
+ && (errno != ENOPROTOOPT) )
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
+ net = 0;
+ doit((struct sockaddr *)&from);
+ /* NOTREACHED */
+ return(0);
+} /* end of main */
+
+ void
+usage()
+{
+ fprintf(stderr, "usage: telnetd");
+#ifdef AUTHENTICATION
+ fprintf(stderr,
+ " [-4] [-6] [-a (debug|other|user|valid|off|none)]\n\t");
+#endif
+#ifdef BFTPDAEMON
+ fprintf(stderr, " [-B]");
+#endif
+ fprintf(stderr, " [-debug]");
+#ifdef DIAGNOSTICS
+ fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
+#endif
+#ifdef AUTHENTICATION
+ fprintf(stderr, " [-edebug]");
+#endif
+ fprintf(stderr, " [-h]");
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ fprintf(stderr, " [-k]");
+#endif
+#ifdef LINEMODE
+ fprintf(stderr, " [-l]");
+#endif
+ fprintf(stderr, " [-n]");
+ fprintf(stderr, "\n\t");
+#ifdef HAS_GETTOS
+ fprintf(stderr, " [-S tos]");
+#endif
+#ifdef AUTHENTICATION
+ fprintf(stderr, " [-X auth-type]");
+#endif
+ fprintf(stderr, " [-u utmp_hostname_length] [-U]");
+ fprintf(stderr, " [port]\n");
+ exit(1);
+}
+
+/*
+ * getterminaltype
+ *
+ * Ask the other end to send along its terminal type and speed.
+ * Output is the variable terminaltype filled in.
+ */
+static unsigned char ttytype_sbbuf[] = {
+ IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
+};
+
+
+#ifndef AUTHENTICATION
+#define undef2 __unused
+#else
+#define undef2
+#endif
+
+static int
+getterminaltype(char *name undef2)
+{
+ int retval = -1;
+
+ settimer(baseline);
+#ifdef AUTHENTICATION
+ /*
+ * Handle the Authentication option before we do anything else.
+ */
+ send_do(TELOPT_AUTHENTICATION, 1);
+ while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
+ ttloop();
+ if (his_state_is_will(TELOPT_AUTHENTICATION)) {
+ retval = auth_wait(name);
+ }
+#endif
+
+#ifdef ENCRYPTION
+ send_will(TELOPT_ENCRYPT, 1);
+#endif /* ENCRYPTION */
+ send_do(TELOPT_TTYPE, 1);
+ send_do(TELOPT_TSPEED, 1);
+ send_do(TELOPT_XDISPLOC, 1);
+ send_do(TELOPT_NEW_ENVIRON, 1);
+ send_do(TELOPT_OLD_ENVIRON, 1);
+ while (
+#ifdef ENCRYPTION
+ his_do_dont_is_changing(TELOPT_ENCRYPT) ||
+#endif /* ENCRYPTION */
+ his_will_wont_is_changing(TELOPT_TTYPE) ||
+ his_will_wont_is_changing(TELOPT_TSPEED) ||
+ his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+ his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
+ his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
+ ttloop();
+ }
+#ifdef ENCRYPTION
+ /*
+ * Wait for the negotiation of what type of encryption we can
+ * send with. If autoencrypt is not set, this will just return.
+ */
+ if (his_state_is_will(TELOPT_ENCRYPT)) {
+ encrypt_wait();
+ }
+#endif /* ENCRYPTION */
+ if (his_state_is_will(TELOPT_TSPEED)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ if (his_state_is_will(TELOPT_XDISPLOC)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ if (his_state_is_will(TELOPT_TTYPE)) {
+
+ output_datalen((char*)ttytype_sbbuf, sizeof ttytype_sbbuf);
+ DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
+ sizeof ttytype_sbbuf - 2););
+ }
+ if (his_state_is_will(TELOPT_TSPEED)) {
+ while (sequenceIs(tspeedsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_XDISPLOC)) {
+ while (sequenceIs(xdisplocsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+ while (sequenceIs(environsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+ while (sequenceIs(oenvironsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_TTYPE)) {
+ char first[256], last[256];
+
+ while (sequenceIs(ttypesubopt, baseline))
+ ttloop();
+
+ /*
+ * If the other side has already disabled the option, then
+ * we have to just go with what we (might) have already gotten.
+ */
+ if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
+ (void) strncpy(first, terminaltype, sizeof(first)-1);
+ first[sizeof(first)-1] = '\0';
+ for(;;) {
+ /*
+ * Save the unknown name, and request the next name.
+ */
+ (void) strncpy(last, terminaltype, sizeof(last)-1);
+ last[sizeof(last)-1] = '\0';
+ _gettermname();
+ if (terminaltypeok(terminaltype))
+ break;
+ if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+ his_state_is_wont(TELOPT_TTYPE)) {
+ /*
+ * We've hit the end. If this is the same as
+ * the first name, just go with it.
+ */
+ if (strncmp(first, terminaltype, sizeof(first)) == 0)
+ break;
+ /*
+ * Get the terminal name one more time, so that
+ * RFC1091 compliant telnets will cycle back to
+ * the start of the list.
+ */
+ _gettermname();
+ if (strncmp(first, terminaltype, sizeof(first)) != 0) {
+ (void) strncpy(terminaltype, first, sizeof(terminaltype)-1);
+ terminaltype[sizeof(terminaltype)-1] = '\0';
+ }
+ break;
+ }
+ }
+ }
+ }
+ return(retval);
+} /* end of getterminaltype */
+
+static void
+_gettermname(void)
+{
+ /*
+ * If the client turned off the option,
+ * we can't send another request, so we
+ * just return.
+ */
+ if (his_state_is_wont(TELOPT_TTYPE))
+ return;
+ settimer(baseline);
+ output_datalen((char*)ttytype_sbbuf, sizeof ttytype_sbbuf);
+ DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
+ sizeof ttytype_sbbuf - 2););
+ while (sequenceIs(ttypesubopt, baseline))
+ ttloop();
+}
+
+int
+terminaltypeok(char *s)
+{
+ char buf[1024];
+
+ if (terminaltype == NULL)
+ return(1);
+
+ /*
+ * tgetent() will return 1 if the type is known, and
+ * 0 if it is not known. If it returns -1, it couldn't
+ * open the database. But if we can't open the database,
+ * it won't help to say we failed, because we won't be
+ * able to verify anything else. So, we treat -1 like 1.
+ */
+ if (tgetent(buf, s) == 0)
+ return(0);
+ return(1);
+}
+
+#ifdef __APPLE__
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif /* MAXHOSTNAMELEN */
+
+char *hostname;
+char host_name[MAXHOSTNAMELEN];
+
+int level;
+char user_name[256];
+#endif /* __APPLE__ */
+
+/*
+ * Get a pty, scan input lines.
+ */
+void
+doit(struct sockaddr *who)
+{
+#ifndef __APPLE__
+ int err_; /* XXX */
+#else
+ char *host = NULL;
+ struct hostent *hp;
+#endif
+ int ptynum;
+
+ /*
+ * Find an available pty to use.
+ */
+#ifndef convex
+ spty = -1;
+ mpty = getpty(&ptynum, &spty);
+ if (mpty < 0)
+ fatal(net, "All network ports in use");
+#else
+ for (;;) {
+ char *lp;
+
+ if ((lp = getpty()) == NULL)
+ fatal(net, "Out of ptys");
+
+ if ((pty = open(lp, 2)) >= 0) {
+ strlcpy(line,lp,sizeof(line));
+ line[5] = 't';
+ break;
+ }
+ }
+#endif
+
+#ifdef __APPLE__
+ /* get name of connected client */
+ hp = gethostbyaddr((char *)&((struct sockaddr_in *)who)->sin_addr, sizeof (struct in_addr),
+ ((struct sockaddr_in *)who)->sin_family);
+
+ if (hp == NULL && registerd_host_only) {
+ fatal(net, "Couldn't resolve your address into a host name.\r\n\
+ Please contact your net administrator");
+ } else if (hp &&
+ (strlen(hp->h_name) <= utmp_len)) {
+ host = hp->h_name;
+ } else {
+ host = inet_ntoa(((struct sockaddr_in *)who)->sin_addr);
+ }
+ /*
+ * We must make a copy because Kerberos is probably going
+ * to also do a gethost* and overwrite the static data...
+ */
+ strncpy(remote_hostname, host, sizeof(remote_hostname)-1);
+ remote_hostname[sizeof(remote_hostname)-1] = 0;
+ host = remote_hostname;
+
+ (void) gethostname(host_name, sizeof(host_name) - 1);
+ host_name[sizeof(host_name) - 1] = '\0';
+ hostname = host_name;
+#else /* __APPLE__ */
+ /* get name of connected client */
+ if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
+ who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
+ fatal(net, "Couldn't resolve your address into a host name.\r\n\
+ Please contact your net administrator");
+ remote_hostname[sizeof(remote_hostname) - 1] = '\0';
+
+ trimdomain(remote_hostname, UT_HOSTSIZE);
+ if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
+ err_ = getnameinfo(who, who->sa_len, remote_hostname,
+ sizeof(remote_hostname), NULL, 0,
+ NI_NUMERICHOST);
+ /* XXX: do 'err_' check */
+
+ (void) gethostname(host_name, sizeof(host_name) - 1);
+ host_name[sizeof(host_name) - 1] = '\0';
+ hostname = host_name;
+#endif /* __APPLE__ */
+
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+/* The above #ifdefs should actually be "or"'ed, not "and"'ed.
+ * This is a byproduct of needing "#ifdef" and not "#if defined()"
+ * for unifdef. XXX MarkM
+ */
+ auth_encrypt_init(hostname, remote_hostname, "TELNETD", 1);
+#endif
+#endif
+
+ init_env();
+ /*
+ * get terminal type.
+ */
+ *user_name = 0;
+ level = getterminaltype(user_name);
+ setenv("TERM", terminaltype ? terminaltype : "network", 1);
+
+ telnet(net, mpty, remote_hostname); /* begin server process */
+
+ /*NOTREACHED*/
+} /* end of doit */
+
+/*
+ * Main loop. Select from pty and network, and
+ * hand data to telnet receiver finite state machine.
+ */
+void
+telnet(int f, int p, char *host)
+{
+ int on = 1;
+#define TABBUFSIZ 512
+ char defent[TABBUFSIZ];
+ char defstrs[TABBUFSIZ];
+#undef TABBUFSIZ
+ char *HE;
+ char *HN;
+ char *IM;
+#ifdef __APPLE__
+ char *IF = NULL;
+ int if_fd = -1;
+ char *if_buf;
+ struct stat statbuf;
+#endif
+ int nfd;
+
+ /*
+ * Initialize the slc mapping table.
+ */
+ get_slc_defaults();
+
+ /*
+ * Do some tests where it is desireable to wait for a response.
+ * Rather than doing them slowly, one at a time, do them all
+ * at once.
+ */
+ if (my_state_is_wont(TELOPT_SGA))
+ send_will(TELOPT_SGA, 1);
+ /*
+ * Is the client side a 4.2 (NOT 4.3) system? We need to know this
+ * because 4.2 clients are unable to deal with TCP urgent data.
+ *
+ * To find out, we send out a "DO ECHO". If the remote system
+ * answers "WILL ECHO" it is probably a 4.2 client, and we note
+ * that fact ("WILL ECHO" ==> that the client will echo what
+ * WE, the server, sends it; it does NOT mean that the client will
+ * echo the terminal input).
+ */
+ send_do(TELOPT_ECHO, 1);
+
+#ifdef LINEMODE
+ if (his_state_is_wont(TELOPT_LINEMODE)) {
+ /* Query the peer for linemode support by trying to negotiate
+ * the linemode option.
+ */
+ linemode = 0;
+ editmode = 0;
+ send_do(TELOPT_LINEMODE, 1); /* send do linemode */
+ }
+#endif /* LINEMODE */
+
+ /*
+ * Send along a couple of other options that we wish to negotiate.
+ */
+ send_do(TELOPT_NAWS, 1);
+ send_will(TELOPT_STATUS, 1);
+ flowmode = 1; /* default flow control state */
+ restartany = -1; /* uninitialized... */
+ send_do(TELOPT_LFLOW, 1);
+
+ /*
+ * Spin, waiting for a response from the DO ECHO. However,
+ * some REALLY DUMB telnets out there might not respond
+ * to the DO ECHO. So, we spin looking for NAWS, (most dumb
+ * telnets so far seem to respond with WONT for a DO that
+ * they don't understand...) because by the time we get the
+ * response, it will already have processed the DO ECHO.
+ * Kludge upon kludge.
+ */
+ while (his_will_wont_is_changing(TELOPT_NAWS))
+ ttloop();
+
+ /*
+ * But...
+ * The client might have sent a WILL NAWS as part of its
+ * startup code; if so, we'll be here before we get the
+ * response to the DO ECHO. We'll make the assumption
+ * that any implementation that understands about NAWS
+ * is a modern enough implementation that it will respond
+ * to our DO ECHO request; hence we'll do another spin
+ * waiting for the ECHO option to settle down, which is
+ * what we wanted to do in the first place...
+ */
+ if (his_want_state_is_will(TELOPT_ECHO) &&
+ his_state_is_will(TELOPT_NAWS)) {
+ while (his_will_wont_is_changing(TELOPT_ECHO))
+ ttloop();
+ }
+ /*
+ * On the off chance that the telnet client is broken and does not
+ * respond to the DO ECHO we sent, (after all, we did send the
+ * DO NAWS negotiation after the DO ECHO, and we won't get here
+ * until a response to the DO NAWS comes back) simulate the
+ * receipt of a will echo. This will also send a WONT ECHO
+ * to the client, since we assume that the client failed to
+ * respond because it believes that it is already in DO ECHO
+ * mode, which we do not want.
+ */
+ if (his_want_state_is_will(TELOPT_ECHO)) {
+ DIAG(TD_OPTIONS, output_data("td: simulating recv\r\n"));
+ willoption(TELOPT_ECHO);
+ }
+
+ /*
+ * Finally, to clean things up, we turn on our echo. This
+ * will break stupid 4.2 telnets out of local terminal echo.
+ */
+
+ if (my_state_is_wont(TELOPT_ECHO))
+ send_will(TELOPT_ECHO, 1);
+
+ /*
+ * Turn on packet mode
+ */
+ (void) ioctl(p, TIOCPKT, (char *)&on);
+
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * Continuing line mode support. If client does not support
+ * real linemode, attempt to negotiate kludge linemode by sending
+ * the do timing mark sequence.
+ */
+ if (lmodetype < REAL_LINEMODE)
+ send_do(TELOPT_TM, 1);
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+ /*
+ * Call telrcv() once to pick up anything received during
+ * terminal type negotiation, 4.2/4.3 determination, and
+ * linemode negotiation.
+ */
+ telrcv();
+
+ (void) ioctl(f, FIONBIO, (char *)&on);
+ (void) ioctl(p, FIONBIO, (char *)&on);
+
+#if defined(SO_OOBINLINE)
+ (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
+ (char *)&on, sizeof on);
+#endif /* defined(SO_OOBINLINE) */
+
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ /*
+ * Ignoring SIGTTOU keeps the kernel from blocking us
+ * in ttioct() in /sys/tty.c.
+ */
+ (void) signal(SIGTTOU, SIG_IGN);
+#endif
+
+ (void) signal(SIGCHLD, cleanup);
+
+#ifdef TIOCNOTTY
+ {
+ int t;
+ t = open(_PATH_TTY, O_RDWR);
+ if (t >= 0) {
+ (void) ioctl(t, TIOCNOTTY, (char *)0);
+ (void) close(t);
+ }
+ }
+#endif
+
+ /*
+ * Show banner that getty never gave.
+ *
+ * We put the banner in the pty input buffer. This way, it
+ * gets carriage return null processing, etc., just like all
+ * other pty --> client data.
+ */
+
+#ifdef __APPLE__
+ if (getenv("USER"))
+ hostinfo = 0;
+#endif
+ if (getent(defent, "default") == 1) {
+ char *cp=defstrs;
+
+ HE = Getstr("he", &cp);
+ HN = Getstr("hn", &cp);
+ IM = Getstr("im", &cp);
+#ifdef __APPLE__
+ IF = Getstr("if", &cp);
+#endif
+ if (HN && *HN)
+ (void) strlcpy(host_name, HN, sizeof(host_name));
+#ifdef __APPLE__
+ if (IF && (if_fd = open(IF, O_RDONLY, 000)) != -1)
+ IM = 0;
+#endif
+ if (IM == 0)
+ IM = strdup("");
+ } else {
+ IM = strdup(DEFAULT_IM);
+ HE = 0;
+ }
+ edithost(HE, host_name);
+ if (hostinfo && *IM)
+ putf(IM, ptyibuf2);
+#ifdef __APPLE__
+ else if (IF && if_fd != -1) {
+ fstat (if_fd, &statbuf);
+ if_buf = (char *) mmap (0, statbuf.st_size, PROT_READ,
+ 0, if_fd, 0);
+ putf(if_buf, ptyibuf2);
+ munmap (if_buf, statbuf.st_size);
+ close (if_fd);
+ }
+#endif
+
+ if (pcc)
+ (void) strncat(ptyibuf2, ptyip, pcc+1);
+ ptyip = ptyibuf2;
+ pcc = strlen(ptyip);
+#ifdef LINEMODE
+ /*
+ * Last check to make sure all our states are correct.
+ */
+ init_termbuf();
+ localstat();
+#endif /* LINEMODE */
+
+ DIAG(TD_REPORT, output_data("td: Entering processing loop\r\n"));
+
+ /*
+ * Startup the login process on the slave side of the terminal
+ * now. We delay this until here to insure option negotiation
+ * is complete.
+ */
+ startslave(host, level, user_name);
+
+ nfd = ((f > p) ? f : p) + 1;
+ for (;;) {
+ fd_set ibits, obits, xbits;
+ int c;
+
+ if (ncc < 0 && pcc < 0)
+ break;
+
+ FD_ZERO(&ibits);
+ FD_ZERO(&obits);
+ FD_ZERO(&xbits);
+ /*
+ * Never look for input if there's still
+ * stuff in the corresponding output buffer
+ */
+ if (nfrontp - nbackp || pcc > 0) {
+ FD_SET(f, &obits);
+ } else {
+ FD_SET(p, &ibits);
+ }
+ if (pfrontp - pbackp || ncc > 0) {
+ FD_SET(p, &obits);
+ } else {
+ FD_SET(f, &ibits);
+ }
+ if (!SYNCHing) {
+ FD_SET(f, &xbits);
+ }
+ if ((c = select(nfd, &ibits, &obits, &xbits,
+ (struct timeval *)0)) < 1) {
+ if (c == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ }
+ sleep(5);
+ continue;
+ }
+
+ /*
+ * Any urgent data?
+ */
+ if (FD_ISSET(net, &xbits)) {
+ SYNCHing = 1;
+ }
+
+ /*
+ * Something to read from the network...
+ */
+ if (FD_ISSET(net, &ibits)) {
+#if !defined(SO_OOBINLINE)
+ /*
+ * In 4.2 (and 4.3 beta) systems, the
+ * OOB indication and data handling in the kernel
+ * is such that if two separate TCP Urgent requests
+ * come in, one byte of TCP data will be overlaid.
+ * This is fatal for Telnet, but we try to live
+ * with it.
+ *
+ * In addition, in 4.2 (and...), a special protocol
+ * is needed to pick up the TCP Urgent data in
+ * the correct sequence.
+ *
+ * What we do is: if we think we are in urgent
+ * mode, we look to see if we are "at the mark".
+ * If we are, we do an OOB receive. If we run
+ * this twice, we will do the OOB receive twice,
+ * but the second will fail, since the second
+ * time we were "at the mark", but there wasn't
+ * any data there (the kernel doesn't reset
+ * "at the mark" until we do a normal read).
+ * Once we've read the OOB data, we go ahead
+ * and do normal reads.
+ *
+ * There is also another problem, which is that
+ * since the OOB byte we read doesn't put us
+ * out of OOB state, and since that byte is most
+ * likely the TELNET DM (data mark), we would
+ * stay in the TELNET SYNCH (SYNCHing) state.
+ * So, clocks to the rescue. If we've "just"
+ * received a DM, then we test for the
+ * presence of OOB data when the receive OOB
+ * fails (and AFTER we did the normal mode read
+ * to clear "at the mark").
+ */
+ if (SYNCHing) {
+ int atmark;
+
+ (void) ioctl(net, SIOCATMARK, (char *)&atmark);
+ if (atmark) {
+ ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
+ if ((ncc == -1) && (errno == EINVAL)) {
+ ncc = read(net, netibuf, sizeof (netibuf));
+ if (sequenceIs(didnetreceive, gotDM)) {
+ SYNCHing = stilloob(net);
+ }
+ }
+ } else {
+ ncc = read(net, netibuf, sizeof (netibuf));
+ }
+ } else {
+ ncc = read(net, netibuf, sizeof (netibuf));
+ }
+ settimer(didnetreceive);
+#else /* !defined(SO_OOBINLINE)) */
+ ncc = read(net, netibuf, sizeof (netibuf));
+#endif /* !defined(SO_OOBINLINE)) */
+ if (ncc < 0 && errno == EWOULDBLOCK)
+ ncc = 0;
+ else {
+ if (ncc <= 0) {
+ break;
+ }
+ netip = netibuf;
+ }
+ DIAG((TD_REPORT | TD_NETDATA),
+ output_data("td: netread %d chars\r\n", ncc));
+ DIAG(TD_NETDATA, printdata("nd", netip, ncc));
+ }
+
+ /*
+ * Something to read from the pty...
+ */
+ if (FD_ISSET(p, &ibits)) {
+ pcc = read(p, ptyibuf, BUFSIZ);
+ /*
+ * On some systems, if we try to read something
+ * off the master side before the slave side is
+ * opened, we get EIO.
+ */
+ if (pcc < 0 && (errno == EWOULDBLOCK ||
+#ifdef EAGAIN
+ errno == EAGAIN ||
+#endif
+ errno == EIO)) {
+ pcc = 0;
+ } else {
+ if (pcc <= 0)
+ break;
+#ifdef LINEMODE
+ /*
+ * If ioctl from pty, pass it through net
+ */
+ if (ptyibuf[0] & TIOCPKT_IOCTL) {
+ copy_termbuf(ptyibuf+1, pcc-1);
+ localstat();
+ pcc = 1;
+ }
+#endif /* LINEMODE */
+ if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+ netclear(); /* clear buffer back */
+#ifndef NO_URGENT
+ /*
+ * There are client telnets on some
+ * operating systems get screwed up
+ * royally if we send them urgent
+ * mode data.
+ */
+ output_data("%c%c", IAC, DM);
+ neturg = nfrontp-1; /* off by one XXX */
+ DIAG(TD_OPTIONS,
+ printoption("td: send IAC", DM));
+
+#endif
+ }
+ if (his_state_is_will(TELOPT_LFLOW) &&
+ (ptyibuf[0] &
+ (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
+ int newflow =
+ ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
+ if (newflow != flowmode) {
+ flowmode = newflow;
+ output_data("%c%c%c%c%c%c",
+ IAC, SB, TELOPT_LFLOW,
+ flowmode ? LFLOW_ON
+ : LFLOW_OFF,
+ IAC, SE);
+ DIAG(TD_OPTIONS, printsub('>',
+ (unsigned char *)nfrontp-4,
+ 4););
+ }
+ }
+ pcc--;
+ ptyip = ptyibuf+1;
+ }
+ }
+
+ while (pcc > 0) {
+ if ((&netobuf[BUFSIZ] - nfrontp) < 2)
+ break;
+ c = *ptyip++ & 0377, pcc--;
+ if (c == IAC)
+ output_data("%c", c);
+ output_data("%c", c);
+ if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
+ if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
+ output_data("%c", *ptyip++ & 0377);
+ pcc--;
+ } else
+ output_data("%c", '\0');
+ }
+ }
+
+ if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
+ netflush();
+ if (ncc > 0)
+ telrcv();
+ if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
+ ptyflush();
+ }
+ cleanup(0);
+} /* end of telnet */
+
+#ifndef TCSIG
+# ifdef TIOCSIG
+# define TCSIG TIOCSIG
+# endif
+#endif
+
+/*
+ * Send interrupt to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write intr char.
+ */
+void
+interrupt(void)
+{
+ ptyflush(); /* half-hearted */
+
+#ifdef TCSIG
+ (void) ioctl(mpty, TCSIG, (char *)SIGINT);
+#else /* TCSIG */
+ init_termbuf();
+ *pfrontp++ = slctab[SLC_IP].sptr ?
+ (unsigned char)*slctab[SLC_IP].sptr : '\177';
+#endif /* TCSIG */
+}
+
+/*
+ * Send quit to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write quit char.
+ */
+void
+sendbrk(void)
+{
+ ptyflush(); /* half-hearted */
+#ifdef TCSIG
+ (void) ioctl(mpty, TCSIG, (char *)SIGQUIT);
+#else /* TCSIG */
+ init_termbuf();
+ *pfrontp++ = slctab[SLC_ABORT].sptr ?
+ (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
+#endif /* TCSIG */
+}
+
+void
+sendsusp(void)
+{
+#ifdef SIGTSTP
+ ptyflush(); /* half-hearted */
+# ifdef TCSIG
+ (void) ioctl(mpty, TCSIG, (char *)SIGTSTP);
+# else /* TCSIG */
+ *pfrontp++ = slctab[SLC_SUSP].sptr ?
+ (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
+# endif /* TCSIG */
+#endif /* SIGTSTP */
+}
+
+/*
+ * When we get an AYT, if ^T is enabled, use that. Otherwise,
+ * just send back "[Yes]".
+ */
+void
+recv_ayt(void)
+{
+#if defined(SIGINFO) && defined(TCSIG)
+ if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
+ (void) ioctl(spty, TCSIG, (char *)SIGINFO);
+ return;
+ }
+#endif
+ output_data("\r\n[Yes]\r\n");
+}
+
+void
+doeof(void)
+{
+ init_termbuf();
+
+#if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
+ if (!tty_isediting()) {
+ extern char oldeofc;
+ *pfrontp++ = oldeofc;
+ return;
+ }
+#endif
+ *pfrontp++ = slctab[SLC_EOF].sptr ?
+ (unsigned char)*slctab[SLC_EOF].sptr : '\004';
+}
diff --git a/remote_cmds/telnetd.tproj/telnetd.h b/remote_cmds/telnetd.tproj/telnetd.h
new file mode 100644
index 0000000..e99a7c9
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnetd.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)telnetd.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/contrib/telnet/telnetd/telnetd.h,v 1.2 2001/11/30 21:06:38 markm Exp $
+ */
+
+
+#include "defs.h"
+#include "ext.h"
+
+#ifdef DIAGNOSTICS
+#define DIAG(a,b) if (diagnostic & (a)) b
+#else
+#define DIAG(a,b)
+#endif
+
+/* other external variables */
+extern char **environ;
+extern const char *altlogin;
diff --git a/remote_cmds/telnetd.tproj/termstat.c b/remote_cmds/telnetd.tproj/termstat.c
new file mode 100644
index 0000000..e29e526
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/termstat.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/termstat.c,v 1.13 2004/07/28 05:37:18 kan Exp $");
+
+#include "telnetd.h"
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/*
+ * local variables
+ */
+int def_tspeed = -1, def_rspeed = -1;
+#ifdef TIOCSWINSZ
+int def_row = 0, def_col = 0;
+#endif
+#ifdef LINEMODE
+static int _terminit = 0;
+#endif /* LINEMODE */
+
+#ifdef LINEMODE
+/*
+ * localstat
+ *
+ * This function handles all management of linemode.
+ *
+ * Linemode allows the client to do the local editing of data
+ * and send only complete lines to the server. Linemode state is
+ * based on the state of the pty driver. If the pty is set for
+ * external processing, then we can use linemode. Further, if we
+ * can use real linemode, then we can look at the edit control bits
+ * in the pty to determine what editing the client should do.
+ *
+ * Linemode support uses the following state flags to keep track of
+ * current and desired linemode state.
+ * alwayslinemode : true if -l was specified on the telnetd
+ * command line. It means to have linemode on as much as
+ * possible.
+ *
+ * lmodetype: signifies whether the client can
+ * handle real linemode, or if use of kludgeomatic linemode
+ * is preferred. It will be set to one of the following:
+ * REAL_LINEMODE : use linemode option
+ * NO_KLUDGE : don't initiate kludge linemode.
+ * KLUDGE_LINEMODE : use kludge linemode
+ * NO_LINEMODE : client is ignorant of linemode
+ *
+ * linemode, uselinemode : linemode is true if linemode
+ * is currently on, uselinemode is the state that we wish
+ * to be in. If another function wishes to turn linemode
+ * on or off, it sets or clears uselinemode.
+ *
+ * editmode, useeditmode : like linemode/uselinemode, but
+ * these contain the edit mode states (edit and trapsig).
+ *
+ * The state variables correspond to some of the state information
+ * in the pty.
+ * linemode:
+ * In real linemode, this corresponds to whether the pty
+ * expects external processing of incoming data.
+ * In kludge linemode, this more closely corresponds to the
+ * whether normal processing is on or not. (ICANON in
+ * system V, or COOKED mode in BSD.)
+ * If the -l option was specified (alwayslinemode), then
+ * an attempt is made to force external processing on at
+ * all times.
+ *
+ * The following heuristics are applied to determine linemode
+ * handling within the server.
+ * 1) Early on in starting up the server, an attempt is made
+ * to negotiate the linemode option. If this succeeds
+ * then lmodetype is set to REAL_LINEMODE and all linemode
+ * processing occurs in the context of the linemode option.
+ * 2) If the attempt to negotiate the linemode option failed,
+ * and the "-k" (don't initiate kludge linemode) isn't set,
+ * then we try to use kludge linemode. We test for this
+ * capability by sending "do Timing Mark". If a positive
+ * response comes back, then we assume that the client
+ * understands kludge linemode (ech!) and the
+ * lmodetype flag is set to KLUDGE_LINEMODE.
+ * 3) Otherwise, linemode is not supported at all and
+ * lmodetype remains set to NO_LINEMODE (which happens
+ * to be 0 for convenience).
+ * 4) At any time a command arrives that implies a higher
+ * state of linemode support in the client, we move to that
+ * linemode support.
+ *
+ * A short explanation of kludge linemode is in order here.
+ * 1) The heuristic to determine support for kludge linemode
+ * is to send a do timing mark. We assume that a client
+ * that supports timing marks also supports kludge linemode.
+ * A risky proposition at best.
+ * 2) Further negotiation of linemode is done by changing the
+ * the server's state regarding SGA. If server will SGA,
+ * then linemode is off, if server won't SGA, then linemode
+ * is on.
+ */
+void
+localstat(void)
+{
+ int need_will_echo = 0;
+
+ /*
+ * Check for changes to flow control if client supports it.
+ */
+ flowstat();
+
+ /*
+ * Check linemode on/off state
+ */
+ uselinemode = tty_linemode();
+
+ /*
+ * If alwayslinemode is on, and pty is changing to turn it off, then
+ * force linemode back on.
+ */
+ if (alwayslinemode && linemode && !uselinemode) {
+ uselinemode = 1;
+ tty_setlinemode(uselinemode);
+ }
+
+ if (uselinemode) {
+ /*
+ * Check for state of BINARY options.
+ *
+ * We only need to do the binary dance if we are actually going
+ * to use linemode. As this confuses some telnet clients
+ * that don't support linemode, and doesn't gain us
+ * anything, we don't do it unless we're doing linemode.
+ * -Crh (henrich@msu.edu)
+ */
+
+ if (tty_isbinaryin()) {
+ if (his_want_state_is_wont(TELOPT_BINARY))
+ send_do(TELOPT_BINARY, 1);
+ } else {
+ if (his_want_state_is_will(TELOPT_BINARY))
+ send_dont(TELOPT_BINARY, 1);
+ }
+
+ if (tty_isbinaryout()) {
+ if (my_want_state_is_wont(TELOPT_BINARY))
+ send_will(TELOPT_BINARY, 1);
+ } else {
+ if (my_want_state_is_will(TELOPT_BINARY))
+ send_wont(TELOPT_BINARY, 1);
+ }
+ }
+
+#ifdef ENCRYPTION
+ /*
+ * If the terminal is not echoing, but editing is enabled,
+ * something like password input is going to happen, so
+ * if we the other side is not currently sending encrypted
+ * data, ask the other side to start encrypting.
+ */
+ if (his_state_is_will(TELOPT_ENCRYPT)) {
+ static int enc_passwd = 0;
+ if (uselinemode && !tty_isecho() && tty_isediting()
+ && (enc_passwd == 0) && !decrypt_input) {
+ encrypt_send_request_start();
+ enc_passwd = 1;
+ } else if (enc_passwd) {
+ encrypt_send_request_end();
+ enc_passwd = 0;
+ }
+ }
+#endif /* ENCRYPTION */
+
+ /*
+ * Do echo mode handling as soon as we know what the
+ * linemode is going to be.
+ * If the pty has echo turned off, then tell the client that
+ * the server will echo. If echo is on, then the server
+ * will echo if in character mode, but in linemode the
+ * client should do local echoing. The state machine will
+ * not send anything if it is unnecessary, so don't worry
+ * about that here.
+ *
+ * If we need to send the WILL ECHO (because echo is off),
+ * then delay that until after we have changed the MODE.
+ * This way, when the user is turning off both editing
+ * and echo, the client will get editing turned off first.
+ * This keeps the client from going into encryption mode
+ * and then right back out if it is doing auto-encryption
+ * when passwords are being typed.
+ */
+ if (uselinemode) {
+ if (tty_isecho())
+ send_wont(TELOPT_ECHO, 1);
+ else
+ need_will_echo = 1;
+#ifdef KLUDGELINEMODE
+ if (lmodetype == KLUDGE_OK)
+ lmodetype = KLUDGE_LINEMODE;
+#endif
+ }
+
+ /*
+ * If linemode is being turned off, send appropriate
+ * command and then we're all done.
+ */
+ if (!uselinemode && linemode) {
+# ifdef KLUDGELINEMODE
+ if (lmodetype == REAL_LINEMODE) {
+# endif /* KLUDGELINEMODE */
+ send_dont(TELOPT_LINEMODE, 1);
+# ifdef KLUDGELINEMODE
+ } else if (lmodetype == KLUDGE_LINEMODE)
+ send_will(TELOPT_SGA, 1);
+# endif /* KLUDGELINEMODE */
+ send_will(TELOPT_ECHO, 1);
+ linemode = uselinemode;
+ goto done;
+ }
+
+# ifdef KLUDGELINEMODE
+ /*
+ * If using real linemode check edit modes for possible later use.
+ * If we are in kludge linemode, do the SGA negotiation.
+ */
+ if (lmodetype == REAL_LINEMODE) {
+# endif /* KLUDGELINEMODE */
+ useeditmode = 0;
+ if (tty_isediting())
+ useeditmode |= MODE_EDIT;
+ if (tty_istrapsig())
+ useeditmode |= MODE_TRAPSIG;
+ if (tty_issofttab())
+ useeditmode |= MODE_SOFT_TAB;
+ if (tty_islitecho())
+ useeditmode |= MODE_LIT_ECHO;
+# ifdef KLUDGELINEMODE
+ } else if (lmodetype == KLUDGE_LINEMODE) {
+ if (tty_isediting() && uselinemode)
+ send_wont(TELOPT_SGA, 1);
+ else
+ send_will(TELOPT_SGA, 1);
+ }
+# endif /* KLUDGELINEMODE */
+
+ /*
+ * Negotiate linemode on if pty state has changed to turn it on.
+ * Send appropriate command and send along edit mode, then all done.
+ */
+ if (uselinemode && !linemode) {
+# ifdef KLUDGELINEMODE
+ if (lmodetype == KLUDGE_LINEMODE) {
+ send_wont(TELOPT_SGA, 1);
+ } else if (lmodetype == REAL_LINEMODE) {
+# endif /* KLUDGELINEMODE */
+ send_do(TELOPT_LINEMODE, 1);
+ /* send along edit modes */
+ output_data("%c%c%c%c%c%c%c", IAC, SB,
+ TELOPT_LINEMODE, LM_MODE, useeditmode,
+ IAC, SE);
+ editmode = useeditmode;
+# ifdef KLUDGELINEMODE
+ }
+# endif /* KLUDGELINEMODE */
+ linemode = uselinemode;
+ goto done;
+ }
+
+# ifdef KLUDGELINEMODE
+ /*
+ * None of what follows is of any value if not using
+ * real linemode.
+ */
+ if (lmodetype < REAL_LINEMODE)
+ goto done;
+# endif /* KLUDGELINEMODE */
+
+ if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
+ /*
+ * If edit mode changed, send edit mode.
+ */
+ if (useeditmode != editmode) {
+ /*
+ * Send along appropriate edit mode mask.
+ */
+ output_data("%c%c%c%c%c%c%c", IAC, SB,
+ TELOPT_LINEMODE, LM_MODE, useeditmode,
+ IAC, SE);
+ editmode = useeditmode;
+ }
+
+
+ /*
+ * Check for changes to special characters in use.
+ */
+ start_slc(0);
+ check_slc();
+ (void) end_slc(0);
+ }
+
+done:
+ if (need_will_echo)
+ send_will(TELOPT_ECHO, 1);
+ /*
+ * Some things should be deferred until after the pty state has
+ * been set by the local process. Do those things that have been
+ * deferred now. This only happens once.
+ */
+ if (_terminit == 0) {
+ _terminit = 1;
+ defer_terminit();
+ }
+
+ netflush();
+ set_termbuf();
+ return;
+
+} /* end of localstat */
+#endif /* LINEMODE */
+
+/*
+ * flowstat
+ *
+ * Check for changes to flow control
+ */
+void
+flowstat(void)
+{
+ if (his_state_is_will(TELOPT_LFLOW)) {
+ if (tty_flowmode() != flowmode) {
+ flowmode = tty_flowmode();
+ output_data("%c%c%c%c%c%c",
+ IAC, SB, TELOPT_LFLOW,
+ flowmode ? LFLOW_ON : LFLOW_OFF,
+ IAC, SE);
+ }
+ if (tty_restartany() != restartany) {
+ restartany = tty_restartany();
+ output_data("%c%c%c%c%c%c",
+ IAC, SB, TELOPT_LFLOW,
+ restartany ? LFLOW_RESTART_ANY
+ : LFLOW_RESTART_XON,
+ IAC, SE);
+ }
+ }
+}
+
+/*
+ * clientstat
+ *
+ * Process linemode related requests from the client.
+ * Client can request a change to only one of linemode, editmode or slc's
+ * at a time, and if using kludge linemode, then only linemode may be
+ * affected.
+ */
+void
+clientstat(int code, int parm1, int parm2)
+{
+
+ /*
+ * Get a copy of terminal characteristics.
+ */
+ init_termbuf();
+
+ /*
+ * Process request from client. code tells what it is.
+ */
+ switch (code) {
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+ /*
+ * Don't do anything unless client is asking us to change
+ * modes.
+ */
+ uselinemode = (parm1 == WILL);
+ if (uselinemode != linemode) {
+# ifdef KLUDGELINEMODE
+ /*
+ * If using kludge linemode, make sure that
+ * we can do what the client asks.
+ * We can not turn off linemode if alwayslinemode
+ * and the ICANON bit is set.
+ */
+ if (lmodetype == KLUDGE_LINEMODE) {
+ if (alwayslinemode && tty_isediting()) {
+ uselinemode = 1;
+ }
+ }
+
+ /*
+ * Quit now if we can't do it.
+ */
+ if (uselinemode == linemode)
+ return;
+
+ /*
+ * If using real linemode and linemode is being
+ * turned on, send along the edit mode mask.
+ */
+ if (lmodetype == REAL_LINEMODE && uselinemode)
+# else /* KLUDGELINEMODE */
+ if (uselinemode)
+# endif /* KLUDGELINEMODE */
+ {
+ useeditmode = 0;
+ if (tty_isediting())
+ useeditmode |= MODE_EDIT;
+ if (tty_istrapsig())
+ useeditmode |= MODE_TRAPSIG;
+ if (tty_issofttab())
+ useeditmode |= MODE_SOFT_TAB;
+ if (tty_islitecho())
+ useeditmode |= MODE_LIT_ECHO;
+ output_data("%c%c%c%c%c%c%c", IAC,
+ SB, TELOPT_LINEMODE, LM_MODE,
+ useeditmode, IAC, SE);
+ editmode = useeditmode;
+ }
+
+
+ tty_setlinemode(uselinemode);
+
+ linemode = uselinemode;
+
+ if (!linemode)
+ send_will(TELOPT_ECHO, 1);
+ }
+ break;
+
+ case LM_MODE:
+ {
+ int ack, changed;
+
+ /*
+ * Client has sent along a mode mask. If it agrees with
+ * what we are currently doing, ignore it; if not, it could
+ * be viewed as a request to change. Note that the server
+ * will change to the modes in an ack if it is different from
+ * what we currently have, but we will not ack the ack.
+ */
+ useeditmode &= MODE_MASK;
+ ack = (useeditmode & MODE_ACK);
+ useeditmode &= ~MODE_ACK;
+
+ if ((changed = (useeditmode ^ editmode))) {
+ /*
+ * This check is for a timing problem. If the
+ * state of the tty has changed (due to the user
+ * application) we need to process that info
+ * before we write in the state contained in the
+ * ack!!! This gets out the new MODE request,
+ * and when the ack to that command comes back
+ * we'll set it and be in the right mode.
+ */
+ if (ack)
+ localstat();
+ if (changed & MODE_EDIT)
+ tty_setedit(useeditmode & MODE_EDIT);
+
+ if (changed & MODE_TRAPSIG)
+ tty_setsig(useeditmode & MODE_TRAPSIG);
+
+ if (changed & MODE_SOFT_TAB)
+ tty_setsofttab(useeditmode & MODE_SOFT_TAB);
+
+ if (changed & MODE_LIT_ECHO)
+ tty_setlitecho(useeditmode & MODE_LIT_ECHO);
+
+ set_termbuf();
+
+ if (!ack) {
+ output_data("%c%c%c%c%c%c%c", IAC,
+ SB, TELOPT_LINEMODE, LM_MODE,
+ useeditmode|MODE_ACK,
+ IAC, SE);
+ }
+
+ editmode = useeditmode;
+ }
+
+ break;
+
+ } /* end of case LM_MODE */
+#endif /* LINEMODE */
+
+ case TELOPT_NAWS:
+#ifdef TIOCSWINSZ
+ {
+ struct winsize ws;
+
+ def_col = parm1;
+ def_row = parm2;
+#ifdef LINEMODE
+ /*
+ * Defer changing window size until after terminal is
+ * initialized.
+ */
+ if (terminit() == 0)
+ return;
+#endif /* LINEMODE */
+
+ /*
+ * Change window size as requested by client.
+ */
+
+ ws.ws_col = parm1;
+ ws.ws_row = parm2;
+ (void) ioctl(spty, TIOCSWINSZ, (char *)&ws);
+ }
+#endif /* TIOCSWINSZ */
+
+ break;
+
+ case TELOPT_TSPEED:
+ {
+ def_tspeed = parm1;
+ def_rspeed = parm2;
+#ifdef LINEMODE
+ /*
+ * Defer changing the terminal speed.
+ */
+ if (terminit() == 0)
+ return;
+#endif /* LINEMODE */
+ /*
+ * Change terminal speed as requested by client.
+ * We set the receive speed first, so that if we can't
+ * store separate receive and transmit speeds, the transmit
+ * speed will take precedence.
+ */
+ tty_rspeed(parm2);
+ tty_tspeed(parm1);
+ set_termbuf();
+
+ break;
+
+ } /* end of case TELOPT_TSPEED */
+
+ default:
+ /* What? */
+ break;
+ } /* end of switch */
+
+ netflush();
+
+} /* end of clientstat */
+
+#ifdef LINEMODE
+/*
+ * defer_terminit
+ *
+ * Some things should not be done until after the login process has started
+ * and all the pty modes are set to what they are supposed to be. This
+ * function is called when the pty state has been processed for the first time.
+ * It calls other functions that do things that were deferred in each module.
+ */
+void
+defer_terminit(void)
+{
+
+ /*
+ * local stuff that got deferred.
+ */
+ if (def_tspeed != -1) {
+ clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
+ def_tspeed = def_rspeed = 0;
+ }
+
+#ifdef TIOCSWINSZ
+ if (def_col || def_row) {
+ struct winsize ws;
+
+ memset((char *)&ws, 0, sizeof(ws));
+ ws.ws_col = def_col;
+ ws.ws_row = def_row;
+ (void) ioctl(spty, TIOCSWINSZ, (char *)&ws);
+ }
+#endif
+
+ /*
+ * The only other module that currently defers anything.
+ */
+ deferslc();
+
+} /* end of defer_terminit */
+
+/*
+ * terminit
+ *
+ * Returns true if the pty state has been processed yet.
+ */
+int
+terminit(void)
+{
+ return(_terminit);
+
+} /* end of terminit */
+#endif /* LINEMODE */
diff --git a/remote_cmds/telnetd.tproj/utility.c b/remote_cmds/telnetd.tproj/utility.c
new file mode 100644
index 0000000..306c027
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/utility.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/utility.c,v 1.13 2003/05/04 02:54:49 obrien Exp $");
+
+#ifdef __FreeBSD__
+#include <locale.h>
+#include <sys/utsname.h>
+#endif
+#include <string.h>
+#define PRINTOPTIONS
+#include "telnetd.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/*
+ * utility functions performing io related tasks
+ */
+
+/*
+ * ttloop
+ *
+ * A small subroutine to flush the network output buffer, get some data
+ * from the network, and pass it through the telnet state machine. We
+ * also flush the pty input buffer (by dropping its data) if it becomes
+ * too full.
+ */
+
+ void
+ttloop()
+{
+
+ DIAG(TD_REPORT, output_data("td: ttloop\r\n"));
+ if (nfrontp - nbackp > 0) {
+ netflush();
+ }
+ ncc = read(net, netibuf, sizeof netibuf);
+ if (ncc < 0) {
+ syslog(LOG_INFO, "ttloop: read: %m");
+ exit(1);
+ } else if (ncc == 0) {
+ syslog(LOG_INFO, "ttloop: peer died: %m");
+ exit(1);
+ }
+ DIAG(TD_REPORT, output_data("td: ttloop read %d chars\r\n", ncc));
+ netip = netibuf;
+ telrcv(); /* state machine */
+ if (ncc > 0) {
+ pfrontp = pbackp = ptyobuf;
+ telrcv();
+ }
+} /* end of ttloop */
+
+/*
+ * Check a descriptor to see if out of band data exists on it.
+ */
+int
+stilloob(int s)
+{
+ static struct timeval timeout = { 0, 0 };
+ fd_set excepts;
+ int value;
+
+ do {
+ FD_ZERO(&excepts);
+ FD_SET(s, &excepts);
+ memset((char *)&timeout, 0, sizeof timeout);
+ value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
+ } while ((value == -1) && (errno == EINTR));
+
+ if (value < 0) {
+ fatalperror(mpty, "select");
+ }
+ if (FD_ISSET(s, &excepts)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void
+ptyflush(void)
+{
+ int n;
+
+ if ((n = pfrontp - pbackp) > 0) {
+ DIAG(TD_REPORT | TD_PTYDATA,
+ output_data("td: ptyflush %d chars\r\n", n));
+ DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
+ n = write(mpty, pbackp, n);
+ }
+ if (n < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ return;
+ cleanup(0);
+ }
+ pbackp += n;
+ if (pbackp == pfrontp)
+ pbackp = pfrontp = ptyobuf;
+}
+
+/*
+ * nextitem()
+ *
+ * Return the address of the next "item" in the TELNET data
+ * stream. This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
+static char *
+nextitem(char *current)
+{
+ if ((*current&0xff) != IAC) {
+ return current+1;
+ }
+ switch (*(current+1)&0xff) {
+ case DO:
+ case DONT:
+ case WILL:
+ case WONT:
+ return current+3;
+ case SB: /* loop forever looking for the SE */
+ {
+ char *look = current+2;
+
+ for (;;) {
+ if ((*look++&0xff) == IAC) {
+ if ((*look++&0xff) == SE) {
+ return look;
+ }
+ }
+ }
+ }
+ default:
+ return current+2;
+ }
+} /* end of nextitem */
+
+/*
+ * netclear()
+ *
+ * We are about to do a TELNET SYNCH operation. Clear
+ * the path to the network.
+ *
+ * Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ * A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer. The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
+ */
+void
+netclear(void)
+{
+ char *thisitem, *next;
+ char *good;
+#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
+ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+
+#ifdef ENCRYPTION
+ thisitem = nclearto > netobuf ? nclearto : netobuf;
+#else /* ENCRYPTION */
+ thisitem = netobuf;
+#endif /* ENCRYPTION */
+
+ while ((next = nextitem(thisitem)) <= nbackp) {
+ thisitem = next;
+ }
+
+ /* Now, thisitem is first before/at boundary. */
+
+#ifdef ENCRYPTION
+ good = nclearto > netobuf ? nclearto : netobuf;
+#else /* ENCRYPTION */
+ good = netobuf; /* where the good bytes go */
+#endif /* ENCRYPTION */
+
+ while (nfrontp > thisitem) {
+ if (wewant(thisitem)) {
+ int length;
+
+ next = thisitem;
+ do {
+ next = nextitem(next);
+ } while (wewant(next) && (nfrontp > next));
+ length = next-thisitem;
+ memmove(good, thisitem, length);
+ good += length;
+ thisitem = next;
+ } else {
+ thisitem = nextitem(thisitem);
+ }
+ }
+
+ nbackp = netobuf;
+ nfrontp = good; /* next byte to be sent */
+ neturg = 0;
+} /* end of netclear */
+
+/*
+ * netflush
+ * Send as much data as possible to the network,
+ * handling requests for urgent data.
+ */
+void
+netflush(void)
+{
+ int n;
+ extern int not42;
+
+ while ((n = nfrontp - nbackp) > 0) {
+#if 0
+ /* XXX This causes output_data() to recurse and die */
+ DIAG(TD_REPORT, {
+ n += output_data("td: netflush %d chars\r\n", n);
+ });
+#endif
+#ifdef ENCRYPTION
+ if (encrypt_output) {
+ char *s = nclearto ? nclearto : nbackp;
+ if (nfrontp - s > 0) {
+ (*encrypt_output)((unsigned char *)s, nfrontp-s);
+ nclearto = nfrontp;
+ }
+ }
+#endif /* ENCRYPTION */
+ /*
+ * if no urgent data, or if the other side appears to be an
+ * old 4.2 client (and thus unable to survive TCP urgent data),
+ * write the entire buffer in non-OOB mode.
+ */
+ if ((neturg == 0) || (not42 == 0)) {
+ n = write(net, nbackp, n); /* normal write */
+ } else {
+ n = neturg - nbackp;
+ /*
+ * In 4.2 (and 4.3) systems, there is some question about
+ * what byte in a sendOOB operation is the "OOB" data.
+ * To make ourselves compatible, we only send ONE byte
+ * out of band, the one WE THINK should be OOB (though
+ * we really have more the TCP philosophy of urgent data
+ * rather than the Unix philosophy of OOB data).
+ */
+ if (n > 1) {
+ n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
+ } else {
+ n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
+ }
+ }
+ if (n == -1) {
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ continue;
+ cleanup(0);
+ /* NOTREACHED */
+ }
+ nbackp += n;
+#ifdef ENCRYPTION
+ if (nbackp > nclearto)
+ nclearto = 0;
+#endif /* ENCRYPTION */
+ if (nbackp >= neturg) {
+ neturg = 0;
+ }
+ if (nbackp == nfrontp) {
+ nbackp = nfrontp = netobuf;
+#ifdef ENCRYPTION
+ nclearto = 0;
+#endif /* ENCRYPTION */
+ }
+ }
+ return;
+} /* end of netflush */
+
+
+/*
+ * miscellaneous functions doing a variety of little jobs follow ...
+ */
+
+
+void
+fatal(int f, const char *msg)
+{
+ char buf[BUFSIZ];
+
+ (void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
+#ifdef ENCRYPTION
+ if (encrypt_output) {
+ /*
+ * Better turn off encryption first....
+ * Hope it flushes...
+ */
+ encrypt_send_end();
+ netflush();
+ }
+#endif /* ENCRYPTION */
+ (void) write(f, buf, (int)strlen(buf));
+ sleep(1); /*XXX*/
+ exit(1);
+}
+
+void
+fatalperror(int f, const char *msg)
+{
+ char buf[BUFSIZ];
+
+ (void) snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
+ fatal(f, buf);
+}
+
+char editedhost[32];
+
+void
+edithost(char *pat, char *host)
+{
+ char *res = editedhost;
+
+ if (!pat)
+ pat = strdup("");
+ while (*pat) {
+ switch (*pat) {
+
+ case '#':
+ if (*host)
+ host++;
+ break;
+
+ case '@':
+ if (*host)
+ *res++ = *host++;
+ break;
+
+ default:
+ *res++ = *pat;
+ break;
+ }
+ if (res == &editedhost[sizeof editedhost - 1]) {
+ *res = '\0';
+ return;
+ }
+ pat++;
+ }
+ if (*host)
+ (void) strncpy(res, host,
+ sizeof editedhost - (res - editedhost) -1);
+ else
+ *res = '\0';
+ editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static char *putlocation;
+
+static void
+putstr(const char *s)
+{
+
+ while (*s)
+ putchr(*s++);
+}
+
+void
+putchr(int cc)
+{
+ *putlocation++ = cc;
+}
+
+#ifdef __FreeBSD__
+static char fmtstr[] = { "%+" };
+#else
+static char fmtstr[] = { "%l:%M%P on %A, %d %B %Y" };
+#endif
+
+void
+putf(char *cp, char *where)
+{
+ char *slash;
+ time_t t;
+ char db[100];
+#ifdef __FreeBSD__
+ static struct utsname kerninfo;
+
+ if (!*kerninfo.sysname)
+ uname(&kerninfo);
+#endif
+
+ putlocation = where;
+
+ while (*cp) {
+ if (*cp =='\n') {
+ putstr("\r\n");
+ cp++;
+ continue;
+ } else if (*cp != '%') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+ case 't':
+#ifdef STREAMSPTY
+ /* names are like /dev/pts/2 -- we want pts/2 */
+ slash = strchr(line+1, '/');
+#else
+ slash = strrchr(line, '/');
+#endif
+ if (slash == (char *) 0)
+ putstr(line);
+ else
+ putstr(&slash[1]);
+ break;
+
+ case 'h':
+ putstr(editedhost);
+ break;
+
+ case 'd':
+#ifdef __FreeBSD__
+ setlocale(LC_TIME, "");
+#endif
+ (void)time(&t);
+ (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
+ putstr(db);
+ break;
+
+#ifdef __FreeBSD__
+ case 's':
+ putstr(kerninfo.sysname);
+ break;
+
+ case 'm':
+ putstr(kerninfo.machine);
+ break;
+
+ case 'r':
+ putstr(kerninfo.release);
+ break;
+
+ case 'v':
+ putstr(kerninfo.version);
+ break;
+#endif
+
+ case '%':
+ putchr('%');
+ break;
+ }
+ cp++;
+ }
+}
+
+#ifdef DIAGNOSTICS
+/*
+ * Print telnet options and commands in plain text, if possible.
+ */
+void
+printoption(const char *fmt, int option)
+{
+ if (TELOPT_OK(option))
+ output_data("%s %s\r\n", fmt, TELOPT(option));
+ else if (TELCMD_OK(option))
+ output_data("%s %s\r\n", fmt, TELCMD(option));
+ else
+ output_data("%s %d\r\n", fmt, option);
+ return;
+}
+
+void
+printsub(char direction, unsigned char *pointer, int length)
+{
+ int i = 0;
+
+ if (!(diagnostic & TD_OPTIONS))
+ return;
+
+ if (direction) {
+ output_data("td: %s suboption ",
+ direction == '<' ? "recv" : "send");
+ if (length >= 3) {
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if (i != IAC || j != SE) {
+ output_data("(terminated by ");
+ if (TELOPT_OK(i))
+ output_data("%s ", TELOPT(i));
+ else if (TELCMD_OK(i))
+ output_data("%s ", TELCMD(i));
+ else
+ output_data("%d ", i);
+ if (TELOPT_OK(j))
+ output_data("%s", TELOPT(j));
+ else if (TELCMD_OK(j))
+ output_data("%s", TELCMD(j));
+ else
+ output_data("%d", j);
+ output_data(", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if (length < 1) {
+ output_data("(Empty suboption??\?)");
+ return;
+ }
+ switch (pointer[0]) {
+ case TELOPT_TTYPE:
+ output_data("TERMINAL-TYPE ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ output_data("SEND");
+ break;
+ default:
+ output_data(
+ "- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+ case TELOPT_TSPEED:
+ output_data("TERMINAL-SPEED");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data(" IS %.*s", length-2, (char *)pointer+2);
+ break;
+ default:
+ if (pointer[1] == 1)
+ output_data(" SEND");
+ else
+ output_data(" %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+ }
+ break;
+
+ case TELOPT_LFLOW:
+ output_data("TOGGLE-FLOW-CONTROL");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case LFLOW_OFF:
+ output_data(" OFF"); break;
+ case LFLOW_ON:
+ output_data(" ON"); break;
+ case LFLOW_RESTART_ANY:
+ output_data(" RESTART-ANY"); break;
+ case LFLOW_RESTART_XON:
+ output_data(" RESTART-XON"); break;
+ default:
+ output_data(" %d (unknown)", pointer[1]);
+ }
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+
+ case TELOPT_NAWS:
+ output_data("NAWS");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ if (length == 2) {
+ output_data(" ?%d?", pointer[1]);
+ break;
+ }
+ output_data(" %d %d (%d)",
+ pointer[1], pointer[2],
+ (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+ if (length == 4) {
+ output_data(" ?%d?", pointer[3]);
+ break;
+ }
+ output_data(" %d %d (%d)",
+ pointer[3], pointer[4],
+ (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+ for (i = 5; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+
+ case TELOPT_LINEMODE:
+ output_data("LINEMODE ");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case WILL:
+ output_data("WILL ");
+ goto common;
+ case WONT:
+ output_data("WONT ");
+ goto common;
+ case DO:
+ output_data("DO ");
+ goto common;
+ case DONT:
+ output_data("DONT ");
+ common:
+ if (length < 3) {
+ output_data("(no option??\?)");
+ break;
+ }
+ switch (pointer[2]) {
+ case LM_FORWARDMASK:
+ output_data("Forward Mask");
+ for (i = 3; i < length; i++) {
+ output_data(" %x", pointer[i]);
+ }
+ break;
+ default:
+ output_data("%d (unknown)", pointer[2]);
+ for (i = 3; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ break;
+ }
+ break;
+
+ case LM_SLC:
+ output_data("SLC");
+ for (i = 2; i < length - 2; i += 3) {
+ if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+ output_data(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
+ else
+ output_data(" %d", pointer[i+SLC_FUNC]);
+ switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+ case SLC_NOSUPPORT:
+ output_data(" NOSUPPORT"); break;
+ case SLC_CANTCHANGE:
+ output_data(" CANTCHANGE"); break;
+ case SLC_VARIABLE:
+ output_data(" VARIABLE"); break;
+ case SLC_DEFAULT:
+ output_data(" DEFAULT"); break;
+ }
+ output_data("%s%s%s",
+ pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
+ if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+ SLC_FLUSHOUT| SLC_LEVELBITS)) {
+ output_data("(0x%x)", pointer[i+SLC_FLAGS]);
+ }
+ output_data(" %d;", pointer[i+SLC_VALUE]);
+ if ((pointer[i+SLC_VALUE] == IAC) &&
+ (pointer[i+SLC_VALUE+1] == IAC))
+ i++;
+ }
+ for (; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+
+ case LM_MODE:
+ output_data("MODE ");
+ if (length < 3) {
+ output_data("(no mode??\?)");
+ break;
+ }
+ {
+ char tbuf[32];
+ sprintf(tbuf, "%s%s%s%s%s",
+ pointer[2]&MODE_EDIT ? "|EDIT" : "",
+ pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
+ pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
+ pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
+ pointer[2]&MODE_ACK ? "|ACK" : "");
+ output_data("%s", tbuf[1] ? &tbuf[1] : "0");
+ }
+ if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
+ output_data(" (0x%x)", pointer[2]);
+ }
+ for (i = 3; i < length; i++) {
+ output_data(" ?0x%x?", pointer[i]);
+ }
+ break;
+ default:
+ output_data("%d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ }
+ break;
+
+ case TELOPT_STATUS: {
+ const char *cp;
+ int j, k;
+
+ output_data("STATUS");
+
+ switch (pointer[1]) {
+ default:
+ if (pointer[1] == TELQUAL_SEND)
+ output_data(" SEND");
+ else
+ output_data(" %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+ case TELQUAL_IS:
+ output_data(" IS\r\n");
+
+ for (i = 2; i < length; i++) {
+ switch(pointer[i]) {
+ case DO: cp = "DO"; goto common2;
+ case DONT: cp = "DONT"; goto common2;
+ case WILL: cp = "WILL"; goto common2;
+ case WONT: cp = "WONT"; goto common2;
+ common2:
+ i++;
+ if (TELOPT_OK(pointer[i]))
+ output_data(" %s %s", cp, TELOPT(pointer[i]));
+ else
+ output_data(" %s %d", cp, pointer[i]);
+
+ output_data("\r\n");
+ break;
+
+ case SB:
+ output_data(" SB ");
+ i++;
+ j = k = i;
+ while (j < length) {
+ if (pointer[j] == SE) {
+ if (j+1 == length)
+ break;
+ if (pointer[j+1] == SE)
+ j++;
+ else
+ break;
+ }
+ pointer[k++] = pointer[j++];
+ }
+ printsub(0, &pointer[i], k - i);
+ if (i < length) {
+ output_data(" SE");
+ i = j;
+ } else
+ i = j - 1;
+
+ output_data("\r\n");
+
+ break;
+
+ default:
+ output_data(" %d", pointer[i]);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ case TELOPT_XDISPLOC:
+ output_data("X-DISPLAY-LOCATION ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ output_data("SEND");
+ break;
+ default:
+ output_data("- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+
+ case TELOPT_NEW_ENVIRON:
+ output_data("NEW-ENVIRON ");
+ goto env_common1;
+ case TELOPT_OLD_ENVIRON:
+ output_data("OLD-ENVIRON");
+ env_common1:
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data("IS ");
+ goto env_common;
+ case TELQUAL_SEND:
+ output_data("SEND ");
+ goto env_common;
+ case TELQUAL_INFO:
+ output_data("INFO ");
+ env_common:
+ {
+ int noquote = 2;
+ for (i = 2; i < length; i++ ) {
+ switch (pointer[i]) {
+ case NEW_ENV_VAR:
+ output_data("%s", "\" VAR " + noquote);
+ noquote = 2;
+ break;
+
+ case NEW_ENV_VALUE:
+ output_data("%s", "\" VALUE " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_ESC:
+ output_data("%s", "\" ESC " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_USERVAR:
+ output_data("%s", "\" USERVAR " + noquote);
+ noquote = 2;
+ break;
+
+ default:
+ if (isprint(pointer[i]) && pointer[i] != '"') {
+ if (noquote) {
+ output_data("\"");
+ noquote = 0;
+ }
+ output_data("%c", pointer[i]);
+ } else {
+ output_data("\" %03o " + noquote,
+ pointer[i]);
+ noquote = 2;
+ }
+ break;
+ }
+ }
+ if (!noquote)
+ output_data("\"");
+ break;
+ }
+ }
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ output_data("AUTHENTICATION");
+
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_REPLY:
+ case TELQUAL_IS:
+ output_data(" %s ", (pointer[1] == TELQUAL_IS) ?
+ "IS" : "REPLY");
+ if (AUTHTYPE_NAME_OK(pointer[2]))
+ output_data("%s ", AUTHTYPE_NAME(pointer[2]));
+ else
+ output_data("%d ", pointer[2]);
+ if (length < 3) {
+ output_data("(partial suboption??\?)");
+ break;
+ }
+ output_data("%s|%s",
+ ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+
+ {
+ char buf[512];
+ auth_printsub(&pointer[1], length - 1, (unsigned char*)buf, sizeof(buf));
+ output_data("%s", buf);
+ }
+ break;
+
+ case TELQUAL_SEND:
+ i = 2;
+ output_data(" SEND ");
+ while (i < length) {
+ if (AUTHTYPE_NAME_OK(pointer[i]))
+ output_data("%s ", AUTHTYPE_NAME(pointer[i]));
+ else
+ output_data("%d ", pointer[i]);
+ if (++i >= length) {
+ output_data("(partial suboption??\?)");
+ break;
+ }
+ output_data("%s|%s ",
+ ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+ ++i;
+ }
+ break;
+
+ case TELQUAL_NAME:
+ output_data(" NAME \"%.*s\"", length - 2, pointer + 2);
+ break;
+
+ default:
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+ }
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ output_data("ENCRYPT");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case ENCRYPT_START:
+ output_data(" START");
+ break;
+
+ case ENCRYPT_END:
+ output_data(" END");
+ break;
+
+ case ENCRYPT_REQSTART:
+ output_data(" REQUEST-START");
+ break;
+
+ case ENCRYPT_REQEND:
+ output_data(" REQUEST-END");
+ break;
+
+ case ENCRYPT_IS:
+ case ENCRYPT_REPLY:
+ output_data(" %s ", (pointer[1] == ENCRYPT_IS) ?
+ "IS" : "REPLY");
+ if (length < 3) {
+ output_data(" (partial suboption??\?)");
+ break;
+ }
+ if (ENCTYPE_NAME_OK(pointer[2]))
+ output_data("%s ", ENCTYPE_NAME(pointer[2]));
+ else
+ output_data(" %d (unknown)", pointer[2]);
+
+ {
+ char buf[512];
+ encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+ output_data("%s", buf);
+ }
+ break;
+
+ case ENCRYPT_SUPPORT:
+ i = 2;
+ output_data(" SUPPORT ");
+ while (i < length) {
+ if (ENCTYPE_NAME_OK(pointer[i]))
+ output_data("%s ", ENCTYPE_NAME(pointer[i]));
+ else
+ output_data("%d ", pointer[i]);
+ i++;
+ }
+ break;
+
+ case ENCRYPT_ENC_KEYID:
+ output_data(" ENC_KEYID");
+ goto encommon;
+
+ case ENCRYPT_DEC_KEYID:
+ output_data(" DEC_KEYID");
+ goto encommon;
+
+ default:
+ output_data(" %d (unknown)", pointer[1]);
+ encommon:
+ for (i = 2; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+
+ default:
+ if (TELOPT_OK(pointer[0]))
+ output_data("%s (unknown)", TELOPT(pointer[0]));
+ else
+ output_data("%d (unknown)", pointer[i]);
+ for (i = 1; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ break;
+ }
+ output_data("\r\n");
+}
+
+/*
+ * Dump a data buffer in hex and ascii to the output data stream.
+ */
+void
+printdata(const char *tag, char *ptr, int cnt)
+{
+ int i;
+ char xbuf[30];
+
+ while (cnt) {
+ /* flush net output buffer if no room for new data) */
+ if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
+ netflush();
+ }
+
+ /* add a line of output */
+ output_data("%s: ", tag);
+ for (i = 0; i < 20 && cnt; i++) {
+ output_data("%02x", *ptr);
+ if (isprint(*ptr)) {
+ xbuf[i] = *ptr;
+ } else {
+ xbuf[i] = '.';
+ }
+ if (i % 2) {
+ output_data(" ");
+ }
+ cnt--;
+ ptr++;
+ }
+ xbuf[i] = '\0';
+ output_data(" %s\r\n", xbuf );
+ }
+}
+#endif /* DIAGNOSTICS */
diff --git a/remote_cmds/telnetd.tproj/vasprintf.c b/remote_cmds/telnetd.tproj/vasprintf.c
new file mode 100644
index 0000000..ad4aed6
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/vasprintf.c
@@ -0,0 +1,66 @@
+/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+static char rcsid[] = "$FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.12 2001/01/24 13:00:47 deischen Exp $";
+#endif /* LIBC_RCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+int
+vasprintf(str, fmt, ap)
+ char **str;
+ const char *fmt;
+ va_list ap;
+{
+ int ret;
+ FILE f;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR ;
+ f._bf._base = f._p = (unsigned char *)malloc(128);
+ if (f._bf._base == NULL) {
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NULL */
+ ret = vfprintf(&f, fmt, ap);
+ *f._p = '\0';
+ f._bf._base = realloc(f._bf._base, f._bf._size + 1);
+ if (f._bf._base == NULL) {
+ errno = ENOMEM;
+ ret = -1;
+ }
+ *str = (char *)f._bf._base;
+ return (ret);
+}
diff --git a/remote_cmds/tftp.tproj/Makefile b/remote_cmds/tftp.tproj/Makefile
new file mode 100644
index 0000000..6ed62a0
--- /dev/null
+++ b/remote_cmds/tftp.tproj/Makefile
@@ -0,0 +1,12 @@
+Project = tftp
+
+HFILES = extern.h tftpsubs.h
+CFILES = main.c tftp.c tftpsubs.c
+MANPAGES = tftp.1
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+Extra_LD_Flags += -ledit
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/tftp.tproj/extern.h b/remote_cmds/tftp.tproj/extern.h
new file mode 100644
index 0000000..fdf3d31
--- /dev/null
+++ b/remote_cmds/tftp.tproj/extern.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/tftp/extern.h,v 1.3 2002/03/22 01:42:33 imp Exp $
+ */
+
+void recvfile(int, char *, char *);
+void xmitfile(int, char *, char *);
diff --git a/remote_cmds/tftp.tproj/main.c b/remote_cmds/tftp.tproj/main.c
new file mode 100644
index 0000000..f223726
--- /dev/null
+++ b/remote_cmds/tftp.tproj/main.c
@@ -0,0 +1,920 @@
+/* $NetBSD: main.c,v 1.19 2003/10/02 23:31:52 itojun Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tftp/main.c,v 1.22 2005/10/19 15:37:42 stefanf Exp $");
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Command Interface.
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/tftp.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <err.h>
+#include <histedit.h>
+#include <netdb.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define MAXLINE 200
+#define TIMEOUT 5 /* secs between rexmt's */
+#define MAXSEGSIZE 65464
+struct sockaddr_storage peeraddr;
+int f;
+int trace;
+int verbose;
+int tsize=0;
+int tout=0;
+int def_blksize=SEGSIZE;
+int blksize=SEGSIZE;
+int connected;
+char mode[32];
+char line[MAXLINE];
+int margc;
+#define MAX_MARGV 20
+char *margv[MAX_MARGV];
+jmp_buf toplevel;
+volatile int txrx_error;
+
+void get(int, char **);
+void help(int, char **);
+void intr(int);
+void modecmd(int, char **);
+void put(int, char **);
+void quit(int, char **);
+void setascii(int, char **);
+void setbinary(int, char **);
+void setpeer0(char *, const char *);
+void setpeer(int, char **);
+void setrexmt(int, char **);
+void settimeout(int, char **);
+void settrace(int, char **);
+void setverbose(int, char **);
+#ifdef __APPLE__
+void setblksize(int, char **);
+void settsize(int, char **);
+void settimeoutopt(int, char **);
+#endif
+void status(int, char **);
+#ifdef __APPLE__
+char *tail(char *);
+int main(int, char *[]);
+void intr(int);
+struct cmd *getcmd(char *);
+#endif
+
+static void command(void) __dead2;
+static const char *command_prompt(void);
+
+static void getusage(char *);
+static void makeargv(void);
+static void putusage(char *);
+static void settftpmode(const char *);
+
+char *tail(char *);
+struct cmd *getcmd(char *);
+
+#define HELPINDENT (sizeof("connect"))
+
+struct cmd {
+ const char *name;
+ char *help;
+ void (*handler)(int, char **);
+};
+
+char vhelp[] = "toggle verbose mode";
+char thelp[] = "toggle packet tracing";
+#ifdef __APPLE__
+char tshelp[] = "toggle extended tsize option";
+char tohelp[] = "toggle extended timeout option";
+char blhelp[] = "set an alternative blocksize (def. 512)";
+#endif
+char chelp[] = "connect to remote tftp";
+char qhelp[] = "exit tftp";
+char hhelp[] = "print help information";
+char shelp[] = "send file";
+char rhelp[] = "receive file";
+char mhelp[] = "set file transfer mode";
+char sthelp[] = "show current status";
+char xhelp[] = "set per-packet retransmission timeout";
+char ihelp[] = "set total retransmission timeout";
+char ashelp[] = "set mode to netascii";
+char bnhelp[] = "set mode to octet";
+
+struct cmd cmdtab[] = {
+ { "connect", chelp, setpeer },
+ { "mode", mhelp, modecmd },
+ { "put", shelp, put },
+ { "get", rhelp, get },
+ { "quit", qhelp, quit },
+ { "verbose", vhelp, setverbose },
+#ifdef __APPLE__
+ { "blksize", blhelp, setblksize },
+ { "tsize", tshelp, settsize },
+#endif
+ { "trace", thelp, settrace },
+ { "status", sthelp, status },
+ { "binary", bnhelp, setbinary },
+ { "ascii", ashelp, setascii },
+ { "rexmt", xhelp, setrexmt },
+ { "timeout", ihelp, settimeout },
+#ifdef __APPLE__
+ { "tout", tohelp, settimeoutopt },
+#endif
+ { "?", hhelp, help },
+ { NULL, NULL, NULL }
+};
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ f = -1;
+ strcpy(mode, "netascii");
+ signal(SIGINT, intr);
+
+ setprogname(argv[0]);
+ while ((c = getopt(argc, argv, "e")) != -1) {
+ switch (c) {
+ case 'e':
+ blksize = MAXSEGSIZE;
+ strcpy(mode, "octet");
+ tsize = 1;
+ tout = 1;
+ break;
+ default:
+ printf("usage: %s [-e] host-name [port]\n",
+ getprogname());
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc >= 1) {
+ if (setjmp(toplevel) != 0)
+ exit(txrx_error);
+ argc++;
+ argv--;
+ setpeer(argc, argv);
+ }
+ if (setjmp(toplevel) != 0)
+ (void)putchar('\n');
+ command();
+ return (0);
+}
+
+char hostname[MAXHOSTNAMELEN];
+
+void
+setpeer0(host, port)
+ char *host;
+ const char *port;
+{
+ struct addrinfo hints, *res0, *res;
+ int error, soopt;
+ struct sockaddr_storage ss;
+ const char *cause = "unknown";
+
+ if (connected) {
+ close(f);
+ f = -1;
+ }
+ connected = 0;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_CANONNAME;
+ if (!port)
+ port = "tftp";
+ error = getaddrinfo(host, port, &hints, &res0);
+ if (error) {
+ warnx("%s", gai_strerror(error));
+ return;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ if (res->ai_addrlen > sizeof(peeraddr))
+ continue;
+ f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (f < 0) {
+ cause = "socket";
+ continue;
+ }
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = res->ai_family;
+ ss.ss_len = res->ai_addrlen;
+ if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
+ cause = "bind";
+ close(f);
+ f = -1;
+ continue;
+ }
+
+ break;
+ }
+
+ if (f >= 0) {
+ soopt = 65536;
+ if (setsockopt(f, SOL_SOCKET, SO_SNDBUF, &soopt, sizeof(soopt))
+ < 0) {
+ close(f);
+ f = -1;
+ cause = "setsockopt SNDBUF";
+ }
+ if (setsockopt(f, SOL_SOCKET, SO_RCVBUF, &soopt, sizeof(soopt))
+ < 0) {
+ close(f);
+ f = -1;
+ cause = "setsockopt RCVBUF";
+ }
+ }
+
+ if (f < 0)
+ warn("%s", cause);
+ else {
+ /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ if (res->ai_canonname) {
+ (void) strlcpy(hostname, res->ai_canonname,
+ sizeof(hostname));
+ } else
+ (void) strlcpy(hostname, host, sizeof(hostname));
+ connected = 1;
+ }
+
+ freeaddrinfo(res0);
+}
+
+void
+setpeer(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2) {
+ strcpy(line, "Connect ");
+ printf("(to) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if ((argc < 2) || (argc > 3)) {
+ printf("usage: %s [-e] host-name [port]\n", getprogname());
+ return;
+ }
+ if (argc == 3)
+ setpeer0(argv[1], argv[2]);
+ else
+ setpeer0(argv[1], NULL);
+}
+
+struct modes {
+ const char *m_name;
+ const char *m_mode;
+} modes[] = {
+ { "ascii", "netascii" },
+ { "netascii", "netascii" },
+ { "binary", "octet" },
+ { "image", "octet" },
+ { "octet", "octet" },
+/* { "mail", "mail" }, */
+ { 0, 0 }
+};
+
+void
+modecmd(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct modes *p;
+ const char *sep;
+
+ if (argc < 2) {
+ printf("Using %s mode to transfer files.\n", mode);
+ return;
+ }
+ if (argc == 2) {
+ for (p = modes; p->m_name; p++)
+ if (strcmp(argv[1], p->m_name) == 0)
+ break;
+ if (p->m_name) {
+ settftpmode(p->m_mode);
+ return;
+ }
+ printf("%s: unknown mode\n", argv[1]);
+ /* drop through and print usage message */
+ }
+
+ printf("usage: %s [", argv[0]);
+ sep = " ";
+ for (p = modes; p->m_name; p++) {
+ printf("%s%s", sep, p->m_name);
+ if (*sep == ' ')
+ sep = " | ";
+ }
+ printf(" ]\n");
+ return;
+}
+
+void
+setbinary(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+
+ settftpmode("octet");
+}
+
+void
+setascii(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+
+ settftpmode("netascii");
+}
+
+static void
+settftpmode(newmode)
+ const char *newmode;
+{
+ strcpy(mode, newmode);
+ if (verbose)
+ printf("mode set to %s\n", mode);
+}
+
+
+/*
+ * Send file(s).
+ */
+void
+put(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int fd;
+ int n;
+ char *cp, *targ;
+#ifdef __APPLE__
+ char targbuf[PATH_MAX];
+#endif /* __APPLE__ */
+
+ if (argc < 2) {
+ strcpy(line, "send ");
+ printf("(file) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc < 2) {
+ putusage(argv[0]);
+ return;
+ }
+ targ = argv[argc - 1];
+ if (rindex(argv[argc - 1], ':')) {
+ char *lcp;
+
+ for (n = 1; n < argc - 1; n++)
+ if (index(argv[n], ':')) {
+ putusage(argv[0]);
+ return;
+ }
+ lcp = argv[argc - 1];
+ targ = rindex(lcp, ':');
+ *targ++ = 0;
+ if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
+ lcp[strlen(lcp) - 1] = '\0';
+ lcp++;
+ }
+ setpeer0(lcp, NULL);
+ }
+ if (!connected) {
+ printf("No target machine specified.\n");
+ return;
+ }
+ if (argc < 4) {
+ cp = argc == 2 ? tail(targ) : argv[1];
+ fd = open(cp, O_RDONLY);
+ if (fd < 0) {
+ warn("%s", cp);
+ return;
+ }
+ if (verbose)
+ printf("putting %s to %s:%s [%s]\n",
+ cp, hostname, targ, mode);
+ xmitfile(fd, targ, mode);
+ return;
+ }
+ /* this assumes the target is a directory */
+ /* on a remote unix system. hmmmm. */
+#ifdef __APPLE__
+ snprintf(targbuf, sizeof(targbuf), "%s/", targ);
+ cp = targbuf + strlen(targbuf);
+#else /* !__APPLE__ */
+ cp = index(targ, '\0');
+ *cp++ = '/';
+#endif /* __APPLE__ */
+ for (n = 1; n < argc - 1; n++) {
+#ifdef __APPLE__
+ strlcpy(cp, tail(argv[n]), sizeof(targbuf) - (cp - targbuf));
+#else /* !__APPLE__ */
+ strcpy(cp, tail(argv[n]));
+#endif /* __APPLE__ */
+ fd = open(argv[n], O_RDONLY);
+ if (fd < 0) {
+ warn("%s", argv[n]);
+ continue;
+ }
+ if (verbose)
+ printf("putting %s to %s:%s [%s]\n",
+#ifdef __APPLE__
+ argv[n], hostname, targbuf, mode);
+#else /* !__APPLE__ */
+ argv[n], hostname, targ, mode);
+#endif /* __APPLE__ */
+ xmitfile(fd, targ, mode);
+ }
+}
+
+static void
+putusage(s)
+ char *s;
+{
+ printf("usage: %s file ... host:target, or\n", s);
+ printf(" %s file ... target (when already connected)\n", s);
+}
+
+/*
+ * Receive file(s).
+ */
+void
+get(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int fd;
+ int n;
+ char *cp;
+ char *src;
+
+ if (argc < 2) {
+ strcpy(line, "get ");
+ printf("(files) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc < 2) {
+ getusage(argv[0]);
+ return;
+ }
+ if (!connected) {
+ for (n = 1; n < argc ; n++)
+ if (rindex(argv[n], ':') == 0) {
+ getusage(argv[0]);
+ return;
+ }
+ }
+ for (n = 1; n < argc ; n++) {
+ src = rindex(argv[n], ':');
+ if (src == NULL)
+ src = argv[n];
+ else {
+ char *lcp;
+
+ *src++ = 0;
+ lcp = argv[n];
+ if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
+ lcp[strlen(lcp) - 1] = '\0';
+ lcp++;
+ }
+ setpeer0(lcp, NULL);
+ if (!connected)
+ continue;
+ }
+ if (argc < 4) {
+ cp = argc == 3 ? argv[2] : tail(src);
+ fd = creat(cp, 0644);
+ if (fd < 0) {
+ warn("%s", cp);
+ return;
+ }
+ if (verbose)
+ printf("getting from %s:%s to %s [%s]\n",
+ hostname, src, cp, mode);
+ recvfile(fd, src, mode);
+ break;
+ }
+ cp = tail(src); /* new .. jdg */
+ fd = creat(cp, 0644);
+ if (fd < 0) {
+ warn("%s", cp);
+ continue;
+ }
+ if (verbose)
+ printf("getting from %s:%s to %s [%s]\n",
+ hostname, src, cp, mode);
+ recvfile(fd, src, mode);
+ }
+}
+
+static void
+getusage(s)
+ char *s;
+{
+ printf("usage: %s host:file host:file ... file, or\n", s);
+ printf(" %s file file ... file if connected\n", s);
+}
+
+void
+setblksize(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int t;
+
+ if (argc < 2) {
+ strcpy(line, "blksize ");
+ printf("(blksize) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc != 2) {
+ printf("usage: %s value\n", argv[0]);
+ return;
+ }
+ t = atoi(argv[1]);
+ if (t < 8 || t > 65464)
+ printf("%s: bad value\n", argv[1]);
+ else
+ blksize = t;
+}
+
+int def_rexmtval = TIMEOUT;
+int rexmtval = TIMEOUT;
+
+void
+setrexmt(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int t;
+
+ if (argc < 2) {
+ strcpy(line, "Rexmt-timeout ");
+ printf("(value) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc != 2) {
+ printf("usage: %s value\n", argv[0]);
+ return;
+ }
+ t = atoi(argv[1]);
+ if (t < 0)
+ printf("%s: bad value\n", argv[1]);
+ else
+ rexmtval = t;
+}
+
+int maxtimeout = 5 * TIMEOUT;
+
+void
+settimeout(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int t;
+
+ if (argc < 2) {
+ strcpy(line, "Maximum-timeout ");
+ printf("(value) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc != 2) {
+ printf("usage: %s value\n", argv[0]);
+ return;
+ }
+ t = atoi(argv[1]);
+ if (t < 0)
+ printf("%s: bad value\n", argv[1]);
+ else
+ maxtimeout = t;
+}
+
+void
+status(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+ if (connected)
+ printf("Connected to %s.\n", hostname);
+ else
+ printf("Not connected.\n");
+ printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
+ verbose ? "on" : "off", trace ? "on" : "off");
+ printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
+ rexmtval, maxtimeout);
+}
+
+void
+intr(dummy)
+ int dummy __unused;
+{
+
+ signal(SIGALRM, SIG_IGN);
+ alarm(0);
+ longjmp(toplevel, -1);
+}
+
+char *
+tail(filename)
+ char *filename;
+{
+ char *s;
+
+ while (*filename) {
+ s = rindex(filename, '/');
+ if (s == NULL)
+ break;
+ if (s[1])
+ return (s + 1);
+ *s = '\0';
+ }
+ return (filename);
+}
+
+static const char *
+command_prompt()
+{
+
+ return ("tftp> ");
+}
+
+/*
+ * Command parser.
+ */
+static void
+command()
+{
+ HistEvent he;
+ struct cmd *c;
+ static EditLine *el;
+ static History *hist;
+ const char *bp;
+ char *cp;
+ int len, num, vrbose;
+
+ vrbose = isatty(0);
+ if (vrbose) {
+ el = el_init("tftp", stdin, stdout, stderr);
+ hist = history_init();
+ history(hist, &he, H_SETSIZE, 100);
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_PROMPT, command_prompt);
+ el_set(el, EL_SIGNAL, 1);
+ el_source(el, NULL);
+ }
+ for (;;) {
+ if (vrbose) {
+ if ((bp = el_gets(el, &num)) == NULL || num == 0)
+ exit(0);
+ len = (num > MAXLINE) ? MAXLINE : num;
+ memcpy(line, bp, len);
+ line[len] = '\0';
+ history(hist, &he, H_ENTER, bp);
+ } else {
+ if (fgets(line, sizeof line , stdin) == 0) {
+ if (feof(stdin)) {
+ exit(txrx_error);
+ } else {
+ continue;
+ }
+ }
+ }
+ if ((cp = strchr(line, '\n')))
+ *cp = '\0';
+ if (line[0] == 0)
+ continue;
+ makeargv();
+ if (margc == 0)
+ continue;
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ (*c->handler)(margc, margv);
+ }
+}
+
+struct cmd *
+getcmd(name)
+ char *name;
+{
+ const char *p, *q;
+ struct cmd *c, *found;
+ int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; (p = c->name) != NULL; c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return (c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return ((struct cmd *)-1);
+ return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+static void
+makeargv()
+{
+ char *cp;
+ char **argp = margv;
+
+ margc = 0;
+ if ((cp = strchr(line, '\n')))
+ *cp = '\0';
+ for (cp = line; margc < MAX_MARGV - 1 && *cp;) {
+ while (isspace((unsigned char)*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace((unsigned char)*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+void
+quit(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+ exit(txrx_error);
+}
+
+/*
+ * Help command.
+ */
+void
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct cmd *c;
+
+ if (argc == 1) {
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->name; c++)
+ printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
+ return;
+ }
+ while (--argc > 0) {
+ char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%s\n", c->help);
+ }
+}
+
+void
+settrace(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ trace = !trace;
+ printf("Packet tracing %s.\n", trace ? "on" : "off");
+}
+
+void
+setverbose(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ verbose = !verbose;
+ printf("Verbose mode %s.\n", verbose ? "on" : "off");
+}
+
+void
+settsize(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ tsize = !tsize;
+ printf("Tsize mode %s.\n", tsize ? "on" : "off");
+}
+
+void
+settimeoutopt(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ tout = !tout;
+ printf("Timeout option %s.\n", tout ? "on" : "off");
+}
diff --git a/remote_cmds/tftp.tproj/tftp.1 b/remote_cmds/tftp.tproj/tftp.1
new file mode 100644
index 0000000..fe867ca
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftp.1
@@ -0,0 +1,243 @@
+.\" $NetBSD: tftp.1,v 1.18 2003/08/07 11:16:14 agc Exp $
+.\"
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tftp.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/tftp/tftp.1,v 1.20 2007/11/07 07:56:57 ru Exp $
+.\"
+.Dd June 11, 2003
+.Dt TFTP 1
+.Os
+.Sh NAME
+.Nm tftp
+.Nd "trivial file transfer program"
+.Sh SYNOPSIS
+.Nm
+.Op Fl e
+.Op Ar host
+.Op Ar port
+.Sh DESCRIPTION
+The
+.Nm
+utility is the user interface to the Internet
+.Tn TFTP
+(Trivial File Transfer Protocol),
+which allows users to transfer files to and from a remote machine.
+The remote
+.Ar host
+(and optional
+.Ar port )
+may be specified on the command line, in which case
+.Nm
+uses
+.Ar host
+(and
+.Ar port )
+as the default for future transfers (see the
+.Cm connect
+command below).
+.Pp
+The optional
+.Fl e
+argument sets a binary transfer mode as well as setting the extended options
+as if
+.Cm tout ,
+.Cm tsize ,
+and
+.Cm blksize 65464 ,
+had been given.
+.Sh COMMANDS
+Once
+.Nm
+is running, it issues the prompt
+.Ql tftp\*[Gt]
+and recognizes the following commands:
+.Pp
+.Bl -tag -width verbose -compact
+.It Cm \&? Ar command-name ...
+Print help information.
+.Pp
+.It Cm ascii
+Shorthand for
+.Ic mode Cm ascii .
+.Pp
+.It Cm binary
+Shorthand for
+.Ic mode Cm binary .
+.Pp
+.It Cm blksize Ar blk-size
+Set the tftp blksize option to
+.Ar blk-size
+octets (8-bit bytes). Since the number of blocks in a tftp
+.Cm get
+or
+.Cm put
+is 65535, the default block size of 512 bytes only allows a maximum of
+just under 32 megabytes to be transferred. The value given for
+.Ar blk-size
+must be between 8 and 65464, inclusive.
+Note that many servers will not respect this option.
+.Pp
+.It Cm connect Ar host-name Op Ar port
+Set the
+.Ar host
+(and optionally
+.Ar port )
+for transfers.
+Note that the
+.Tn TFTP
+protocol, unlike the
+.Tn FTP
+protocol,
+does not maintain connections between transfers; thus, the
+.Cm connect
+command does not actually create a connection,
+but merely remembers what host is to be used for transfers.
+You do not have to use the
+.Cm connect
+command; the remote host can be specified as part of the
+.Cm get
+or
+.Cm put
+commands.
+.Pp
+.It Cm get Ar filename
+.It Cm get Ar remotename localname
+.It Cm get Ar file1 file2 ... fileN
+Get one or more files from the remote host.
+When using the
+.Ar host
+argument, the
+.Ar host
+will be used as default host for future transfers.
+If
+.Ar localname
+is specified, the file is stored locally as
+.Ar localname ,
+otherwise the original filename is used.
+Note that it is not possible to download two files at a time, only
+one, three, or more than three files, at a time.
+.Pp
+To specify an IPv6 numeric address for a host, wrap it using square
+brackets like
+.Dq Li [3ffe:2900:e00c:ffee::1234] : Ns Ar file
+to disambiguate the
+colons used in the IPv6 address from the colon separating the host and
+the filename.
+.Pp
+.It Cm mode Ar transfer-mode
+Set the mode for transfers;
+.Ar transfer-mode
+may be one of
+.Cm ascii
+or
+.Cm binary .
+The default is
+.Cm ascii .
+.Pp
+.It Cm put Ar file
+.It Cm put Ar localfile remotefile
+.It Cm put Ar file1 file2 ... fileN remote-directory
+Put a file or set of files to the specified
+remote file or directory.
+The destination
+can be in one of two forms:
+a filename on the remote host, if the host has already been specified,
+or a string of the form
+.Ar hosts:filename
+to specify both a host and filename at the same time.
+If the latter form is used,
+the hostname specified becomes the default for future transfers.
+When
+.Ar remotename
+is specified, the file is stored remotely as
+.Ar remotename ,
+otherwise the original filename is used.
+If the
+.Ar remote-directory
+argument is used, the remote host is assumed to be a
+.Ux
+machine.
+To specify an IPv6 numeric address for a
+.Ar host ,
+see the example under the
+.Cm get
+command.
+.Pp
+.It Cm quit
+Exit
+.Nm .
+An end of file also exits.
+.Pp
+.It Cm rexmt Ar retransmission-timeout
+Set the per-packet retransmission timeout, in seconds.
+.Pp
+.It Cm status
+Show current status.
+.Pp
+.It Cm timeout Ar total-transmission-timeout
+Set the total transmission timeout, in seconds.
+.Pp
+.It Cm tout
+Toggle the tftp "timeout" option. If enabled, the client will pass its
+.Ar retransmission-timeout
+to the server.
+Note that many servers will not respect this option.
+.Pp
+.It Cm trace
+Toggle packet tracing.
+.Pp
+.It Cm tsize
+Toggle the tftp "tsize" option. If enabled, the client will pass and
+request the filesize of a file at the beginning of a file transfer.
+Note that many servers will not respect this option.
+.Pp
+.It Cm verbose
+Toggle verbose mode.
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
+IPv6 support was implemented by WIDE/KAME project in 1999.
+TFTP options were implemented by Wasabi Systems, Inc., in 2003,
+and first appeared in
+.Nx 2.0 .
+.Sh SECURITY CONSIDERATIONS
+Because there is no user-login or validation within
+the
+.Tn TFTP
+protocol, the remote site will probably have some
+sort of file-access restrictions in place.
+The
+exact methods are specific to each site and therefore
+difficult to document here.
+.Pp
+Files larger than 33488896 octets (65535 blocks) cannot be transferred
+without client and server supporting blocksize negotiation (RFC1783).
diff --git a/remote_cmds/tftp.tproj/tftp.c b/remote_cmds/tftp.tproj/tftp.c
new file mode 100644
index 0000000..56c9750
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftp.c
@@ -0,0 +1,742 @@
+/* $NetBSD: tftp.c,v 1.18 2003/08/07 11:16:14 agc Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tftp/tftp.c,v 1.13 2006/09/28 21:22:21 matteo Exp $");
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Protocol Machines
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/tftp.h>
+
+#include <err.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#ifdef __APPLE__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include "extern.h"
+#include "tftpsubs.h"
+
+extern struct sockaddr_storage peeraddr; /* filled in by main */
+extern int f; /* the opened socket */
+extern int trace;
+extern int verbose;
+extern int def_rexmtval;
+extern int rexmtval;
+extern int maxtimeout;
+extern volatile int txrx_error;
+#ifdef __APPLE__
+extern int tsize;
+extern int tout;
+extern int def_blksize;
+extern int blksize;
+#endif
+
+char ackbuf[PKTSIZE];
+int timeout;
+extern jmp_buf toplevel;
+jmp_buf timeoutbuf;
+
+static void nak(int, struct sockaddr *);
+#ifdef __APPLE__
+static int makerequest(int, const char *, struct tftphdr *, const char *, off_t);
+#else
+static int makerequest(int, const char *, struct tftphdr *, const char *);
+#endif
+static void printstats(const char *, unsigned long);
+static void startclock(void);
+static void stopclock(void);
+static void timer(int);
+static void tpacket(const char *, struct tftphdr *, int);
+static int sockaddrcmp(struct sockaddr *, struct sockaddr *);
+
+static void get_options(struct tftphdr *, int);
+
+static void
+get_options(struct tftphdr *ap, int size)
+{
+ unsigned long val;
+ char *opt, *endp, *nextopt, *valp;
+ int l;
+
+ size -= 2; /* skip over opcode */
+ opt = ap->th_stuff;
+ endp = opt + size - 1;
+ *endp = '\0';
+
+ while (opt < endp) {
+ l = strlen(opt) + 1;
+ valp = opt + l;
+ if (valp < endp) {
+ val = strtoul(valp, NULL, 10);
+ l = strlen(valp) + 1;
+ nextopt = valp + l;
+ if (val == ULONG_MAX && errno == ERANGE) {
+ /* Report illegal value */
+ opt = nextopt;
+ continue;
+ }
+ } else {
+ /* Badly formed OACK */
+ break;
+ }
+ if (strcmp(opt, "tsize") == 0) {
+ /* cool, but we'll ignore it */
+ } else if (strcmp(opt, "timeout") == 0) {
+ if (val >= 1 && val <= 255) {
+ rexmtval = val;
+ } else {
+ /* Report error? */
+ }
+ } else if (strcmp(opt, "blksize") == 0) {
+ if (val >= 8 && val <= MAXSEGSIZE) {
+ blksize = val;
+ } else {
+ /* Report error? */
+ }
+ } else {
+ /* unknown option */
+ }
+ opt = nextopt;
+ }
+}
+
+/*
+ * Send the requested file.
+ */
+void
+xmitfile(fd, name, mode)
+ int fd;
+ char *name;
+ char *mode;
+{
+ struct tftphdr *ap; /* data and ack packets */
+ struct tftphdr *dp;
+ int n;
+ volatile unsigned int block;
+ volatile int size, convert;
+ volatile unsigned long amount;
+ struct sockaddr_storage from;
+ struct stat sbuf;
+ off_t filesize=0;
+ socklen_t fromlen;
+ FILE *file;
+ struct sockaddr_storage peer;
+ struct sockaddr_storage serv; /* valid server port number */
+
+ startclock(); /* start stat's clock */
+ dp = r_init(); /* reset fillbuf/read-ahead code */
+ ap = (struct tftphdr *)ackbuf;
+ if (tsize) {
+ if (fstat(fd, &sbuf) == 0) {
+ filesize = sbuf.st_size;
+ } else {
+ filesize = -1ULL;
+ }
+ }
+ file = fdopen(fd, "r");
+ convert = !strcmp(mode, "netascii");
+ block = 0;
+ amount = 0;
+ memcpy(&peer, &peeraddr, peeraddr.ss_len);
+ memset(&serv, 0, sizeof(serv));
+
+ signal(SIGALRM, timer);
+ do {
+ if (block == 0)
+ size = makerequest(WRQ, name, dp, mode, filesize) - 4;
+ else {
+ /* size = read(fd, dp->th_data, SEGSIZE); */
+ size = readit(file, &dp, blksize, convert);
+ if (size < 0) {
+ nak(errno + 100, (struct sockaddr *)&peer);
+ break;
+ }
+ dp->th_opcode = htons((u_short)DATA);
+ dp->th_block = htons((u_short)block);
+ }
+ timeout = 0;
+ (void) setjmp(timeoutbuf);
+send_data:
+ if (trace)
+ tpacket("sent", dp, size + 4);
+ n = sendto(f, dp, size + 4, 0,
+ (struct sockaddr *)&peer, peer.ss_len);
+ if (n != size + 4) {
+ warn("sendto");
+ goto abort;
+ }
+ if (block)
+ read_ahead(file, blksize, convert);
+ for ( ; ; ) {
+ alarm(rexmtval);
+ do {
+ fromlen = sizeof(from);
+ n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while (n <= 0);
+ alarm(0);
+ if (n < 0) {
+ warn("recvfrom");
+ goto abort;
+ }
+ if (!serv.ss_family)
+ serv = from;
+ else if (!sockaddrcmp((struct sockaddr *)&serv,
+ (struct sockaddr *)&from)) {
+ warn("server address/port mismatch");
+ goto abort;
+ }
+ peer = from;
+ if (trace)
+ tpacket("received", ap, n);
+ /* should verify packet came from server */
+ ap->th_opcode = ntohs(ap->th_opcode);
+ if (ap->th_opcode == ERROR) {
+ printf("Error code %d: %s\n", ap->th_code,
+ ap->th_msg);
+ txrx_error = 1;
+ goto abort;
+ }
+ if (ap->th_opcode == ACK) {
+ int j;
+
+ ap->th_block = ntohs(ap->th_block);
+ if (ap->th_block == 0 && block == 0) {
+ /*
+ * If the extended options are enabled,
+ * the server just refused 'em all.
+ * The only one that _really_
+ * matters is blksize, but we'll
+ * clear timeout, too.
+ */
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ }
+ if (ap->th_block == (u_short)block) {
+ break;
+ }
+ /* On an error, try to synchronize
+ * both sides.
+ */
+ j = synchnet(f);
+ if (j && trace) {
+ printf("discarded %d packets\n",
+ j);
+ }
+ if (ap->th_block == (u_short)(block-1)) {
+ goto send_data;
+ }
+ }
+ if (ap->th_opcode == OACK) {
+ if (block == 0) {
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ get_options(ap, n);
+ break;
+ }
+ }
+ }
+ if (block > 0)
+ amount += size;
+ block++;
+ } while (size == blksize || block == 1);
+abort:
+ fclose(file);
+ stopclock();
+ if (amount > 0)
+ printstats("Sent", amount);
+ txrx_error = 1;
+}
+
+/*
+ * Receive a file.
+ */
+void
+recvfile(fd, name, mode)
+ int fd;
+ char *name;
+ char *mode;
+{
+ struct tftphdr *ap;
+ struct tftphdr *dp;
+ int n, oack=0;
+ volatile unsigned int block;
+ volatile int size, firsttrip;
+ volatile unsigned long amount;
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+ int readlen;
+ FILE *file;
+ volatile int convert; /* true if converting crlf -> lf */
+ struct sockaddr_storage peer;
+ struct sockaddr_storage serv; /* valid server port number */
+
+ startclock();
+ dp = w_init();
+ ap = (struct tftphdr *)ackbuf;
+ file = fdopen(fd, "w");
+ convert = !strcmp(mode, "netascii");
+ block = 1;
+ firsttrip = 1;
+ amount = 0;
+ memcpy(&peer, &peeraddr, peeraddr.ss_len);
+ memset(&serv, 0, sizeof(serv));
+
+ signal(SIGALRM, timer);
+ do {
+ short rx_opcode;
+
+ if (firsttrip) {
+ size = makerequest(RRQ, name, ap, mode, 0);
+ readlen = PKTSIZE;
+ firsttrip = 0;
+ } else {
+ ap->th_opcode = htons((u_short)ACK);
+ ap->th_block = htons((u_short)(block));
+ readlen = blksize+4;
+ size = 4;
+ block++;
+ }
+ timeout = 0;
+ (void) setjmp(timeoutbuf);
+send_ack:
+ if (trace)
+ tpacket("sent", ap, size);
+ if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer,
+ peer.ss_len) != size) {
+ alarm(0);
+ warn("sendto");
+ goto abort;
+ }
+ write_behind(file, convert);
+ for ( ; ; ) {
+ int j;
+ unsigned short rx_block;
+
+ alarm(rexmtval);
+ do {
+ fromlen = sizeof(from);
+ n = recvfrom(f, dp, readlen, 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while (n <= 0);
+ alarm(0);
+ if (n < 0) {
+ warn("recvfrom");
+ goto abort;
+ }
+ if (serv.ss_family != AF_UNSPEC
+ && !sockaddrcmp((struct sockaddr *)&serv,
+ (struct sockaddr *)&from)) {
+ /* ignore this packet */
+ if (trace && verbose)
+ tpacket("ignored", dp, n);
+ continue;
+ }
+ if (trace)
+ tpacket("received", dp, n);
+ /* should verify client address */
+ rx_opcode = ntohs(dp->th_opcode);
+ switch (rx_opcode) {
+ case ERROR:
+ printf("Error code %d: %s\n", dp->th_code,
+ dp->th_msg);
+ txrx_error = 1;
+ if (serv.ss_family == AF_UNSPEC) {
+ peer = from;
+ }
+ goto abort;
+ case DATA:
+ rx_block = ntohs(dp->th_block);
+ if (rx_block == (u_short)block) {
+ if (block == 1 && !oack) {
+ /* no OACK, revert to defaults */
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ }
+ if (serv.ss_family == AF_UNSPEC) {
+ peer = serv = from;
+ }
+ goto next_packet;
+ }
+ /* On an error, try to synchronize
+ * both sides.
+ */
+ j = synchnet(f);
+ if (j && trace) {
+ printf("discarded %d packets\n", j);
+ }
+ if (rx_block == (u_short)(block - 1)
+ && serv.ss_family != AF_UNSPEC) {
+ goto send_ack; /* resend ack */
+ }
+ break;
+ case OACK:
+ if (block == 1) {
+ if (serv.ss_family == AF_UNSPEC) {
+ serv = peer = from;
+ }
+ oack = 1;
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ get_options(dp, n);
+ ap->th_opcode = htons(ACK);
+ ap->th_block = 0;
+ readlen = blksize+4;
+ size = 4;
+ goto send_ack;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+next_packet:
+ /* size = write(fd, dp->th_data, n - 4); */
+ size = writeit(file, &dp, n - 4, convert);
+ if (size < 0) {
+ nak(errno + 100, (struct sockaddr *)&peer);
+ break;
+ }
+ amount += size;
+ } while (size == blksize);
+abort: /* ok to ack, since user */
+ ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
+ ap->th_block = htons((u_short)block);
+ (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
+ peer.ss_len);
+ write_behind(file, convert); /* flush last buffer */
+ fclose(file);
+ stopclock();
+ if (amount > 0)
+ printstats("Received", amount);
+ txrx_error = 1;
+}
+
+static int
+#ifdef __APPLE__
+makerequest(request, name, tp, mode, filesize)
+#else
+makerequest(request, name, tp, mode)
+#endif
+ int request;
+ const char *name;
+ struct tftphdr *tp;
+ const char *mode;
+#ifdef __APPLE__
+ off_t filesize;
+#endif
+{
+ char *cp;
+
+ tp->th_opcode = htons((u_short)request);
+ cp = tp->th_stuff;
+ strcpy(cp, name);
+ cp += strlen(name);
+ *cp++ = '\0';
+ strcpy(cp, mode);
+ cp += strlen(mode);
+ *cp++ = '\0';
+#ifdef __APPLE__
+ if (tsize) {
+ strcpy(cp, "tsize");
+ cp += strlen(cp);
+ *cp++ = '\0';
+ sprintf(cp, "%lu", (unsigned long) filesize);
+ cp += strlen(cp);
+ *cp++ = '\0';
+ }
+ if (tout) {
+ strcpy(cp, "timeout");
+ cp += strlen(cp);
+ *cp++ = '\0';
+ sprintf(cp, "%d", rexmtval);
+ cp += strlen(cp);
+ *cp++ = '\0';
+ }
+ if (blksize != SEGSIZE) {
+ strcpy(cp, "blksize");
+ cp += strlen(cp);
+ *cp++ = '\0';
+ sprintf(cp, "%d", blksize);
+ cp += strlen(cp);
+ *cp++ = '\0';
+ }
+#endif
+ return (cp - (char *)tp);
+}
+
+struct errmsg {
+ int e_code;
+ const char *e_msg;
+} errmsgs[] = {
+ { EUNDEF, "Undefined error code" },
+ { ENOTFOUND, "File not found" },
+ { EACCESS, "Access violation" },
+ { ENOSPACE, "Disk full or allocation exceeded" },
+ { EBADOP, "Illegal TFTP operation" },
+ { EBADID, "Unknown transfer ID" },
+ { EEXISTS, "File already exists" },
+ { ENOUSER, "No such user" },
+ { EOPTNEG, "Option negotiation failed" },
+ { -1, 0 }
+};
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void
+nak(error, peer)
+ int error;
+ struct sockaddr *peer;
+{
+ struct errmsg *pe;
+ struct tftphdr *tp;
+ int length;
+ size_t msglen;
+
+ tp = (struct tftphdr *)ackbuf;
+ tp->th_opcode = htons((u_short)ERROR);
+ msglen = sizeof(ackbuf) - (&tp->th_msg[0] - ackbuf);
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ break;
+ if (pe->e_code < 0) {
+ tp->th_code = EUNDEF;
+ strlcpy(tp->th_msg, strerror(error - 100), msglen);
+ } else {
+ tp->th_code = htons((u_short)error);
+ strlcpy(tp->th_msg, pe->e_msg, msglen);
+ }
+ length = strlen(tp->th_msg);
+ msglen = &tp->th_msg[length + 1] - ackbuf;
+ if (trace)
+ tpacket("sent", tp, (int)msglen);
+ if (sendto(f, ackbuf, msglen, 0, peer, peer->sa_len) != msglen)
+ warn("nak");
+}
+
+static void
+tpacket(s, tp, n)
+ const char *s;
+ struct tftphdr *tp;
+ int n;
+{
+ static const char *opcodes[] =
+ { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
+ char *cp, *file, *endp, *opt = NULL, *spc;
+ u_short op = ntohs(tp->th_opcode);
+ int i, o;
+
+ if (op < RRQ || op > OACK)
+ printf("%s opcode=%x ", s, op);
+ else
+ printf("%s %s ", s, opcodes[op]);
+ switch (op) {
+
+ case RRQ:
+ case WRQ:
+ n -= 2;
+ cp = tp->th_stuff;
+ endp = cp + n - 1;
+ if (*endp != '\0') { /* Shouldn't happen, but... */
+ *endp = '\0';
+ }
+ file = cp;
+ cp = strchr(cp, '\0') + 1;
+ printf("<file=%s, mode=%s", file, cp);
+ cp = strchr(cp, '\0') + 1;
+ o = 0;
+ while (cp < endp) {
+ i = strlen(cp) + 1;
+ if (o) {
+ printf(", %s=%s", opt, cp);
+ } else {
+ opt = cp;
+ }
+ o = (o+1) % 2;
+ cp += i;
+ }
+ printf(">\n");
+ break;
+
+ case DATA:
+ printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
+ break;
+
+ case ACK:
+ printf("<block=%d>\n", ntohs(tp->th_block));
+ break;
+
+ case ERROR:
+ printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
+ break;
+
+ case OACK:
+ o = 0;
+ n -= 2;
+ cp = tp->th_stuff;
+ endp = cp + n - 1;
+ if (*endp != '\0') { /* Shouldn't happen, but... */
+ *endp = '\0';
+ }
+ printf("<");
+ spc = "";
+ while (cp < endp) {
+ i = strlen(cp) + 1;
+ if (o) {
+ printf("%s%s=%s", spc, opt, cp);
+ spc = ", ";
+ } else {
+ opt = cp;
+ }
+ o = (o+1) % 2;
+ cp += i;
+ }
+ printf(">\n");
+ break;
+ }
+}
+
+struct timeval tstart;
+struct timeval tstop;
+
+static void
+startclock()
+{
+
+ (void)gettimeofday(&tstart, NULL);
+}
+
+static void
+stopclock()
+{
+
+ (void)gettimeofday(&tstop, NULL);
+}
+
+static void
+printstats(direction, amount)
+ const char *direction;
+ unsigned long amount;
+{
+ double delta;
+ /* compute delta in 1/10's second units */
+ delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
+ ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
+ delta = delta/10.; /* back to seconds */
+ printf("%s %ld bytes in %.1f seconds", direction, amount, delta);
+ if (verbose)
+ printf(" [%.0f bits/sec]", (amount*8.)/delta);
+ putchar('\n');
+}
+
+static void
+timer(sig)
+ int sig __unused;
+{
+
+ timeout += rexmtval;
+ if (timeout >= maxtimeout) {
+ printf("Transfer timed out.\n");
+ longjmp(toplevel, -1);
+ }
+ txrx_error = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+typedef union {
+ struct sockaddr * addr;
+ struct sockaddr_in * in;
+ struct sockaddr_in6 * in6;
+} sockaddr_union;
+
+static int
+sockaddrcmp(struct sockaddr * sa, struct sockaddr * sb)
+{
+ sockaddr_union a;
+ sockaddr_union b;
+
+ if (sa->sa_len != sb->sa_len
+ || sa->sa_family != sb->sa_family) {
+ return 0;
+ }
+ a.addr = sa;
+ b.addr = sb;
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (a.in->sin_port != b.in->sin_port
+ || a.in->sin_addr.s_addr != b.in->sin_addr.s_addr) {
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if (a.in6->sin6_port != b.in6->sin6_port
+ || !IN6_ARE_ADDR_EQUAL(&a.in6->sin6_addr,
+ &b.in6->sin6_addr)) {
+ return 0;
+ }
+ break;
+ default:
+ if (bcmp(sa, sb, sa->sa_len) != 0) {
+ return 0;
+ }
+ break;
+ }
+ return 1;
+}
diff --git a/remote_cmds/tftp.tproj/tftpsubs.c b/remote_cmds/tftp.tproj/tftpsubs.c
new file mode 100644
index 0000000..5dbaa87
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftpsubs.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/tftp/tftpsubs.c,v 1.6 2005/02/14 17:42:58 stefanf Exp $");
+
+#ifndef lint
+__attribute__((__used__))
+static const char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+ server. Written originally with multiple buffers in mind, but current
+ implementation has two buffer logic wired in.
+
+ Todo: add some sort of final error check so when the write-buffer
+ is finally flushed, the caller can detect if the disk filled up
+ (or had an i/o error) and return a nak to the other side.
+
+ Jim Guyton 10/85
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tftpsubs.h"
+
+#ifdef __APPLE__
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[MAXPKTSIZE]; /* room for data packet */
+} bfs[2];
+#else
+#define PKTSIZE SEGSIZE+4 /* should be moved to tftp.h */
+
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[PKTSIZE]; /* room for data packet */
+} bfs[2];
+#endif
+
+ /* Values for bf.counter */
+#define BF_ALLOC -3 /* alloc'd but not yet filled */
+#define BF_FREE -2 /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone; /* index of next buffer to use */
+static int current; /* index of buffer in use */
+
+ /* control flags for crlf conversions */
+int newline = 0; /* fillbuf: in middle of newline expansion */
+int prevchar = -1; /* putbuf: previous char (cr check) */
+
+static struct tftphdr *rw_init(int);
+
+struct tftphdr *w_init(void) { return rw_init(0); } /* write-behind */
+struct tftphdr *r_init(void) { return rw_init(1); } /* read-ahead */
+
+static struct tftphdr *
+rw_init(x) /* init for either read-ahead or write-behind */
+ int x; /* zero for write-behind, one for read-head */
+{
+ newline = 0; /* init crlf flag */
+ prevchar = -1;
+ bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
+ current = 0;
+ bfs[1].counter = BF_FREE;
+ nextone = x; /* ahead or behind? */
+ return (struct tftphdr *)bfs[0].buf;
+}
+
+
+/* Have emptied current buffer by sending to net and getting ack.
+ Free it and return next buffer filled with data.
+ */
+int
+readit(file, dpp, amt, convert)
+ FILE *file; /* file opened for read */
+ struct tftphdr **dpp;
+ int amt;
+ int convert; /* if true, convert to ascii */
+{
+ struct bf *b;
+
+ bfs[current].counter = BF_FREE; /* free old one */
+ current = !current; /* "incr" current */
+
+ b = &bfs[current]; /* look at new buffer */
+ if (b->counter == BF_FREE) /* if it's empty */
+ read_ahead(file, amt, convert); /* fill it */
+/* assert(b->counter != BF_FREE);*//* check */
+ *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
+ return b->counter;
+}
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are lf -> cr,lf and cr -> cr, nul
+ */
+void
+read_ahead(file, amt, convert)
+ FILE *file; /* file opened for read */
+ int amt; /* number of bytes to read */
+ int convert; /* if true, convert to ascii */
+{
+ int i;
+ char *p;
+ int c;
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone]; /* look at "next" buffer */
+ if (b->counter != BF_FREE) /* nop if not free */
+ return;
+ nextone = !nextone; /* "incr" next buffer ptr */
+
+ dp = (struct tftphdr *)b->buf;
+
+ if (convert == 0) {
+ b->counter = read(fileno(file), dp->th_data, amt);
+ return;
+ }
+
+ p = dp->th_data;
+ for (i = 0 ; i < amt; i++) {
+ if (newline) {
+ if (prevchar == '\n')
+ c = '\n'; /* lf to cr,lf */
+ else c = '\0'; /* cr to cr,nul */
+ newline = 0;
+ }
+ else {
+ c = getc(file);
+ if (c == EOF) break;
+ if (c == '\n' || c == '\r') {
+ prevchar = c;
+ c = '\r';
+ newline = 1;
+ }
+ }
+ *p++ = c;
+ }
+ b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+ from the queue. Calls write_behind only if next buffer not
+ available.
+ */
+int
+writeit(file, dpp, ct, convert)
+ FILE *file;
+ struct tftphdr **dpp;
+ int ct, convert;
+{
+ bfs[current].counter = ct; /* set size of data to write */
+ current = !current; /* switch to other buffer */
+ if (bfs[current].counter != BF_FREE) /* if not free */
+ (void)write_behind(file, convert); /* flush it */
+ bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
+ *dpp = (struct tftphdr *)bfs[current].buf;
+ return ct; /* this is a lie of course */
+}
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else. In this case we leave it alone.
+ */
+int
+write_behind(file, convert)
+ FILE *file;
+ int convert;
+{
+ char *buf;
+ int count;
+ int ct;
+ char *p;
+ int c; /* current character */
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone];
+ if (b->counter < -1) /* anything to flush? */
+ return 0; /* just nop if nothing to do */
+
+ count = b->counter; /* remember byte count */
+ b->counter = BF_FREE; /* reset flag */
+ dp = (struct tftphdr *)b->buf;
+ nextone = !nextone; /* incr for next time */
+ buf = dp->th_data;
+
+ if (count <= 0) return -1; /* nak logic? */
+
+ if (convert == 0)
+ return write(fileno(file), buf, count);
+
+ p = buf;
+ ct = count;
+ while (ct--) { /* loop over the buffer */
+ c = *p++; /* pick up a character */
+ if (prevchar == '\r') { /* if prev char was cr */
+ if (c == '\n') /* if have cr,lf then just */
+ fseek(file, -1, 1); /* smash lf on top of the cr */
+ else
+ if (c == '\0') /* if have cr,nul then */
+ goto skipit; /* just skip over the putc */
+ /* else just fall through and allow it */
+ }
+ putc(c, file);
+skipit:
+ prevchar = c;
+ }
+ return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch. Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+int
+synchnet(f)
+ int f; /* socket to flush */
+{
+ int i, j = 0;
+ char rbuf[PKTSIZE];
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+
+ while (1) {
+ (void) ioctl(f, FIONREAD, &i);
+ if (i) {
+ j++;
+ fromlen = sizeof from;
+ (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } else {
+ return(j);
+ }
+ }
+}
diff --git a/remote_cmds/tftp.tproj/tftpsubs.h b/remote_cmds/tftp.tproj/tftpsubs.h
new file mode 100644
index 0000000..808acb2
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftpsubs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/tftp/tftpsubs.h,v 1.2 2002/03/22 01:42:34 imp Exp $
+ */
+
+/*
+ * Prototypes for read-ahead/write-behind subroutines for tftp user and
+ * server.
+ */
+struct tftphdr *r_init(void);
+#ifdef __APPLE__
+void read_ahead(FILE *, int, int);
+int readit(FILE *, struct tftphdr **, int, int);
+#else
+void read_ahead(FILE *, int);
+int readit(FILE *, struct tftphdr **, int);
+#endif
+
+int synchnet(int);
+
+struct tftphdr *w_init(void);
+int write_behind(FILE *, int);
+int writeit(FILE *, struct tftphdr **, int, int);
diff --git a/remote_cmds/tftpd.tproj/DERIVED_FILES b/remote_cmds/tftpd.tproj/DERIVED_FILES
new file mode 100644
index 0000000..6e6534d
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/DERIVED_FILES
@@ -0,0 +1,5 @@
+# The following files have been derived from another project. If you do any
+# changes to them here, make sure you mirror them there too.
+
+argon_usrbin/tftp/tftpsubs.h
+argon_usrbin/tftp/tftpsubs.c
diff --git a/remote_cmds/tftpd.tproj/Makefile b/remote_cmds/tftpd.tproj/Makefile
new file mode 100644
index 0000000..e48f484
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/Makefile
@@ -0,0 +1,16 @@
+Project = tftpd
+Install_Dir = /usr/libexec
+
+HFILES = tftpsubs.h
+CFILES = tftpd.c ../tftp.tproj/tftpsubs.c
+MANPAGES = tftpd.8
+LAUNCHD_PLISTS = tftp.plist
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+after_install:
+ $(MKDIR) "$(DSTROOT)/private/tftpboot"
diff --git a/remote_cmds/tftpd.tproj/tftp.plist b/remote_cmds/tftpd.tproj/tftp.plist
new file mode 100644
index 0000000..e31e08b
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftp.plist
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.tftpd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/tftpd</string>
+ <string>-i</string>
+ <string>/private/tftpboot</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+ <key>InitGroups</key>
+ <true/>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>tftp</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/remote_cmds/tftpd.tproj/tftpd.8 b/remote_cmds/tftpd.tproj/tftpd.8
new file mode 100644
index 0000000..14df0f1
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpd.8
@@ -0,0 +1,233 @@
+.\" $NetBSD: tftpd.8,v 1.21 2003/08/07 09:46:53 agc Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)tftpd.8 8.1 (Berkeley) 6/4/93
+.\"
+.Dd June 11, 2003
+.Dt TFTPD 8
+.Os
+.Sh NAME
+.Nm tftpd
+.Nd
+.Tn DARPA
+Internet Trivial File Transfer Protocol server
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl g Ar group
+.Op Fl i
+.Op Fl l
+.Op Fl n
+.Op Fl s Ar directory
+.Op Fl u Ar user
+.Op Ar directory ...
+.Sh DESCRIPTION
+.Nm
+is a server which supports the
+.Tn DARPA
+Trivial File Transfer Protocol.
+The
+.Tn TFTP
+server operates at the port indicated in the
+.Ql tftp
+service description; see
+.Xr services 5 .
+This server should not be started manually; instead, it should be run using
+.Xr launchd 8
+using the plist
+.Pa /System/Library/LaunchDaemons/tftp.plist .
+It may be started using the
+.Xr launchctl 1
+load command; refer to the documentation for that utility for more information.
+.Pp
+The use of
+.Xr tftp 1
+does not require an account or password on the remote system.
+Due to the lack of authentication information,
+.Nm
+will allow only publicly readable files to be accessed.
+Filenames beginning in ``\|\fB.\|.\fP\|/'' or
+containing ``/\|\fB.\|.\fP\|/'' are not allowed.
+Files may be written to only if they already exist and are publicly writable.
+.Pp
+Note that this extends the concept of
+.Qq public
+to include
+all users on all hosts that can be reached through the network;
+this may not be appropriate on all systems, and its implications
+should be considered before enabling tftp service.
+The server should have the user ID with the lowest possible privilege.
+.Pp
+Access to files may be restricted by invoking
+.Nm
+with a list of directories by including up to 20 pathnames
+as server program arguments in
+.Pa /System/Library/LaunchDaemons/tftp.plist .
+In this case access is restricted to files whose
+names are prefixed by the one of the given directories.
+The given directories are also treated as a search path for
+relative filename requests.
+.Pp
+The options are:
+.Bl -tag -width "directory"
+.It Fl d
+Enable verbose debugging messages to
+.Xr syslogd 8 .
+.It Fl g Ar group
+Change gid to that of
+.Ar group
+on startup.
+If this isn't specified, the gid is set to that of the
+.Ar user
+specified with
+.Fl u .
+.It Fl i
+Enable insecure mode, no
+.Xr realpath 3 .
+.It Fl l
+Logs all requests using
+.Xr syslog 3 .
+.It Fl n
+Suppresses negative acknowledgement of requests for nonexistent
+relative filenames.
+.It Fl s Ar directory
+.Nm
+will
+.Xr chroot 2
+to
+.Ar directory
+on startup.
+This is recommended for security reasons (so that files other than
+those in the
+.Pa /tftpboot
+directory aren't accessible).
+If the remote host passes the directory name as part of the
+file name to transfer, you may have to create a symbolic link
+from
+.Sq tftpboot
+to
+.Sq \&.
+under
+.Pa /tftpboot .
+.It Fl u Ar user
+Change uid to that of
+.Ar user
+on startup.
+If
+.Fl u
+isn't given,
+.Ar user
+defaults to
+.Dq nobody .
+If
+.Fl g
+isn't also given, change the gid to that of
+.Ar user
+as well.
+.El
+.Sh SEE ALSO
+.Xr tftp 1 ,
+.Xr launchd 8 ,
+.Xr launchctl 1 ,
+.Xr launchd.plist 5
+.Rs
+.%R RFC
+.%N 1350
+.%D July 1992
+.%T "The TFTP Protocol (Revision 2)"
+.Re
+.Rs
+.%R RFC
+.%N 2347
+.%D May 1998
+.%T "TFTP Option Extension"
+.Re
+.Rs
+.%R RFC
+.%N 2348
+.%D May 1998
+.%T "TFTP Blocksize Option"
+.Re
+.Rs
+.%R RFC
+.%N 2349
+.%D May 1998
+.%T "TFTP Timeout Interval and Transfer Size Options"
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+The
+.Fl s
+flag appeared in
+.Nx 1.0 .
+.Pp
+The
+.Fl g
+and
+.Fl u
+flags appeared in
+.Nx 1.4 .
+.Pp
+IPv6 support was implemented by WIDE/KAME project in 1999.
+.Pp
+TFTP options were implemented by Wasabi Systems, Inc., in 2003,
+and first appeared in
+NetBSD 2.0 .
+.Sh BUGS
+Files larger than 33488896 octets (65535 blocks) cannot be transferred
+without client and server supporting blocksize negotiation (RFCs
+2347 and 2348).
+.Pp
+Many tftp clients will not transfer files over 16744448 octets (32767 blocks).
+.Sh SECURITY CONSIDERATIONS
+You are
+.Em strongly
+advised to set up
+.Nm
+using the
+.Fl s
+flag in conjunction with the name of the directory that
+contains the files that
+.Nm
+will serve to remote hosts (e.g.,
+.Pa /tftpboot ) .
+This ensures that only the files that should be served
+to remote hosts can be accessed by them.
+.Pp
+Because there is no user-login or validation within
+the
+.Tn TFTP
+protocol, the remote site will probably have some
+sort of file-access restrictions in place.
+The exact methods are specific to each site and therefore
+difficult to document here.
diff --git a/remote_cmds/tftpd.tproj/tftpd.c b/remote_cmds/tftpd.tproj/tftpd.c
new file mode 100644
index 0000000..8e4c118
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpd.c
@@ -0,0 +1,1238 @@
+/* $NetBSD: tftpd.c,v 1.28 2004/05/05 20:15:45 kleink Exp $ */
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/tftpd/tftpd.c,v 1.38 2007/11/23 00:05:29 edwin Exp $";
+#endif /* not lint */
+
+/*
+ * Trivial file transfer protocol server.
+ *
+ * This version includes many modifications by Jim Guyton
+ * <guyton@rand-unix>.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "tftpsubs.h"
+
+#define DEFAULTUSER "nobody"
+
+#define TIMEOUT 5
+#define MAX_TIMEOUTS 5
+
+int peer;
+int rexmtval = TIMEOUT;
+int maxtimeout = 5*TIMEOUT;
+
+char buf[MAXPKTSIZE];
+char ackbuf[PKTSIZE];
+char oackbuf[PKTSIZE];
+struct sockaddr_storage from;
+socklen_t fromlen;
+int debug;
+
+int tftp_opt_tsize = 0;
+int tftp_blksize = SEGSIZE;
+int tftp_tsize = 0;
+
+/*
+ * Null-terminated directory prefix list for absolute pathname requests and
+ * search list for relative pathname requests.
+ *
+ * MAXDIRS should be at least as large as the number of arguments that
+ * inetd allows (currently 20).
+ */
+#define MAXDIRS 20
+static struct dirlist {
+ const char *name;
+ int len;
+} dirs[MAXDIRS+1];
+static int suppress_naks;
+static int logging;
+static int insecure=0;
+static int secure;
+static char *securedir;
+
+struct formats;
+
+static const char *errtomsg(int);
+static void nak(int);
+#ifndef __APPLE__
+static void oack(void);
+#endif
+
+static void timer(int);
+static void justquit(int);
+
+static void tftp(struct tftphdr *, int);
+static void usage(void);
+static char *verifyhost(struct sockaddr *);
+int main(int, char **);
+void recvfile(struct formats *, int, int);
+void xmitfile(struct formats *, int, int);
+static const char *opcode(int);
+int validate_access(char **, int);
+
+struct formats {
+ const char *f_mode;
+ int (*f_validate)(char **, int);
+ void (*f_send)(struct formats *, int, int);
+ void (*f_recv)(struct formats *, int, int);
+ int f_convert;
+} formats[] = {
+ { "netascii", validate_access, xmitfile, recvfile, 1 },
+ { "octet", validate_access, xmitfile, recvfile, 0 },
+ { 0 }
+};
+
+static void
+usage(void)
+{
+
+ syslog(LOG_ERR,
+ "Usage: %s [-diln] [-u user] [-g group] [-s directory] [directory ...]",
+ getprogname());
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_storage me;
+ struct passwd *pwent;
+ struct group *grent;
+ struct tftphdr *tp;
+ char *tgtuser, *tgtgroup, *ep;
+ int n, ch, on, fd;
+ socklen_t len;
+ int soopt;
+ uid_t curuid, tgtuid;
+ gid_t curgid, tgtgid;
+ long nid;
+
+ n = 0;
+ fd = 0;
+ tzset();
+ openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
+ tgtuser = DEFAULTUSER;
+ tgtgroup = NULL;
+ curuid = getuid();
+ curgid = getgid();
+
+ while ((ch = getopt(argc, argv, "dg:ilns:u:")) != -1)
+ switch (ch) {
+ case 'd':
+ debug++;
+ break;
+
+ case 'g':
+ tgtgroup = optarg;
+ break;
+
+ case 'i':
+ insecure = 1;
+ break;
+
+ case 'l':
+ logging = 1;
+ break;
+
+ case 'n':
+ suppress_naks = 1;
+ break;
+
+ case 's':
+ secure = 1;
+ securedir = optarg;
+ break;
+
+ case 'u':
+ tgtuser = optarg;
+ break;
+
+ default:
+ usage();
+ break;
+ }
+
+ if (optind < argc) {
+ struct dirlist *dirp;
+
+ /* Get list of directory prefixes. Skip relative pathnames. */
+ for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
+ optind++) {
+ if (argv[optind][0] == '/') {
+ dirp->name = argv[optind];
+ dirp->len = strlen(dirp->name);
+ dirp++;
+ }
+ }
+ }
+
+ if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0'))
+ usage();
+
+ nid = (strtol(tgtuser, &ep, 10));
+ if (*ep == '\0') {
+ if (nid > UID_MAX) {
+ syslog(LOG_ERR, "uid %ld is too large", nid);
+ exit(1);
+ }
+ pwent = getpwuid((uid_t)nid);
+ } else
+ pwent = getpwnam(tgtuser);
+ if (pwent == NULL) {
+ syslog(LOG_ERR, "unknown user `%s'", tgtuser);
+ exit(1);
+ }
+ tgtuid = pwent->pw_uid;
+ tgtgid = pwent->pw_gid;
+
+ if (tgtgroup != NULL) {
+ nid = (strtol(tgtgroup, &ep, 10));
+ if (*ep == '\0') {
+ if (nid > GID_MAX) {
+ syslog(LOG_ERR, "gid %ld is too large", nid);
+ exit(1);
+ }
+ grent = getgrgid((gid_t)nid);
+ } else
+ grent = getgrnam(tgtgroup);
+ if (grent != NULL)
+ tgtgid = grent->gr_gid;
+ else {
+ syslog(LOG_ERR, "unknown group `%s'", tgtgroup);
+ exit(1);
+ }
+ }
+
+ if (secure) {
+ if (chdir(securedir) < 0) {
+ syslog(LOG_ERR, "chdir %s: %m", securedir);
+ exit(1);
+ }
+ if (chroot(".")) {
+ syslog(LOG_ERR, "chroot: %m");
+ exit(1);
+ }
+ }
+
+ if (logging)
+ syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)",
+ tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)",
+ tgtgid);
+ if (curgid != tgtgid) {
+ if (setgid(tgtgid)) {
+ syslog(LOG_ERR, "setgid to %d: %m", (int)tgtgid);
+ exit(1);
+ }
+ if (setgroups(0, NULL)) {
+ syslog(LOG_ERR, "setgroups: %m");
+ exit(1);
+ }
+ }
+
+ if (curuid != tgtuid) {
+ if (setuid(tgtuid)) {
+ syslog(LOG_ERR, "setuid to %d: %m", (int)tgtuid);
+ exit(1);
+ }
+ }
+
+ on = 1;
+ if (ioctl(fd, FIONBIO, &on) < 0) {
+ syslog(LOG_ERR, "ioctl(FIONBIO): %m");
+ exit(1);
+ }
+ fromlen = sizeof (from);
+ n = recvfrom(fd, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ if (n < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ /*
+ * Now that we have read the message out of the UDP
+ * socket, we fork and exit. Thus, inetd will go back
+ * to listening to the tftp port, and the next request
+ * to come in will start up a new instance of tftpd.
+ *
+ * We do this so that inetd can run tftpd in "wait" mode.
+ * The problem with tftpd running in "nowait" mode is that
+ * inetd may get one or more successful "selects" on the
+ * tftp port before we do our receive, so more than one
+ * instance of tftpd may be started up. Worse, if tftpd
+ * break before doing the above "recvfrom", inetd would
+ * spawn endless instances, clogging the system.
+ */
+ {
+ int i, pid;
+ socklen_t j;
+
+ for (i = 1; i < 20; i++) {
+ pid = fork();
+ if (pid < 0) {
+ sleep(i);
+ /*
+ * flush out to most recently sent request.
+ *
+ * This may drop some request, but those
+ * will be resent by the clients when
+ * they timeout. The positive effect of
+ * this flush is to (try to) prevent more
+ * than one tftpd being started up to service
+ * a single request from a single client.
+ */
+ j = sizeof from;
+ i = recvfrom(fd, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &j);
+ if (i > 0) {
+ n = i;
+ fromlen = j;
+ }
+ } else {
+ break;
+ }
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ } else if (pid != 0) {
+ exit(0);
+ }
+ }
+
+ /*
+ * remember what address this was sent to, so we can respond on the
+ * same interface
+ */
+ len = sizeof(me);
+ if (getsockname(fd, (struct sockaddr *)&me, &len) == 0) {
+ switch (me.ss_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)&me)->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&me)->sin6_port = 0;
+ break;
+ default:
+ /* unsupported */
+ break;
+ }
+ } else {
+ memset(&me, 0, sizeof(me));
+ me.ss_family = from.ss_family;
+ me.ss_len = from.ss_len;
+ }
+ alarm(0);
+ close(fd);
+ close(1);
+ peer = socket(from.ss_family, SOCK_DGRAM, 0);
+ if (peer < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+ if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ exit(1);
+ }
+ if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
+ syslog(LOG_ERR, "connect: %m");
+ exit(1);
+ }
+ soopt = 65536; /* larger than we'll ever need */
+ if (setsockopt(peer, SOL_SOCKET, SO_SNDBUF, (void *) &soopt, sizeof(soopt)) < 0) {
+ syslog(LOG_ERR, "set SNDBUF: %m");
+ exit(1);
+ }
+ if (setsockopt(peer, SOL_SOCKET, SO_RCVBUF, (void *) &soopt, sizeof(soopt)) < 0) {
+ syslog(LOG_ERR, "set RCVBUF: %m");
+ exit(1);
+ }
+
+ tp = (struct tftphdr *)buf;
+ tp->th_opcode = ntohs(tp->th_opcode);
+ if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
+ tftp(tp, n);
+ exit(1);
+}
+
+static int
+blk_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
+ int *ackl, int *ec)
+{
+ unsigned long bsize;
+ char *endp;
+ int l;
+
+ /*
+ * On these failures, we could just ignore the blocksize option.
+ * Perhaps that should be a command-line option.
+ */
+ errno = 0;
+ bsize = strtoul(val, &endp, 10);
+ if ((bsize == ULONG_MAX && errno == ERANGE) || *endp) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "illegal value %s for blksize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+ if (bsize < 8 || bsize > 65464) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "out of range value %s for blksize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+
+ tftp_blksize = bsize;
+ strcpy(ack + *ackl, "blksize");
+ *ackl += 8;
+ l = sprintf(ack + *ackl, "%lu", bsize);
+ *ackl += l + 1;
+
+ return 0;
+}
+
+static int
+timeout_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
+ int *ackl, int *ec)
+{
+ unsigned long tout;
+ char *endp;
+ int l;
+
+ errno = 0;
+ tout = strtoul(val, &endp, 10);
+ if ((tout == ULONG_MAX && errno == ERANGE) || *endp) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "illegal value %s for timeout option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+ if (tout < 1 || tout > 255) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "out of range value %s for timeout option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+
+ rexmtval = tout;
+ strcpy(ack + *ackl, "timeout");
+ *ackl += 8;
+ l = sprintf(ack + *ackl, "%lu", tout);
+ *ackl += l + 1;
+
+ /*
+ * Arbitrarily pick a maximum timeout on a request to 3
+ * retransmissions if the interval timeout is more than
+ * one minute. Longest possible timeout is therefore
+ * 3 * 255 - 1, or 764 seconds.
+ */
+ if (rexmtval > 60) {
+ maxtimeout = rexmtval * 3;
+ } else {
+ maxtimeout = rexmtval * 5;
+ }
+
+ return 0;
+}
+
+static int
+tsize_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
+ int *ackl, int *ec)
+{
+ unsigned long fsize;
+ char *endp;
+
+ /*
+ * Maximum file even with extended tftp is 65535 blocks of
+ * length 65464, or 4290183240 octets (4784056 less than 2^32).
+ * unsigned long is at least 32 bits on all NetBSD archs.
+ */
+
+ errno = 0;
+ fsize = strtoul(val, &endp, 10);
+ if ((fsize == ULONG_MAX && errno == ERANGE) || *endp) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "illegal value %s for tsize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+ if (fsize > (unsigned long) 65535 * 65464) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "out of range value %s for tsize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+
+ tftp_opt_tsize = 1;
+ tftp_tsize = fsize;
+ /*
+ * We will report this later -- either replying with the fsize (WRQ)
+ * or replying with the actual filesize (RRQ).
+ */
+
+ return 0;
+}
+
+struct tftp_options {
+ char *o_name;
+ int (*o_handler)(struct tftphdr *, char *, char *, char *,
+ int *, int *);
+} options[] = {
+ { "blksize", blk_handler },
+ { "timeout", timeout_handler },
+ { "tsize", tsize_handler },
+ { NULL, NULL }
+};
+
+enum opt_enum {
+ OPT_TSIZE = 0,
+ OPT_TIMEOUT,
+};
+
+/*
+ * Get options for an extended tftp session. Stuff the ones we
+ * recognize in oackbuf.
+ */
+static int
+get_options(struct tftphdr *tp, char *cp, int size, char *ackb,
+ int *alen, int *err)
+{
+ struct tftp_options *op;
+ char *option, *value, *endp;
+ int r, rv=0, ec=0;
+
+ endp = cp + size;
+ while (cp < endp) {
+ option = cp;
+ while (*cp && cp < endp) {
+ *cp = tolower(*cp);
+ cp++;
+ }
+ if (*cp) {
+ /* if we have garbage at the end, just ignore it */
+ break;
+ }
+ cp++; /* skip over NUL */
+ value = cp;
+ while (*cp && cp < endp) {
+ cp++;
+ }
+ if (*cp) {
+ /* if we have garbage at the end, just ignore it */
+ break;
+ }
+ cp++;
+ for (op = options; op->o_name; op++) {
+ if (strcmp(op->o_name, option) == 0)
+ break;
+ }
+ if (op->o_name) {
+ r = op->o_handler(tp, option, value, ackb, alen, &ec);
+ if (r < 0) {
+ rv = -1;
+ break;
+ }
+ rv++;
+ } /* else ignore unknown options */
+ }
+
+ if (rv < 0)
+ *err = ec;
+
+ return rv;
+}
+
+/*
+ * Handle initial connection protocol.
+ */
+static void
+tftp(struct tftphdr *tp, int size)
+{
+ struct formats *pf;
+ char *cp;
+ char *filename, *mode;
+ int first, ecode=0, alen, etftp=0, r;
+
+ first = 1;
+ mode = NULL;
+
+ filename = cp = tp->th_stuff;
+again:
+ while (cp < buf + size) {
+ if (*cp == '\0')
+ break;
+ cp++;
+ }
+ if (*cp != '\0') {
+ nak(EBADOP);
+ exit(1);
+ }
+ if (first) {
+ mode = ++cp;
+ first = 0;
+ goto again;
+ }
+ for (cp = mode; *cp; cp++)
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ for (pf = formats; pf->f_mode; pf++)
+ if (strcmp(pf->f_mode, mode) == 0)
+ break;
+ if (pf->f_mode == 0) {
+ nak(EBADOP);
+ exit(1);
+ }
+ /*
+ * cp currently points to the NUL byte following the mode.
+ *
+ * If we have some valid options, then let's assume that we're
+ * now dealing with an extended tftp session. Note that if we
+ * don't get any options, then we *must* assume that we do not
+ * have an extended tftp session. If we get options, we fill
+ * in the ack buf to acknowledge them. If we skip that, then
+ * the client *must* assume that we are not using an extended
+ * session.
+ */
+ size -= (++cp - (char *) tp);
+ if (size > 0 && *cp) {
+ alen = 2; /* Skip over opcode */
+ r = get_options(tp, cp, size, oackbuf, &alen, &ecode);
+ if (r > 0) {
+ etftp = 1;
+ } else if (r < 0) {
+ nak(ecode);
+ exit(1);
+ }
+ }
+ ecode = (*pf->f_validate)(&filename, tp->th_opcode);
+ if (logging) {
+ syslog(LOG_INFO, "%s: %s request for %s: %s",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ filename, errtomsg(ecode));
+ }
+ if (ecode) {
+ /*
+ * Avoid storms of naks to a RRQ broadcast for a relative
+ * bootfile pathname from a diskless Sun.
+ */
+ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
+ exit(0);
+ nak(ecode);
+ exit(1);
+ }
+
+ if (etftp) {
+ struct tftphdr *oack_h;
+
+ if (tftp_opt_tsize) {
+ int l;
+
+ strcpy(oackbuf + alen, "tsize");
+ alen += 6;
+ l = sprintf(oackbuf + alen, "%u", tftp_tsize);
+ alen += l + 1;
+ }
+ oack_h = (struct tftphdr *) oackbuf;
+ oack_h->th_opcode = htons(OACK);
+ }
+
+ if (tp->th_opcode == WRQ)
+ (*pf->f_recv)(pf, etftp, alen);
+ else
+ (*pf->f_send)(pf, etftp, alen);
+ exit(0);
+}
+
+
+FILE *file;
+
+/*
+ * Validate file access. Since we
+ * have no uid or gid, for now require
+ * file to exist and be publicly
+ * readable/writable.
+ * If we were invoked with arguments
+ * from inetd then the file must also be
+ * in one of the given directory prefixes.
+ */
+int
+validate_access(char **filep, int mode)
+{
+ struct stat stbuf;
+ struct dirlist *dirp;
+ static char pathname[MAXPATHLEN];
+ int fd;
+ char *filename;
+#ifdef __APPLE__
+ static char resolved_path[PATH_MAX+1];
+ bzero(resolved_path,PATH_MAX+1);
+ if(insecure) {
+ filename = *filep;
+ } else {
+ if (realpath(*filep, resolved_path)==NULL) {
+ return (EACCESS);
+ }
+ filename = resolved_path;
+ }
+#else
+ filename = *filep;
+#endif
+ /*
+ * Prevent tricksters from getting around the directory restrictions
+ */
+ if (strstr(filename, "/../"))
+ return (EACCESS);
+
+ if (*filename == '/') {
+ /*
+ * Allow the request if it's in one of the approved locations.
+ * Special case: check the null prefix ("/") by looking
+ * for length = 1 and relying on the arg. processing that
+ * it's a /.
+ */
+ for (dirp = dirs; dirp->name != NULL; dirp++) {
+ if (dirp->len == 1 ||
+ (!strncmp(filename, dirp->name, dirp->len) &&
+ filename[dirp->len] == '/'))
+ break;
+ }
+ /* If directory list is empty, allow access to any file */
+ if (dirp->name == NULL && dirp != dirs)
+ return (EACCESS);
+ if (stat(filename, &stbuf) < 0)
+ return (errno == ENOENT ? ENOTFOUND : EACCESS);
+ if (!S_ISREG(stbuf.st_mode))
+ return (ENOTFOUND);
+ if (mode == RRQ) {
+ if ((stbuf.st_mode & S_IROTH) == 0)
+ return (EACCESS);
+ } else {
+ if ((stbuf.st_mode & S_IWOTH) == 0)
+ return (EACCESS);
+ }
+ } else {
+ /*
+ * Relative file name: search the approved locations for it.
+ */
+
+ if (!strncmp(filename, "../", 3))
+ return (EACCESS);
+
+ /*
+ * Find the first file that exists in any of the directories,
+ * check access on it.
+ */
+ if (dirs[0].name != NULL) {
+ for (dirp = dirs; dirp->name != NULL; dirp++) {
+ snprintf(pathname, sizeof pathname, "%s/%s",
+ dirp->name, filename);
+ if (stat(pathname, &stbuf) == 0 &&
+ (stbuf.st_mode & S_IFMT) == S_IFREG) {
+ break;
+ }
+ }
+ if (dirp->name == NULL)
+ return (ENOTFOUND);
+ if (mode == RRQ && !(stbuf.st_mode & S_IROTH))
+ return (EACCESS);
+ if (mode == WRQ && !(stbuf.st_mode & S_IWOTH))
+ return (EACCESS);
+ filename = pathname;
+ *filep = filename;
+ } else {
+ /*
+ * If there's no directory list, take our cue from the
+ * absolute file request check above (*filename == '/'),
+ * and allow access to anything.
+ */
+ if (stat(filename, &stbuf) < 0)
+ return (errno == ENOENT ? ENOTFOUND : EACCESS);
+ if (!S_ISREG(stbuf.st_mode))
+ return (ENOTFOUND);
+ if (mode == RRQ) {
+ if ((stbuf.st_mode & S_IROTH) == 0)
+ return (EACCESS);
+ } else {
+ if ((stbuf.st_mode & S_IWOTH) == 0)
+ return (EACCESS);
+ }
+ *filep = filename;
+ }
+ }
+
+ if (tftp_opt_tsize && mode == RRQ)
+ tftp_tsize = (unsigned long) stbuf.st_size;
+
+ fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | O_TRUNC);
+ if (fd < 0)
+ return (errno + 100);
+ file = fdopen(fd, (mode == RRQ)? "r":"w");
+ if (file == NULL) {
+ close(fd);
+ return (errno + 100);
+ }
+ return (0);
+}
+
+int timeout;
+jmp_buf timeoutbuf;
+
+void
+timer(int dummy)
+{
+
+ timeout += rexmtval;
+ if (timeout >= maxtimeout)
+ exit(1);
+ longjmp(timeoutbuf, 1);
+}
+
+static const char *
+opcode(int code)
+{
+ static char buf[64];
+
+ switch (code) {
+ case RRQ:
+ return "RRQ";
+ case WRQ:
+ return "WRQ";
+ case DATA:
+ return "DATA";
+ case ACK:
+ return "ACK";
+ case ERROR:
+ return "ERROR";
+ case OACK:
+ return "OACK";
+ default:
+ (void)snprintf(buf, sizeof(buf), "*code %d*", code);
+ return buf;
+ }
+}
+
+/*
+ * Send the requested file.
+ */
+void
+xmitfile(struct formats *pf, int etftp, int acklength)
+{
+ volatile unsigned int block;
+ struct tftphdr *dp;
+ struct tftphdr *ap; /* ack packet */
+ int size, n;
+ int first = 1;
+ long amount = 0;
+
+ signal(SIGALRM, timer);
+ ap = (struct tftphdr *)ackbuf;
+ if (etftp) {
+ dp = (struct tftphdr *)oackbuf;
+ size = acklength - 4;
+ block = 0;
+ } else {
+ dp = r_init();
+ size = 0;
+ block = 1;
+ }
+
+ do {
+ if (block > 0) {
+ size = readit(file, &dp, tftp_blksize, pf->f_convert);
+ if (size < 0) {
+ nak(errno + 100);
+ goto abort;
+ }
+ dp->th_opcode = htons((u_short)DATA);
+ dp->th_block = htons((u_short)block);
+ }
+ timeout = 0;
+ (void)setjmp(timeoutbuf);
+
+send_data:
+ if (!etftp && debug)
+ syslog(LOG_DEBUG, "Send DATA %u", block);
+ if ((n = send(peer, dp, size + 4, 0)) != size + 4) {
+ if (errno != ENOBUFS) {
+ syslog(LOG_ERR, "tftpd: write: %m");
+ goto abort;
+ }
+ }
+ amount += size;
+ if (block)
+ read_ahead(file, tftp_blksize, pf->f_convert);
+ for ( ; ; ) {
+ alarm(rexmtval); /* read the ack */
+ n = recv(peer, ackbuf, tftp_blksize, 0);
+ alarm(0);
+ if (n < 0) {
+ syslog(LOG_ERR, "tftpd: read: %m");
+ goto abort;
+ }
+ ap->th_opcode = ntohs((u_short)ap->th_opcode);
+ ap->th_block = ntohs((u_short)ap->th_block);
+ switch (ap->th_opcode) {
+ case ERROR:
+ goto abort;
+
+ case ACK:
+ if (ap->th_block == 0 && first && block == 0) {
+ first = 0;
+ etftp = 0;
+ acklength = 0;
+ dp = r_init();
+ goto done;
+ }
+ if (ap->th_block == (u_short)block)
+ goto done;
+ if (debug)
+ syslog(LOG_DEBUG, "Resync ACK %u != %u",
+ (unsigned int)ap->th_block, block);
+ /* Re-synchronize with the other side */
+ (void) synchnet(peer, tftp_blksize);
+ if (ap->th_block == (u_short)(block-1))
+ goto send_data;
+ default:
+ syslog(LOG_INFO, "Received %s in sendfile\n",
+ opcode(dp->th_opcode));
+ }
+
+ }
+done:
+ if (debug)
+ syslog(LOG_DEBUG, "Received ACK for block %u", block);
+ block++;
+ } while (size == tftp_blksize || block == 1);
+abort:
+ if (logging) {
+ syslog(LOG_DEBUG, "%s: request completed (%ld bytes)",
+ verifyhost((struct sockaddr *)&from), amount);
+ }
+ (void) fclose(file);
+}
+
+void
+justquit(int dummy)
+{
+
+ exit(0);
+}
+
+/*
+ * Receive a file.
+ */
+void
+recvfile(struct formats *pf, int etftp, int acklength)
+{
+ volatile unsigned int block;
+ struct tftphdr *dp;
+ struct tftphdr *ap; /* ack buffer */
+ int n, size;
+
+ signal(SIGALRM, timer);
+ dp = w_init();
+ ap = (struct tftphdr *)oackbuf;
+ block = 0;
+ do {
+ timeout = 0;
+ if (etftp == 0) {
+ ap = (struct tftphdr *)ackbuf;
+ ap->th_opcode = htons((u_short)ACK);
+ ap->th_block = htons((u_short)block);
+ acklength = 4;
+ }
+ if (debug)
+ syslog(LOG_DEBUG, "Sending ACK for block %u\n", block);
+ block++;
+ (void) setjmp(timeoutbuf);
+send_ack:
+ if (send(peer, ap, acklength, 0) != acklength) {
+ syslog(LOG_ERR, "tftpd: write: %m");
+ goto abort;
+ }
+ write_behind(file, pf->f_convert);
+ for ( ; ; ) {
+ alarm(rexmtval);
+ n = recv(peer, dp, tftp_blksize + 4, 0);
+ alarm(0);
+ if (n < 0) { /* really? */
+ syslog(LOG_ERR, "tftpd: read: %m");
+ goto abort;
+ }
+ etftp = 0;
+ dp->th_opcode = ntohs((u_short)dp->th_opcode);
+ dp->th_block = ntohs((u_short)dp->th_block);
+ if (debug)
+ syslog(LOG_DEBUG, "Received %s for block %u",
+ opcode(dp->th_opcode),
+ (unsigned int)dp->th_block);
+
+ switch (dp->th_opcode) {
+ case ERROR:
+ goto abort;
+ case DATA:
+ if (dp->th_block == (u_short)block)
+ goto done; /* normal */
+ if (debug)
+ syslog(LOG_DEBUG, "Resync %u != %u",
+ (unsigned int)dp->th_block, block);
+ /* Re-synchronize with the other side */
+ (void) synchnet(peer, tftp_blksize);
+ if (dp->th_block == (u_short)(block-1))
+ goto send_ack; /* rexmit */
+ break;
+ default:
+ syslog(LOG_INFO, "Received %s in recvfile\n",
+ opcode(dp->th_opcode));
+ break;
+ }
+ }
+done:
+ if (debug)
+ syslog(LOG_DEBUG, "Got block %u", block);
+ /* size = write(file, dp->th_data, n - 4); */
+ size = writeit(file, &dp, n - 4, pf->f_convert);
+ if (size != (n-4)) { /* ahem */
+ if (size < 0) nak(errno + 100);
+ else nak(ENOSPACE);
+ goto abort;
+ }
+ } while (size == tftp_blksize);
+ write_behind(file, pf->f_convert);
+ if (logging) {
+ syslog(LOG_DEBUG, "%s: request completed",
+ verifyhost((struct sockaddr *)&from));
+ }
+ (void) fclose(file); /* close data file */
+
+ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
+ ap->th_block = htons((u_short)(block));
+ if (debug)
+ syslog(LOG_DEBUG, "Send final ACK %u", block);
+ (void) send(peer, ackbuf, 4, 0);
+
+ signal(SIGALRM, justquit); /* just quit on timeout */
+ alarm(rexmtval);
+ n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
+ alarm(0);
+ if (n >= 4 && /* if read some data */
+ dp->th_opcode == DATA && /* and got a data block */
+ block == dp->th_block) { /* then my last ack was lost */
+ (void) send(peer, ackbuf, 4, 0); /* resend final ack */
+ }
+abort:
+ return;
+}
+
+const struct errmsg {
+ int e_code;
+ const char *e_msg;
+} errmsgs[] = {
+ { EUNDEF, "Undefined error code" },
+ { ENOTFOUND, "File not found" },
+ { EACCESS, "Access violation" },
+ { ENOSPACE, "Disk full or allocation exceeded" },
+ { EBADOP, "Illegal TFTP operation" },
+ { EBADID, "Unknown transfer ID" },
+ { EEXISTS, "File already exists" },
+ { ENOUSER, "No such user" },
+ { EOPTNEG, "Option negotiation failed" },
+ { -1, 0 }
+};
+
+static const char *
+errtomsg(int error)
+{
+ static char ebuf[20];
+ const struct errmsg *pe;
+
+ if (error == 0)
+ return ("success");
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ return (pe->e_msg);
+ snprintf(ebuf, sizeof(ebuf), "error %d", error);
+ return (ebuf);
+}
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void
+nak(int error)
+{
+ const struct errmsg *pe;
+ struct tftphdr *tp;
+ int length;
+ size_t msglen;
+
+ tp = (struct tftphdr *)buf;
+ tp->th_opcode = htons((u_short)ERROR);
+ msglen = sizeof(buf) - (&tp->th_msg[0] - buf);
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ break;
+ if (pe->e_code < 0) {
+ tp->th_code = EUNDEF; /* set 'undef' errorcode */
+ strlcpy(tp->th_msg, strerror(error - 100), msglen);
+ } else {
+ tp->th_code = htons((u_short)error);
+ strlcpy(tp->th_msg, pe->e_msg, msglen);
+ }
+ if (debug)
+ syslog(LOG_DEBUG, "Send NACK %s", tp->th_msg);
+ length = strlen(tp->th_msg);
+ msglen = &tp->th_msg[length + 1] - buf;
+ if (send(peer, buf, msglen, 0) != msglen)
+ syslog(LOG_ERR, "nak: %m");
+}
+
+static char *
+verifyhost(struct sockaddr *fromp)
+{
+ static char hbuf[MAXHOSTNAMELEN];
+
+ if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0))
+ if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf),
+ NULL, 0, NI_NUMERICHOST))
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ return (hbuf);
+}
+
+#ifndef __APPLE__
+/*
+ * Send an oack packet (option acknowledgement).
+ */
+static void
+oack(void)
+{
+ struct tftphdr *tp, *ap;
+ int size, i, n;
+ char *bp;
+
+ tp = (struct tftphdr *)buf;
+ bp = buf + 2;
+ size = sizeof(buf) - 2;
+ tp->th_opcode = htons((u_short)OACK);
+ for (i = 0; options[i].o_type != NULL; i++) {
+ if (options[i].o_request) {
+ n = snprintf(bp, size, "%s%c%d", options[i].o_type,
+ 0, options[i].o_reply);
+ bp += n+1;
+ size -= n+1;
+ if (size < 0) {
+ syslog(LOG_ERR, "oack: buffer overflow");
+ exit(1);
+ }
+ }
+ }
+ size = bp - buf;
+ ap = (struct tftphdr *)ackbuf;
+ signal(SIGALRM, timer);
+ timeouts = 0;
+
+ (void)setjmp(timeoutbuf);
+ if (send(peer, buf, size, 0) != size) {
+ syslog(LOG_INFO, "oack: %m");
+ exit(1);
+ }
+
+ for (;;) {
+ alarm(rexmtval);
+ n = recv(peer, ackbuf, sizeof (ackbuf), 0);
+ alarm(0);
+ if (n < 0) {
+ syslog(LOG_ERR, "recv: %m");
+ exit(1);
+ }
+ ap->th_opcode = ntohs((u_short)ap->th_opcode);
+ ap->th_block = ntohs((u_short)ap->th_block);
+ if (ap->th_opcode == ERROR)
+ exit(1);
+ if (ap->th_opcode == ACK && ap->th_block == 0)
+ break;
+ }
+}
+#endif /* !__APPLE__ */
diff --git a/remote_cmds/tftpd.tproj/tftpsubs.c b/remote_cmds/tftpd.tproj/tftpsubs.c
new file mode 100644
index 0000000..90f75bb
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpsubs.c
@@ -0,0 +1,285 @@
+/* $NetBSD: tftpsubs.c,v 1.8 2003/08/07 11:16:14 agc Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: tftpsubs.c,v 1.8 2003/08/07 11:16:14 agc Exp $");
+#endif
+#endif /* not lint */
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+ server. Written originally with multiple buffers in mind, but current
+ implementation has two buffer logic wired in.
+
+ Todo: add some sort of final error check so when the write-buffer
+ is finally flushed, the caller can detect if the disk filled up
+ (or had an i/o error) and return a nak to the other side.
+
+ Jim Guyton 10/85
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tftpsubs.h"
+
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[MAXPKTSIZE]; /* room for data packet */
+} bfs[2];
+
+ /* Values for bf.counter */
+#define BF_ALLOC -3 /* alloc'd but not yet filled */
+#define BF_FREE -2 /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone; /* index of next buffer to use */
+static int current; /* index of buffer in use */
+
+ /* control flags for crlf conversions */
+int newline = 0; /* fillbuf: in middle of newline expansion */
+int prevchar = -1; /* putbuf: previous char (cr check) */
+
+static struct tftphdr *rw_init __P((int));
+
+struct tftphdr *
+w_init() /* write-behind */
+{
+ return rw_init(0);
+}
+
+struct tftphdr *
+r_init() /* read-ahead */
+{
+ return rw_init(1);
+}
+
+static struct tftphdr *
+rw_init(x) /* init for either read-ahead or write-behind */
+ int x; /* zero for write-behind, one for read-head */
+{
+ newline = 0; /* init crlf flag */
+ prevchar = -1;
+ bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
+ current = 0;
+ bfs[1].counter = BF_FREE;
+ nextone = x; /* ahead or behind? */
+ return (struct tftphdr *)bfs[0].buf;
+}
+
+/* Have emptied current buffer by sending to net and getting ack.
+ Free it and return next buffer filled with data.
+ */
+int
+readit(file, dpp, amt, convert)
+ FILE *file; /* file opened for read */
+ struct tftphdr **dpp;
+ int amt;
+ int convert; /* if true, convert to ascii */
+{
+ struct bf *b;
+
+ bfs[current].counter = BF_FREE; /* free old one */
+ current = !current; /* "incr" current */
+
+ b = &bfs[current]; /* look at new buffer */
+ if (b->counter == BF_FREE) /* if it's empty */
+ read_ahead(file, amt, convert); /* fill it */
+/* assert(b->counter != BF_FREE);*//* check */
+ *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
+ return b->counter;
+}
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are lf -> cr,lf and cr -> cr, nul
+ */
+void
+read_ahead(file, amt, convert)
+ FILE *file; /* file opened for read */
+ int amt; /* number of bytes to read */
+ int convert; /* if true, convert to ascii */
+{
+ int i;
+ char *p;
+ int c;
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone]; /* look at "next" buffer */
+ if (b->counter != BF_FREE) /* nop if not free */
+ return;
+ nextone = !nextone; /* "incr" next buffer ptr */
+
+ dp = (struct tftphdr *)b->buf;
+
+ if (convert == 0) {
+ b->counter = read(fileno(file), dp->th_data, amt);
+ return;
+ }
+
+ p = dp->th_data;
+ for (i = 0 ; i < amt; i++) {
+ if (newline) {
+ if (prevchar == '\n')
+ c = '\n'; /* lf to cr,lf */
+ else c = '\0'; /* cr to cr,nul */
+ newline = 0;
+ }
+ else {
+ c = getc(file);
+ if (c == EOF) break;
+ if (c == '\n' || c == '\r') {
+ prevchar = c;
+ c = '\r';
+ newline = 1;
+ }
+ }
+ *p++ = c;
+ }
+ b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+ from the queue. Calls write_behind only if next buffer not
+ available.
+ */
+int
+writeit(file, dpp, ct, convert)
+ FILE *file;
+ struct tftphdr **dpp;
+ int ct, convert;
+{
+ bfs[current].counter = ct; /* set size of data to write */
+ current = !current; /* switch to other buffer */
+ if (bfs[current].counter != BF_FREE) /* if not free */
+ (void)write_behind(file, convert); /* flush it */
+ bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
+ *dpp = (struct tftphdr *)bfs[current].buf;
+ return ct; /* this is a lie of course */
+}
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else. In this case we leave it alone.
+ */
+int
+write_behind(file, convert)
+ FILE *file;
+ int convert;
+{
+ char *buf;
+ int count;
+ int ct;
+ char *p;
+ int c; /* current character */
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone];
+ if (b->counter < -1) /* anything to flush? */
+ return 0; /* just nop if nothing to do */
+
+ count = b->counter; /* remember byte count */
+ b->counter = BF_FREE; /* reset flag */
+ dp = (struct tftphdr *)b->buf;
+ nextone = !nextone; /* incr for next time */
+ buf = dp->th_data;
+
+ if (count <= 0) return -1; /* nak logic? */
+
+ if (convert == 0)
+ return write(fileno(file), buf, count);
+
+ p = buf;
+ ct = count;
+ while (ct--) { /* loop over the buffer */
+ c = *p++; /* pick up a character */
+ if (prevchar == '\r') { /* if prev char was cr */
+ if (c == '\n') /* if have cr,lf then just */
+ fseek(file, -1, 1); /* smash lf on top of the cr */
+ else
+ if (c == '\0') /* if have cr,nul then */
+ goto skipit; /* just skip over the putc */
+ /* else just fall through and allow it */
+ }
+ putc(c, file);
+skipit:
+ prevchar = c;
+ }
+ return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch. Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+int
+synchnet(f, bsize)
+ int f; /* socket to flush */
+ int bsize; /* size of buffer to sync */
+{
+ int i, j = 0;
+ char rbuf[PKTSIZE];
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+
+ while (1) {
+ (void) ioctl(f, FIONREAD, &i);
+ if (i) {
+ j++;
+ fromlen = sizeof from;
+ (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } else {
+ return(j);
+ }
+ }
+}
diff --git a/remote_cmds/tftpd.tproj/tftpsubs.h b/remote_cmds/tftpd.tproj/tftpsubs.h
new file mode 100644
index 0000000..98284f8
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpsubs.h
@@ -0,0 +1,48 @@
+/* $NetBSD: tftpsubs.h,v 1.4 2003/08/07 11:16:14 agc Exp $ */
+
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Prototypes for read-ahead/write-behind subroutines for tftp user and
+ * server.
+ */
+
+
+struct tftphdr *r_init __P((void));
+void read_ahead __P((FILE *, int, int));
+int readit __P((FILE *, struct tftphdr **, int, int));
+
+int synchnet __P((int, int));
+
+struct tftphdr *w_init __P((void));
+int write_behind __P((FILE *, int));
+int writeit __P((FILE *, struct tftphdr **, int, int));
diff --git a/remote_cmds/wall.tproj/Makefile b/remote_cmds/wall.tproj/Makefile
new file mode 100644
index 0000000..08da621
--- /dev/null
+++ b/remote_cmds/wall.tproj/Makefile
@@ -0,0 +1,16 @@
+Project = wall
+Install_Dir = /usr/bin
+
+HFILES = ttymsg.h
+CFILES = ttymsg.c wall.c
+MANPAGES = wall.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+Extra_CC_Flags += -D__FBSDID=__RCSID
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+#Install_Program_Mode = 02555
+#Install_Program_Group = tty
diff --git a/remote_cmds/wall.tproj/ttymsg.c b/remote_cmds/wall.tproj/ttymsg.c
new file mode 100644
index 0000000..ce94f87
--- /dev/null
+++ b/remote_cmds/wall.tproj/ttymsg.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/wall/ttymsg.c,v 1.12 2006/01/27 08:52:14 ume Exp $");
+
+#ifndef lint
+__attribute__((__used__))
+static const char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "ttymsg.h"
+
+/*
+ * Display the contents of a uio structure on a terminal. Used by wall(1),
+ * syslogd(8), and talkd(8). Forks and finishes in child if write would block,
+ * waiting up to tmout seconds. Returns pointer to error string on unexpected
+ * error; string is not newline-terminated. Various "normal" errors are
+ * ignored (exclusive-use, lack of permission, etc.).
+ */
+const char *
+ttymsg(struct iovec *iov, int iovcnt, const char *line, int tmout)
+{
+ struct iovec localiov[7];
+ ssize_t left, wret;
+ int cnt, fd;
+ static char device[MAXNAMLEN] = _PATH_DEV;
+ static char errbuf[1024];
+ char *p;
+ int forked;
+
+ forked = 0;
+ if (iovcnt > (int)(sizeof(localiov) / sizeof(localiov[0])))
+ return ("too many iov's (change code in wall/ttymsg.c)");
+
+ p = device + sizeof(_PATH_DEV) - 1;
+#ifdef __APPLE__
+ /* radar:13145432 */
+ strlcpy(p, line, sizeof(device) - (sizeof(_PATH_DEV) - 1));
+#else
+ strlcpy(p, line, sizeof(device));
+#endif
+ if (strncmp(p, "pts/", 4) == 0)
+ p += 4;
+ if (strchr(p, '/') != NULL) {
+ /* A slash is an attempt to break security... */
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "Too many '/' in \"%s\"", device);
+ return (errbuf);
+ }
+
+ /*
+ * open will fail on slip lines or exclusive-use lines
+ * if not running as root; not an error.
+ */
+ if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
+#ifndef __APPLE__
+ if (errno == EBUSY || errno == EACCES)
+ return (NULL);
+#endif /* !__APPLE__ */
+ (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device,
+ strerror(errno));
+ return (errbuf);
+ }
+
+ for (cnt = 0, left = 0; cnt < iovcnt; ++cnt)
+ left += iov[cnt].iov_len;
+
+ for (;;) {
+ wret = writev(fd, iov, iovcnt);
+ if (wret >= left)
+ break;
+ if (wret >= 0) {
+ left -= wret;
+ if (iov != localiov) {
+ bcopy(iov, localiov,
+ iovcnt * sizeof(struct iovec));
+ iov = localiov;
+ }
+ for (cnt = 0; (size_t)wret >= iov->iov_len; ++cnt) {
+ wret -= iov->iov_len;
+ ++iov;
+ --iovcnt;
+ }
+ if (wret) {
+ iov->iov_base = (char *)iov->iov_base + wret;
+ iov->iov_len -= wret;
+ }
+ continue;
+ }
+ if (errno == EWOULDBLOCK) {
+ int cpid;
+
+ if (forked) {
+ (void) close(fd);
+ _exit(1);
+ }
+ cpid = fork();
+ if (cpid < 0) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "fork: %s", strerror(errno));
+ (void) close(fd);
+ return (errbuf);
+ }
+ if (cpid) { /* parent */
+ (void) close(fd);
+ return (NULL);
+ }
+ forked++;
+ /* wait at most tmout seconds */
+ (void) signal(SIGALRM, SIG_DFL);
+ (void) signal(SIGTERM, SIG_DFL); /* XXX */
+ (void) sigsetmask(0);
+ (void) alarm((u_int)tmout);
+ (void) fcntl(fd, F_SETFL, 0); /* clear O_NONBLOCK */
+ continue;
+ }
+ /*
+ * We get ENODEV on a slip line if we're running as root,
+ * and EIO if the line just went away.
+ */
+ if (errno == ENODEV || errno == EIO)
+ break;
+ (void) close(fd);
+ if (forked)
+ _exit(1);
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "%s: %s", device, strerror(errno));
+ return (errbuf);
+ }
+
+ (void) close(fd);
+ if (forked)
+ _exit(0);
+ return (NULL);
+}
diff --git a/remote_cmds/wall.tproj/ttymsg.h b/remote_cmds/wall.tproj/ttymsg.h
new file mode 100644
index 0000000..625c22d
--- /dev/null
+++ b/remote_cmds/wall.tproj/ttymsg.h
@@ -0,0 +1,3 @@
+/* $FreeBSD: src/usr.bin/wall/ttymsg.h,v 1.1 2001/09/09 14:23:31 dd Exp $ */
+
+const char *ttymsg(struct iovec *, int, const char *, int);
diff --git a/remote_cmds/wall.tproj/wall.1 b/remote_cmds/wall.tproj/wall.1
new file mode 100644
index 0000000..7c92e63
--- /dev/null
+++ b/remote_cmds/wall.tproj/wall.1
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)wall.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/wall/wall.1,v 1.11 2004/07/17 04:15:27 tjr Exp $
+.\"
+.Dd July 17, 2004
+.Dt WALL 1
+.Os
+.Sh NAME
+.Nm wall
+.Nd write a message to users
+.Sh SYNOPSIS
+.Nm
+.Op Fl g Ar group
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the contents of
+.Ar file
+or, by default, its standard input, on the terminals of all
+currently logged in users.
+.Pp
+Only the super-user can write on the
+terminals of users who have chosen
+to deny messages or are using a program which
+automatically denies messages.
+.Bl -tag -width indent
+.It Fl g
+Send messages to users in this group.
+This option may be specified
+multiple times, and any user in any of the specified groups will
+receive the message.
+.El
+.Sh SEE ALSO
+.Xr mesg 1 ,
+.Xr talk 1 ,
+.Xr write 1 ,
+.Xr shutdown 8
+.Sh HISTORY
+A
+.Nm
+command appeared in PWB UNIX.
+.Sh BUGS
+The sender's
+.Ev LC_CTYPE
+setting is used to determine which characters are safe to write to a
+terminal, not the receiver's (which
+.Nm
+has no way of knowing).
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/remote_cmds/wall.tproj/wall.c b/remote_cmds/wall.tproj/wall.c
new file mode 100644
index 0000000..b856f7b
--- /dev/null
+++ b/remote_cmds/wall.tproj/wall.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/wall/wall.c,v 1.25 2008/01/15 07:40:30 das Exp $");
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+__attribute__((__used__))
+static const char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93";
+#endif
+
+/*
+ * This program is not related to David Wall, whose Stanford Ph.D. thesis
+ * is entitled "Mechanisms for Broadcast and Selective Broadcast".
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <grp.h>
+#include <locale.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+
+#include "ttymsg.h"
+
+static void makemsg(char *);
+static void usage(void);
+
+struct wallgroup {
+ struct wallgroup *next;
+ char *name;
+ gid_t gid;
+} *grouplist;
+int nobanner;
+int mbufsize;
+char *mbuf;
+
+#ifndef __APPLE__
+static int
+ttystat(char *line, int sz)
+{
+ struct stat sb;
+ char ttybuf[MAXPATHLEN];
+
+ (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
+ if (stat(ttybuf, &sb) == 0) {
+ return (0);
+ } else
+ return (-1);
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct iovec iov;
+#ifdef __APPLE__
+ // rdar://problem/4433603
+ struct utmpx *u;
+#else
+ struct utmp utmp;
+#endif
+ int ch;
+ int ingroup;
+#ifndef __APPLE__
+ FILE *fp;
+#endif
+ struct wallgroup *g;
+ struct group *grp;
+ char **np;
+ const char *p;
+ struct passwd *pw;
+#ifdef __APPLE__
+ char line[sizeof(u->ut_line) + 1];
+ char username[sizeof(u->ut_user) + 1];
+#else
+ char line[sizeof(utmp.ut_line) + 1];
+ char username[sizeof(utmp.ut_name) + 1];
+#endif
+
+ (void)setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "g:n")) != -1)
+ switch (ch) {
+ case 'n':
+ /* undoc option for shutdown: suppress banner */
+ if (geteuid() == 0)
+ nobanner = 1;
+ break;
+ case 'g':
+ g = (struct wallgroup *)malloc(sizeof *g);
+ g->next = grouplist;
+ g->name = optarg;
+ g->gid = -1;
+ grouplist = g;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc > 1)
+ usage();
+
+ for (g = grouplist; g; g = g->next) {
+ grp = getgrnam(g->name);
+ if (grp != NULL)
+ g->gid = grp->gr_gid;
+ else
+ warnx("%s: no such group", g->name);
+ }
+
+ makemsg(*argv);
+
+#ifdef __APPLE__
+ setutxent();
+#else
+ if (!(fp = fopen(_PATH_UTMP, "r")))
+ err(1, "cannot read %s", _PATH_UTMP);
+#endif
+ iov.iov_base = mbuf;
+ iov.iov_len = mbufsize;
+ /* NOSTRICT */
+#ifdef __APPLE__
+ while ((u = getutxent()) != NULL) {
+ if (!u->ut_user[0] || u->ut_type != USER_PROCESS)
+ continue;
+#else
+ while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) {
+ if (!utmp.ut_name[0])
+ continue;
+ if (ttystat(utmp.ut_line, UT_LINESIZE) != 0)
+ continue;
+#endif
+ if (grouplist) {
+ ingroup = 0;
+#ifdef __APPLE__
+ strlcpy(username, u->ut_user, sizeof(username));
+#else
+ strlcpy(username, utmp.ut_name, sizeof(utmp.ut_name));
+#endif
+ pw = getpwnam(username);
+ if (!pw)
+ continue;
+ for (g = grouplist; g && ingroup == 0; g = g->next) {
+ if (g->gid == (gid_t)-1)
+ continue;
+ if (g->gid == pw->pw_gid)
+ ingroup = 1;
+ else if ((grp = getgrgid(g->gid)) != NULL) {
+ for (np = grp->gr_mem; *np; np++) {
+ if (strcmp(*np, username) == 0) {
+ ingroup = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (ingroup == 0)
+ continue;
+ }
+#ifdef __APPLE__
+ strlcpy(line, u->ut_line, sizeof(line));
+#else
+ strncpy(line, utmp.ut_line, sizeof(utmp.ut_line));
+ line[sizeof(utmp.ut_line)] = '\0';
+#endif
+ if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL)
+ warnx("%s", p);
+ }
+ exit(0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: wall [-g group] [file]\n");
+ exit(1);
+}
+
+void
+makemsg(char *fname)
+{
+ int cnt;
+ unsigned char ch;
+ struct tm *lt;
+ struct passwd *pw;
+ struct stat sbuf;
+ time_t now;
+ FILE *fp;
+ int fd;
+ char *p, hostname[MAXHOSTNAMELEN], lbuf[256], tmpname[64];
+ const char *tty;
+ const char *whom;
+ gid_t egid;
+
+ (void)snprintf(tmpname, sizeof(tmpname), "%s/wall.XXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(tmpname)) == -1 || !(fp = fdopen(fd, "r+")))
+ err(1, "can't open temporary file");
+ (void)unlink(tmpname);
+
+ if (!nobanner) {
+ tty = ttyname(STDERR_FILENO);
+ if (tty == NULL)
+ tty = "no tty";
+
+ if (!(whom = getlogin()))
+ whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+ (void)gethostname(hostname, sizeof(hostname));
+ (void)time(&now);
+ lt = localtime(&now);
+
+ /*
+ * all this stuff is to blank out a square for the message;
+ * we wrap message lines at column 79, not 80, because some
+ * terminals wrap after 79, some do not, and we can't tell.
+ * Which means that we may leave a non-blank character
+ * in column 80, but that can't be helped.
+ */
+ (void)fprintf(fp, "\r%79s\r\n", " ");
+ (void)snprintf(lbuf, sizeof(lbuf),
+ "Broadcast Message from %s@%s",
+ whom, hostname);
+ (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf);
+ (void)snprintf(lbuf, sizeof(lbuf),
+ " (%s) at %d:%02d %s...", tty,
+ lt->tm_hour, lt->tm_min, lt->tm_zone);
+ (void)fprintf(fp, "%-79.79s\r\n", lbuf);
+ }
+ (void)fprintf(fp, "%79s\r\n", " ");
+
+ if (fname) {
+ egid = getegid();
+ setegid(getgid());
+ if (freopen(fname, "r", stdin) == NULL)
+ err(1, "can't read %s", fname);
+ setegid(egid);
+ }
+ while (fgets(lbuf, sizeof(lbuf), stdin)) {
+ for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
+ if (ch == '\r') {
+ putc('\r', fp);
+ cnt = 0;
+ continue;
+ } else if (ch == '\n') {
+ for (; cnt < 79; ++cnt)
+ putc(' ', fp);
+ putc('\r', fp);
+ putc('\n', fp);
+ break;
+ }
+ if (cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+#ifdef __APPLE__
+ else // rdar://problem/3066405
+#endif
+ if (((ch & 0x80) && ch < 0xA0) ||
+ /* disable upper controls */
+ (!isprint(ch) && !isspace(ch) &&
+ ch != '\a' && ch != '\b')
+ ) {
+ if (ch & 0x80) {
+ ch &= 0x7F;
+ putc('M', fp);
+ if (++cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+ putc('-', fp);
+ if (++cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+ }
+ if (iscntrl(ch)) {
+ ch ^= 040;
+ putc('^', fp);
+ if (++cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+ }
+ }
+#ifdef __APPLE__
+ // rdar://problem/4557295
+ if (ch != '\n')
+#endif
+ putc(ch, fp);
+ }
+ }
+ (void)fprintf(fp, "%79s\r\n", " ");
+ rewind(fp);
+
+ if (fstat(fd, &sbuf))
+ err(1, "can't stat temporary file");
+ mbufsize = sbuf.st_size;
+ if (!(mbuf = malloc((u_int)mbufsize)))
+ err(1, "out of memory");
+ if ((int)fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize)
+ err(1, "can't read temporary file");
+ (void)close(fd);
+}