comparison cli-runopts.c @ 389:5ff8218bcee9

propagate from branch 'au.asn.ucc.matt.ltm.dropbear' (head 2af95f00ebd5bb7a28b3817db1218442c935388e) to branch 'au.asn.ucc.matt.dropbear' (head ecd779509ef23a8cdf64888904fc9b31d78aa933)
author Matt Johnston <matt@ucc.asn.au>
date Thu, 11 Jan 2007 03:14:55 +0000
parents 9341570412e5
children b895f91c2ee6
comparison
equal deleted inserted replaced
388:fb54020f78e1 389:5ff8218bcee9
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE. */
24
25 #include "includes.h"
26 #include "runopts.h"
27 #include "signkey.h"
28 #include "buffer.h"
29 #include "dbutil.h"
30 #include "algo.h"
31 #include "tcpfwd.h"
32
33 cli_runopts cli_opts; /* GLOBAL */
34
35 static void printhelp();
36 static void parsehostname(char* userhostarg);
37 #ifdef ENABLE_CLI_PUBKEY_AUTH
38 static void loadidentityfile(const char* filename);
39 #endif
40 #ifdef ENABLE_CLI_ANYTCPFWD
41 static void addforward(char* str, struct TCPFwdList** fwdlist);
42 #endif
43
44 static void printhelp() {
45
46 fprintf(stderr, "Dropbear client v%s\n"
47 "Usage: %s [options] [user@]host [command]\n"
48 "Options are:\n"
49 "-p <remoteport>\n"
50 "-l <username>\n"
51 "-t Allocate a pty\n"
52 "-T Don't allocate a pty\n"
53 "-N Don't run a remote command\n"
54 "-f Run in background after auth\n"
55 #ifdef ENABLE_CLI_PUBKEY_AUTH
56 "-i <identityfile> (multiple allowed)\n"
57 #endif
58 #ifdef ENABLE_CLI_LOCALTCPFWD
59 "-L <listenport:remotehost:remoteport> Local port forwarding\n"
60 "-g Allow remote hosts to connect to forwarded ports\n"
61 #endif
62 #ifdef ENABLE_CLI_REMOTETCPFWD
63 "-R <listenport:remotehost:remoteport> Remote port forwarding\n"
64 #endif
65 #ifdef DEBUG_TRACE
66 "-v verbose\n"
67 #endif
68 ,DROPBEAR_VERSION, cli_opts.progname);
69 }
70
71 void cli_getopts(int argc, char ** argv) {
72
73 unsigned int i, j;
74 char ** next = 0;
75 unsigned int cmdlen;
76 #ifdef ENABLE_CLI_PUBKEY_AUTH
77 int nextiskey = 0; /* A flag if the next argument is a keyfile */
78 #endif
79 #ifdef ENABLE_CLI_LOCALTCPFWD
80 int nextislocal = 0;
81 #endif
82 #ifdef ENABLE_CLI_REMOTETCPFWD
83 int nextisremote = 0;
84 #endif
85 char* dummy = NULL; /* Not used for anything real */
86
87 /* see printhelp() for options */
88 cli_opts.progname = argv[0];
89 cli_opts.remotehost = NULL;
90 cli_opts.remoteport = NULL;
91 cli_opts.username = NULL;
92 cli_opts.cmd = NULL;
93 cli_opts.no_cmd = 0;
94 cli_opts.backgrounded = 0;
95 cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */
96 #ifdef ENABLE_CLI_PUBKEY_AUTH
97 cli_opts.privkeys = NULL;
98 #endif
99 #ifdef ENABLE_CLI_LOCALTCPFWD
100 cli_opts.localfwds = NULL;
101 opts.listen_fwd_all = 0;
102 #endif
103 #ifdef ENABLE_CLI_REMOTETCPFWD
104 cli_opts.remotefwds = NULL;
105 #endif
106 /* not yet
107 opts.ipv4 = 1;
108 opts.ipv6 = 1;
109 */
110
111 /* Iterate all the arguments */
112 for (i = 1; i < (unsigned int)argc; i++) {
113 #ifdef ENABLE_CLI_PUBKEY_AUTH
114 if (nextiskey) {
115 /* Load a hostkey since the previous argument was "-i" */
116 loadidentityfile(argv[i]);
117 nextiskey = 0;
118 continue;
119 }
120 #endif
121 #ifdef ENABLE_CLI_REMOTETCPFWD
122 if (nextisremote) {
123 TRACE(("nextisremote true"))
124 addforward(argv[i], &cli_opts.remotefwds);
125 nextisremote = 0;
126 continue;
127 }
128 #endif
129 #ifdef ENABLE_CLI_LOCALTCPFWD
130 if (nextislocal) {
131 TRACE(("nextislocal true"))
132 addforward(argv[i], &cli_opts.localfwds);
133 nextislocal = 0;
134 continue;
135 }
136 #endif
137 if (next) {
138 /* The previous flag set a value to assign */
139 *next = argv[i];
140 if (*next == NULL) {
141 dropbear_exit("Invalid null argument");
142 }
143 next = NULL;
144 continue;
145 }
146
147 if (argv[i][0] == '-') {
148 /* A flag *waves* */
149
150 switch (argv[i][1]) {
151 case 'p': /* remoteport */
152 next = &cli_opts.remoteport;
153 break;
154 #ifdef ENABLE_CLI_PUBKEY_AUTH
155 case 'i': /* an identityfile */
156 /* Keep scp happy when it changes "-i file" to "-ifile" */
157 if (strlen(argv[i]) > 2) {
158 loadidentityfile(&argv[i][2]);
159 } else {
160 nextiskey = 1;
161 }
162 break;
163 #endif
164 case 't': /* we want a pty */
165 cli_opts.wantpty = 1;
166 break;
167 case 'T': /* don't want a pty */
168 cli_opts.wantpty = 0;
169 break;
170 case 'N':
171 cli_opts.no_cmd = 1;
172 break;
173 case 'f':
174 cli_opts.backgrounded = 1;
175 break;
176 #ifdef ENABLE_CLI_LOCALTCPFWD
177 case 'L':
178 nextislocal = 1;
179 break;
180 case 'g':
181 opts.listen_fwd_all = 1;
182 break;
183 #endif
184 #ifdef ENABLE_CLI_REMOTETCPFWD
185 case 'R':
186 nextisremote = 1;
187 break;
188 #endif
189 case 'l':
190 next = &cli_opts.username;
191 break;
192 case 'h':
193 printhelp();
194 exit(EXIT_SUCCESS);
195 break;
196 #ifdef DEBUG_TRACE
197 case 'v':
198 debug_trace = 1;
199 break;
200 #endif
201 case 'F':
202 case 'e':
203 case 'c':
204 case 'm':
205 case 'D':
206 #ifndef ENABLE_CLI_REMOTETCPFWD
207 case 'R':
208 #endif
209 #ifndef ENABLE_CLI_LOCALTCPFWD
210 case 'L':
211 #endif
212 case 'o':
213 case 'b':
214 next = &dummy;
215 default:
216 fprintf(stderr,
217 "WARNING: Ignoring unknown argument '%s'\n", argv[i]);
218 break;
219 } /* Switch */
220
221 /* Now we handle args where they might be "-luser" (no spaces)*/
222 if (next && strlen(argv[i]) > 2) {
223 *next = &argv[i][2];
224 next = NULL;
225 }
226
227 continue; /* next argument */
228
229 } else {
230 TRACE(("non-flag arg: '%s'", argv[i]))
231
232 /* Either the hostname or commands */
233
234 if (cli_opts.remotehost == NULL) {
235
236 parsehostname(argv[i]);
237
238 } else {
239
240 /* this is part of the commands to send - after this we
241 * don't parse any more options, and flags are sent as the
242 * command */
243 cmdlen = 0;
244 for (j = i; j < (unsigned int)argc; j++) {
245 cmdlen += strlen(argv[j]) + 1; /* +1 for spaces */
246 }
247 /* Allocate the space */
248 cli_opts.cmd = (char*)m_malloc(cmdlen);
249 cli_opts.cmd[0] = '\0';
250
251 /* Append all the bits */
252 for (j = i; j < (unsigned int)argc; j++) {
253 strlcat(cli_opts.cmd, argv[j], cmdlen);
254 strlcat(cli_opts.cmd, " ", cmdlen);
255 }
256 /* It'll be null-terminated here */
257
258 /* We've eaten all the options and flags */
259 break;
260 }
261 }
262 }
263
264 if (cli_opts.remotehost == NULL) {
265 printhelp();
266 exit(EXIT_FAILURE);
267 }
268
269 if (cli_opts.remoteport == NULL) {
270 cli_opts.remoteport = "22";
271 }
272
273 /* If not explicitly specified with -t or -T, we don't want a pty if
274 * there's a command, but we do otherwise */
275 if (cli_opts.wantpty == 9) {
276 if (cli_opts.cmd == NULL) {
277 cli_opts.wantpty = 1;
278 } else {
279 cli_opts.wantpty = 0;
280 }
281 }
282
283 if (cli_opts.backgrounded && cli_opts.cmd == NULL
284 && cli_opts.no_cmd == 0) {
285 dropbear_exit("command required for -f");
286 }
287 }
288
289 #ifdef ENABLE_CLI_PUBKEY_AUTH
290 static void loadidentityfile(const char* filename) {
291
292 struct SignKeyList * nextkey;
293 sign_key *key;
294 int keytype;
295
296 key = new_sign_key();
297 keytype = DROPBEAR_SIGNKEY_ANY;
298 if ( readhostkey(filename, key, &keytype) != DROPBEAR_SUCCESS ) {
299
300 fprintf(stderr, "Failed loading keyfile '%s'\n", filename);
301 sign_key_free(key);
302
303 } else {
304
305 nextkey = (struct SignKeyList*)m_malloc(sizeof(struct SignKeyList));
306 nextkey->key = key;
307 nextkey->next = cli_opts.privkeys;
308 nextkey->type = keytype;
309 cli_opts.privkeys = nextkey;
310 }
311 }
312 #endif
313
314
315 /* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding
316 * - note that it will be modified */
317 static void parsehostname(char* orighostarg) {
318
319 uid_t uid;
320 struct passwd *pw = NULL;
321 char *userhostarg = NULL;
322
323 /* We probably don't want to be editing argvs */
324 userhostarg = m_strdup(orighostarg);
325
326 cli_opts.remotehost = strchr(userhostarg, '@');
327 if (cli_opts.remotehost == NULL) {
328 /* no username portion, the cli-auth.c code can figure the
329 * local user's name */
330 cli_opts.remotehost = userhostarg;
331 } else {
332 cli_opts.remotehost[0] = '\0'; /* Split the user/host */
333 cli_opts.remotehost++;
334 cli_opts.username = userhostarg;
335 }
336
337 if (cli_opts.username == NULL) {
338 uid = getuid();
339
340 pw = getpwuid(uid);
341 if (pw == NULL || pw->pw_name == NULL) {
342 dropbear_exit("Unknown own user");
343 }
344
345 cli_opts.username = m_strdup(pw->pw_name);
346 }
347
348 if (cli_opts.remotehost[0] == '\0') {
349 dropbear_exit("Bad hostname");
350 }
351 }
352
353 #ifdef ENABLE_CLI_ANYTCPFWD
354 /* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
355 * set, and add it to the forwarding list */
356 static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
357
358 char * listenport = NULL;
359 char * connectport = NULL;
360 char * connectaddr = NULL;
361 struct TCPFwdList* newfwd = NULL;
362 char * str = NULL;
363
364 TRACE(("enter addforward"))
365
366 /* We probably don't want to be editing argvs */
367 str = m_strdup(origstr);
368
369 listenport = str;
370
371 connectaddr = strchr(str, ':');
372 if (connectaddr == NULL) {
373 TRACE(("connectaddr == NULL"))
374 goto fail;
375 }
376
377 connectaddr[0] = '\0';
378 connectaddr++;
379
380 connectport = strchr(connectaddr, ':');
381 if (connectport == NULL) {
382 TRACE(("connectport == NULL"))
383 goto fail;
384 }
385
386 connectport[0] = '\0';
387 connectport++;
388
389 newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
390
391 /* Now we check the ports - note that the port ints are unsigned,
392 * the check later only checks for >= MAX_PORT */
393 newfwd->listenport = strtol(listenport, NULL, 10);
394 if (errno != 0) {
395 TRACE(("bad listenport strtol"))
396 goto fail;
397 }
398
399 newfwd->connectport = strtol(connectport, NULL, 10);
400 if (errno != 0) {
401 TRACE(("bad connectport strtol"))
402 goto fail;
403 }
404
405 newfwd->connectaddr = connectaddr;
406
407 if (newfwd->listenport > 65535) {
408 TRACE(("listenport > 65535"))
409 goto badport;
410 }
411
412 if (newfwd->connectport > 65535) {
413 TRACE(("connectport > 65535"))
414 goto badport;
415 }
416
417 newfwd->next = *fwdlist;
418 *fwdlist = newfwd;
419
420 TRACE(("leave addforward: done"))
421 return;
422
423 fail:
424 dropbear_exit("Bad TCP forward '%s'", origstr);
425
426 badport:
427 dropbear_exit("Bad TCP port in '%s'", origstr);
428 }
429 #endif