2 * Copyright (C) 2014 Red Hat Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 /* There is a program called 'sshpass' which does roughly the same
20 * as this simplified example. We run ssh as a subprocess, and log
21 * in using the given password from the command line.
23 * The first argument is the password to send at the password prompt.
24 * The remaining arguments are passed to the ssh subprocess.
27 * sshpass [-d] 123456 ssh remote.example.com
28 * sshpass [-d] 123456 ssh -l root remote.example.com
30 * Use the -d flag to enable debugging to stderr.
43 #include "miniexpect.h"
45 static pcre *compile_re (const char *rex);
50 fprintf (stderr, "usage: sshpass [-d] PASSWORD ssh [SSH-ARGS...] HOST\n");
55 main (int argc, char *argv[])
62 pcre *password_re, *prompt_re, *hello_re;
63 const int ovecsize = 12;
64 int ovector[ovecsize];
66 while ((opt = getopt (argc, argv, "d")) != -1) {
79 password = argv[optind];
82 printf ("starting ssh command ...\n");
84 h = mexp_spawnv (argv[optind], &argv[optind]);
86 perror ("mexp_spawnv: ssh");
90 mexp_set_debug_file (h, stderr);
92 /* Wait for the password prompt. */
93 password_re = compile_re ("assword");
94 switch (mexp_expect (h,
96 { 100, .re = password_re },
103 fprintf (stderr, "error: ssh closed the connection unexpectedly\n");
106 fprintf (stderr, "error: timeout before reaching the password prompt\n");
109 perror ("mexp_expect");
111 case MEXP_PCRE_ERROR:
112 fprintf (stderr, "error: PCRE error: %d\n", mexp_get_pcre_error (h));
116 /* Got the password prompt, so send a password.
118 * Note use of mexp_printf_password here which is identical to
119 * mexp_printf except that it hides the password in debugging
122 printf ("sending the password ...\n");
124 if (mexp_printf_password (h, "%s", password) == -1 ||
125 mexp_printf (h, "\n") == -1) {
126 perror ("mexp_printf");
130 /* We have to wait for the prompt before we can send commands
131 * (because the ssh connection may not be fully established). If we
132 * get "password" again, then probably the password was wrong. This
133 * expect checks all these possibilities. Unfortunately since all
134 * prompts are a little bit different, we have to guess here.
136 prompt_re = compile_re ("[#$]");
137 switch (mexp_expect (h,
139 { 100, .re = password_re },
140 { 101, .re = prompt_re },
143 ovector, ovecsize)) {
144 case 100: /* Password. */
145 fprintf (stderr, "error: ssh asked for password again, probably the password supplied is wrong\n");
147 case 101: /* Prompt. */
150 fprintf (stderr, "error: ssh closed the connection unexpectedly\n");
153 fprintf (stderr, "error: timeout before reaching the prompt\n");
156 perror ("mexp_expect");
158 case MEXP_PCRE_ERROR:
159 fprintf (stderr, "error: PCRE error: %d\n", mexp_get_pcre_error (h));
163 /* Send a command which will have expected output. */
164 printf ("sending a test command ...\n");
166 if (mexp_printf (h, "echo h''ello\n") == -1) {
167 perror ("mexp_printf");
171 /* Wait for expected output from echo hello command. */
172 hello_re = compile_re ("hello");
173 switch (mexp_expect (h,
175 { 100, .re = hello_re },
178 ovector, ovecsize)) {
182 fprintf (stderr, "error: ssh closed the connection unexpectedly\n");
185 fprintf (stderr, "error: timeout before reading command output\n");
188 perror ("mexp_expect");
190 case MEXP_PCRE_ERROR:
191 fprintf (stderr, "error: PCRE error: %d\n", mexp_get_pcre_error (h));
195 /* Send exit command and wait for ssh to exit. */
196 printf ("sending the exit command ...\n");
198 if (mexp_printf (h, "exit\n") == -1) {
199 perror ("mexp_printf");
203 switch (mexp_expect (h, NULL, NULL, 0)) {
205 /* This is what we're expecting: ssh will close the connection. */
208 fprintf (stderr, "error: timeout before ssh closed the connection\n");
211 perror ("mexp_expect");
213 case MEXP_PCRE_ERROR:
214 fprintf (stderr, "error: unexpected return value from mexp_expect\n");
218 /* Close the ssh connection. */
219 status = mexp_close (h);
221 fprintf (stderr, "error: bad exit status from ssh subprocess (status=%d)\n",
226 printf ("test was successful\n");
235 /* Helper function to compile a PCRE regexp. */
237 compile_re (const char *rex)
243 ret = pcre_compile (rex, 0, &errptr, &erroffset, NULL);
245 fprintf (stderr, "error: failed to compile regular expression '%s': %s at offset %d\n",
246 rex, errptr, erroffset);