SSH offers several methods of client authentication. These methods include the following:
- No authentication: This allows any user to connect
- Password authentication: This requires the user to provide a username and password
- Public key: This uses public key encryption methods to authenticate
- Keyboard-interactive: This authenticates by having the user answer several prompts
- Generic Security Service Application Program Interface (GSS-API): This allows authentication through a variety of other services
Password authentication is the most common method, but it does have some drawbacks. If an impostor server tricks a user into sending their password, then that user's password is effectively compromised. Public key user authentication doesn't suffer from this attack to the same degree. With public key authentication, the server issues a unique challenge for each authentication attempt. This prevents a malicious impostor server from replaying a previous authentication to the legitimate server.
Once public key authentication is set up, libssh makes using it very simple. In many cases, it's as easy as calling the ssh_userauth_publickey_auto() function. However, setting up public key authentication in the first place can be a tedious process.
Although public key authentication is more secure, password authentication is still in common use. Password authentication is also more straightforward and easier to test. For these reasons, we continue the examples in this chapter by using password authentication.
Regardless of the user authentication method, the SSH server must know what user you are trying to authenticate as. The libssh library lets us provide this information using the ssh_set_options() function that we saw earlier. It should be called before using ssh_connect(). To set the user, call ssh_options_set() with SSH_OPTIONS_USER as shown in the following code:
ssh_options_set(ssh, SSH_OPTIONS_USER, "alice");
After the SSH session has been established, a password can be provided with the ssh_userauth_password() function. The following code prompts for a password and sends it to the connected SSH server:
/*ssh_auth.c excerpt*/
printf("Password: ");
char password[128];
fgets(password, sizeof(password), stdin);
password[strlen(password)-1] = 0;
if (ssh_userauth_password(ssh, 0, password) != SSH_AUTH_SUCCESS) {
fprintf(stderr, "ssh_userauth_password() failed.\n%s\n",
ssh_get_error(ssh));
return 0;
} else {
printf("Authentication successful!\n");
}
The preceding code uses the fgets() function to obtain the password from the user. The fgets() function always includes the newline character with the input, which we don't want. The password[strlen(password)-1] = 0 code effectively shortens the password by one character, thus removing the newline character.
Note that using fgets() causes the entered password to display on the screen. This isn't secure, and it would be an improvement to hide the password while it's being entered. Unfortunately, there isn't a cross-platform way to do this. If you're using Linux, consider using the getpass() function in place of fgets().
See ssh_auth.c in this chapter's code repository for a working example of authenticating with a server using user password authentication.
You can compile and run ssh_auth.c with the following commands on Windows using MinGW:
gcc ssh_auth.c -o ssh_auth.exe -lssh
ssh_auth example.com 22 alice
On Linux and macOS, the commands to compile and run ssh_auth.c are as follows:
gcc ssh_auth.c -o ssh_auth -lssh
./ssh_auth example.com 22 alice
The following screenshot shows compiling ssh_auth and using it to connect to a locally running SSH server on Linux:
In the preceding screenshot, ssh_auth was used to successfully authenticate with the locally running SSH server. The ssh_auth program used password authentication with the username alice and the password password123. Needless to say, you need to change the username and password as appropriate for your SSH server. Authentication will be successful only if you use the username and password for an actual user account on the server you connect to.
After authenticating, we're ready to run a command over SSH.