1 /*
2 Mosh: the mobile shell
3 Copyright 2012 Keith Winstein
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 In addition, as a special exception, the copyright holders give
19 permission to link the code of portions of this program with the
20 OpenSSL library under certain conditions as described in each
21 individual source file, and distribute linked combinations including
22 the two.
23
24 You must obey the GNU General Public License in all respects for all
25 of the code used other than OpenSSL. If you modify file(s) with this
26 exception, you may extend this exception to your version of the
27 file(s), but you are not obligated to do so. If you do not wish to do
28 so, delete this exception statement from your version. If you delete
29 this exception statement from all source files in the program, then
30 also delete it here.
31 */
32
33 #include "config.h"
34 #include "version.h"
35
36 #include <stdlib.h>
37 #include <unistd.h>
38
39 #include "stmclient.h"
40 #include "crypto.h"
41 #include "locale_utils.h"
42 #include "fatal_assert.h"
43
44 /* These need to be included last because of conflicting defines. */
45 /*
46 * stmclient.h includes termios.h, and that will break termio/termios pull in on Solaris.
47 * The solution is to include termio.h also.
48 * But Mac OS X doesn't have termio.h, so this needs a guard.
49 */
50 #ifdef HAVE_TERMIO_H
51 #include <termio.h>
52 #endif
53
54 #if defined HAVE_NCURSESW_CURSES_H
55 # include <ncursesw/curses.h>
56 # include <ncursesw/term.h>
57 #elif defined HAVE_NCURSESW_H
58 # include <ncursesw.h>
59 # include <term.h>
60 #elif defined HAVE_NCURSES_CURSES_H
61 # include <ncurses/curses.h>
62 # include <ncurses/term.h>
63 #elif defined HAVE_NCURSES_H
64 # include <ncurses.h>
65 # include <term.h>
66 #elif defined HAVE_CURSES_H
67 # include <curses.h>
68 # include <term.h>
69 #else
70 # error "SysV or X/Open-compatible Curses header file required"
71 #endif
72
print_version(FILE * file)73 static void print_version( FILE *file )
74 {
75 fprintf( file, "mosh-client (%s) [build %s]\n", PACKAGE_STRING, BUILD_VERSION );
76 fprintf( file, "Copyright 2012 Keith Winstein <mosh-devel@mit.edu>\n" );
77 fprintf( file, "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\nThis is free software: you are free to change and redistribute it.\nThere is NO WARRANTY, to the extent permitted by law.\n" );
78 }
79
print_usage(FILE * file,const char * argv0)80 static void print_usage( FILE *file, const char *argv0 )
81 {
82 print_version( file );
83 fprintf( file, "\n" );
84 fprintf( file, "Usage: %s [-# 'ARGS'] IP PORT\n %s -c\n", argv0, argv0 );
85 }
86
print_colorcount(void)87 static void print_colorcount( void )
88 {
89 /* check colors */
90 setupterm((char *)0, 1, (int *)0);
91
92 char colors_name[] = "colors";
93 int color_val = tigetnum( colors_name );
94 if ( color_val == -2 ) {
95 fprintf( stderr, "Invalid terminfo numeric capability: %s\n",
96 colors_name );
97 }
98
99 printf( "%d\n", color_val );
100 }
101
102 #ifdef NACL
mosh_main(int argc,char * argv[])103 int mosh_main( int argc, char *argv[] )
104 #else
105 int main( int argc, char *argv[] )
106 #endif
107 {
108 unsigned int verbose = 0;
109 /* For security, make sure we don't dump core */
110 Crypto::disable_dumping_core();
111
112 /* Detect edge case */
113 fatal_assert( argc > 0 );
114
115 /* Get arguments */
116 for ( int i = 1; i < argc; i++ ) {
117 if ( 0 == strcmp( argv[ i ], "--help" ) ) {
118 print_usage( stdout, argv[ 0 ] );
119 exit( 0 );
120 }
121 if ( 0 == strcmp( argv[ i ], "--version" ) ) {
122 print_version( stdout );
123 exit( 0 );
124 }
125 }
126
127 int opt;
128 while ( (opt = getopt( argc, argv, "#:cv" )) != -1 ) {
129 switch ( opt ) {
130 case '#':
131 // Ignore the original arguments to mosh wrapper
132 break;
133 case 'c':
134 print_colorcount();
135 exit( 0 );
136 break;
137 case 'v':
138 verbose++;
139 break;
140 default:
141 print_usage( stderr, argv[ 0 ] );
142 exit( 1 );
143 break;
144 }
145 }
146
147 char *ip, *desired_port;
148
149 if ( argc - optind != 2 ) {
150 print_usage( stderr, argv[ 0 ] );
151 exit( 1 );
152 }
153
154 ip = argv[ optind ];
155 desired_port = argv[ optind + 1 ];
156
157 /* Sanity-check arguments */
158 if ( desired_port
159 && ( strspn( desired_port, "0123456789" ) != strlen( desired_port ) ) ) {
160 fprintf( stderr, "%s: Bad UDP port (%s)\n\n", argv[ 0 ], desired_port );
161 print_usage( stderr, argv[ 0 ] );
162 exit( 1 );
163 }
164
165 /* Read key from environment */
166 char *env_key = getenv( "MOSH_KEY" );
167 if ( env_key == NULL ) {
168 fprintf( stderr, "MOSH_KEY environment variable not found.\n" );
169 exit( 1 );
170 }
171
172 /* Read prediction preference */
173 char *predict_mode = getenv( "MOSH_PREDICTION_DISPLAY" );
174 /* can be NULL */
175
176 char *key = strdup( env_key );
177 if ( key == NULL ) {
178 perror( "strdup" );
179 exit( 1 );
180 }
181
182 if ( unsetenv( "MOSH_KEY" ) < 0 ) {
183 perror( "unsetenv" );
184 exit( 1 );
185 }
186
187 /* Adopt native locale */
188 set_native_locale();
189
190 bool success = false;
191 try {
192 STMClient client( ip, desired_port, key, predict_mode, verbose );
193 client.init();
194
195 try {
196 success = client.main();
197 } catch ( ... ) {
198 client.shutdown();
199 throw;
200 }
201
202 client.shutdown();
203 } catch ( const Network::NetworkException &e ) {
204 fprintf( stderr, "Network exception: %s\r\n",
205 e.what() );
206 success = false;
207 } catch ( const Crypto::CryptoException &e ) {
208 fprintf( stderr, "Crypto exception: %s\r\n",
209 e.what() );
210 success = false;
211 } catch ( const std::exception &e ) {
212 fprintf( stderr, "Error: %s\r\n", e.what() );
213 success = false;
214 }
215
216 printf( "[mosh is exiting.]\n" );
217
218 free( key );
219
220 return !success;
221 }
222