Allow to generate and write a comment into ~/.ssh/authorized_keys
This commit is contained in:
parent
c5c1705cd7
commit
b8ae4a13fc
4 changed files with 109 additions and 17 deletions
|
@ -23,6 +23,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -719,7 +720,7 @@ azure_getovfenv(struct system_config *sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((xe = xml_findl(&xp->xe_head, "UserPassword", NULL)) != NULL) {
|
if ((xe = xml_findl(&xp->xe_head, "UserPassword", NULL)) != NULL) {
|
||||||
if ((sc->sc_password = calloc(1, 128)) == NULL) {
|
if ((sc->sc_password_hash = calloc(1, _PASSWORD_LEN)) == NULL) {
|
||||||
log_debug("%s: password failed", __func__);
|
log_debug("%s: password failed", __func__);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -727,13 +728,14 @@ azure_getovfenv(struct system_config *sc)
|
||||||
str = strndup(xe->xe_data, xe->xe_datalen);
|
str = strndup(xe->xe_data, xe->xe_datalen);
|
||||||
if (str == NULL ||
|
if (str == NULL ||
|
||||||
crypt_newhash(str, "bcrypt,a",
|
crypt_newhash(str, "bcrypt,a",
|
||||||
sc->sc_password, 128) != 0) {
|
sc->sc_password_hash, _PASSWORD_LEN) != 0) {
|
||||||
log_debug("%s: password hashing failed", __func__);
|
log_debug("%s: password hashing failed", __func__);
|
||||||
free(sc->sc_password);
|
free(sc->sc_password_hash);
|
||||||
sc->sc_password = NULL;
|
sc->sc_password_hash = NULL;
|
||||||
free(str);
|
free(str);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
explicit_bzero(str, xe->xe_datalen);
|
||||||
free(str);
|
free(str);
|
||||||
|
|
||||||
/* Replace unencrypted password with hash */
|
/* Replace unencrypted password with hash */
|
||||||
|
@ -743,11 +745,11 @@ azure_getovfenv(struct system_config *sc)
|
||||||
/* Update element for xml_print() below */
|
/* Update element for xml_print() below */
|
||||||
explicit_bzero(xe->xe_data, xe->xe_datalen);
|
explicit_bzero(xe->xe_data, xe->xe_datalen);
|
||||||
free(xe->xe_data);
|
free(xe->xe_data);
|
||||||
xe->xe_data = strdup(sc->sc_password);
|
xe->xe_data = strdup(sc->sc_password_hash);
|
||||||
xe->xe_datalen = strlen(sc->sc_password);
|
xe->xe_datalen = strlen(sc->sc_password_hash);
|
||||||
} else if ((xe = xml_findl(&xp->xe_head,
|
} else if ((xe = xml_findl(&xp->xe_head,
|
||||||
"UserPasswordHash", NULL)) != NULL) {
|
"UserPasswordHash", NULL)) != NULL) {
|
||||||
if ((sc->sc_password =
|
if ((sc->sc_password_hash =
|
||||||
get_word(xe->xe_data, xe->xe_datalen)) != NULL) {
|
get_word(xe->xe_data, xe->xe_datalen)) != NULL) {
|
||||||
log_debug("%s: password hash failed", __func__);
|
log_debug("%s: password hash failed", __func__);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm cloud-agent
|
.Nm cloud-agent
|
||||||
.Op Fl nuv
|
.Op Fl nuv
|
||||||
|
.Op Fl p Ar length
|
||||||
.Op Fl r Ar rootdisk
|
.Op Fl r Ar rootdisk
|
||||||
.Op Fl t Ar timeout
|
.Op Fl t Ar timeout
|
||||||
.Op Fl U Ar username
|
.Op Fl U Ar username
|
||||||
|
@ -35,6 +36,17 @@ environments, including Microsoft Azure and Amazon AWS.
|
||||||
.Pp
|
.Pp
|
||||||
The options are as follows:
|
The options are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
|
.It Fl p Ar length
|
||||||
|
Generate and set a random password for the default user.
|
||||||
|
The password will be written in its plain form into the
|
||||||
|
.Pa ~/.ssh/authorized_keys
|
||||||
|
file.
|
||||||
|
This allows to use the
|
||||||
|
.Xr doas 1
|
||||||
|
command to gain root privileges.
|
||||||
|
The minimum
|
||||||
|
.Ar length
|
||||||
|
is 8 characters and the default is an empty password.
|
||||||
.It Fl n
|
.It Fl n
|
||||||
Do not configure the system and skip the provisioning step.
|
Do not configure the system and skip the provisioning step.
|
||||||
.It Fl t Ar timeout
|
.It Fl t Ar timeout
|
||||||
|
@ -78,6 +90,8 @@ dhcp
|
||||||
.Ed
|
.Ed
|
||||||
.Sh FILES
|
.Sh FILES
|
||||||
.Bl -tag -width "/usr/local/libexec/cloud-agentX" -compact
|
.Bl -tag -width "/usr/local/libexec/cloud-agentX" -compact
|
||||||
|
.It Pa ~/.ssh/authorized_keys
|
||||||
|
The location of the agent-configured SSH public keys and optional password.
|
||||||
.It Pa /usr/local/libexec/cloud-agent
|
.It Pa /usr/local/libexec/cloud-agent
|
||||||
The agent itself.
|
The agent itself.
|
||||||
.It Pa /usr/local/bin/cms
|
.It Pa /usr/local/bin/cms
|
||||||
|
|
93
agent/main.c
93
agent/main.c
|
@ -37,6 +37,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
#include <pwd.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
@ -360,13 +361,19 @@ agent_free(struct system_config *sc)
|
||||||
log_debug("%s: unmounted %s", __func__, sc->sc_cdrom);
|
log_debug("%s: unmounted %s", __func__, sc->sc_cdrom);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(sc->sc_args);
|
if (sc->sc_password_plain != NULL) {
|
||||||
|
/* XXX can be removed with calloc_conceal() post-6.6 */
|
||||||
|
explicit_bzero(sc->sc_password_plain,
|
||||||
|
strlen(sc->sc_password_plain));
|
||||||
|
free(sc->sc_password_plain);
|
||||||
|
}
|
||||||
|
free(sc->sc_password_hash);
|
||||||
free(sc->sc_hostname);
|
free(sc->sc_hostname);
|
||||||
free(sc->sc_username);
|
free(sc->sc_username);
|
||||||
free(sc->sc_password);
|
|
||||||
free(sc->sc_userdata);
|
free(sc->sc_userdata);
|
||||||
free(sc->sc_endpoint);
|
free(sc->sc_endpoint);
|
||||||
free(sc->sc_instance);
|
free(sc->sc_instance);
|
||||||
|
free(sc->sc_args);
|
||||||
close(sc->sc_nullfd);
|
close(sc->sc_nullfd);
|
||||||
|
|
||||||
while ((ssh = TAILQ_FIRST(&sc->sc_pubkeys))) {
|
while ((ssh = TAILQ_FIRST(&sc->sc_pubkeys))) {
|
||||||
|
@ -628,6 +635,7 @@ agent_pf(struct system_config *sc, int open)
|
||||||
static int
|
static int
|
||||||
agent_configure(struct system_config *sc)
|
agent_configure(struct system_config *sc)
|
||||||
{
|
{
|
||||||
|
char pwbuf[_PASSWORD_LEN + 2];
|
||||||
struct ssh_pubkey *ssh;
|
struct ssh_pubkey *ssh;
|
||||||
char *str1, *str2;
|
char *str1, *str2;
|
||||||
|
|
||||||
|
@ -669,18 +677,30 @@ agent_configure(struct system_config *sc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* password */
|
/* password */
|
||||||
if (sc->sc_password == NULL) {
|
if (sc->sc_password_hash == NULL) {
|
||||||
if (asprintf(&str2, "permit keepenv nopass %s as root\n"
|
if (asprintf(&str2, "permit keepenv nopass %s as root\n"
|
||||||
"permit keepenv nopass root\n", sc->sc_username) == -1)
|
"permit keepenv nopass root\n", sc->sc_username) == -1)
|
||||||
str2 = NULL;
|
str2 = NULL;
|
||||||
} else {
|
} else {
|
||||||
if (shell("usermod", "-p", sc->sc_password,
|
if (shell("usermod", "-p", sc->sc_password_hash,
|
||||||
sc->sc_username, NULL) != 0)
|
sc->sc_username, NULL) != 0)
|
||||||
log_warnx("password failed");
|
log_warnx("password failed");
|
||||||
|
|
||||||
if (asprintf(&str2, "permit keepenv persist %s as root\n"
|
if (asprintf(&str2, "permit keepenv persist %s as root\n"
|
||||||
"permit keepenv nopass root\n", sc->sc_username) == -1)
|
"permit keepenv nopass root\n", sc->sc_username) == -1)
|
||||||
str2 = NULL;
|
str2 = NULL;
|
||||||
|
|
||||||
|
/* write generated password as comment to authorized_keys */
|
||||||
|
if (sc->sc_password_plain != NULL) {
|
||||||
|
snprintf(pwbuf, sizeof(pwbuf), "# %s",
|
||||||
|
sc->sc_password_plain);
|
||||||
|
if (fileout(pwbuf, "w",
|
||||||
|
"%s/%s/.ssh/authorized_keys",
|
||||||
|
strcmp("root", sc->sc_username) == 0 ? "" : "/home",
|
||||||
|
sc->sc_username) != 0)
|
||||||
|
log_warnx("password comment failed");
|
||||||
|
explicit_bzero(pwbuf, sizeof(pwbuf));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* doas */
|
/* doas */
|
||||||
|
@ -690,7 +710,7 @@ agent_configure(struct system_config *sc)
|
||||||
free(str2);
|
free(str2);
|
||||||
|
|
||||||
/* ssh configuration */
|
/* ssh configuration */
|
||||||
if (sc->sc_password == NULL && !TAILQ_EMPTY(&sc->sc_pubkeys))
|
if (sc->sc_password_hash == NULL && !TAILQ_EMPTY(&sc->sc_pubkeys))
|
||||||
str1 = "/PasswordAuthentication/"
|
str1 = "/PasswordAuthentication/"
|
||||||
"s/.*/PasswordAuthentication no/";
|
"s/.*/PasswordAuthentication no/";
|
||||||
else
|
else
|
||||||
|
@ -1096,8 +1116,8 @@ usage(void)
|
||||||
{
|
{
|
||||||
extern char *__progname;
|
extern char *__progname;
|
||||||
|
|
||||||
fprintf(stderr, "usage: %s [-nuv] [-r rootdisk] [-t 3] [-U puffy] "
|
fprintf(stderr, "usage: %s [-nuv] [-p length] [-r rootdisk] "
|
||||||
"interface\n", __progname);
|
"[-t 3] [-U puffy] interface\n", __progname);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1131,23 +1151,65 @@ get_args(int argc, char *const *argv)
|
||||||
return (args);
|
return (args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
pwgen(size_t len, char **hash)
|
||||||
|
{
|
||||||
|
char *password;
|
||||||
|
size_t i, alphabet_len;
|
||||||
|
const char *alphabet =
|
||||||
|
"0123456789_"
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
alphabet_len = strlen(alphabet);
|
||||||
|
*hash = NULL;
|
||||||
|
|
||||||
|
/* XXX use calloc_conceal() post-6.6 */
|
||||||
|
if ((password = calloc(1, len + 1)) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
/* Simple password generator */
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
password[i] = alphabet[arc4random_uniform(alphabet_len)];
|
||||||
|
|
||||||
|
if ((*hash = calloc(1, _PASSWORD_LEN)) == NULL) {
|
||||||
|
freezero(password, len + 1);
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypt_newhash(password, "bcrypt,a",
|
||||||
|
*hash, _PASSWORD_LEN) != 0) {
|
||||||
|
freezero(password, len + 1);
|
||||||
|
freezero(*hash, _PASSWORD_LEN);
|
||||||
|
password = NULL;
|
||||||
|
*hash = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (password);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *const *argv)
|
main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
struct system_config *sc;
|
struct system_config *sc;
|
||||||
int verbose = 0, dryrun = 0, unconfigure = 0;
|
int verbose = 0, dryrun = 0, unconfigure = 0;
|
||||||
int ch, ret, timeout = CONNECT_TIMEOUT;
|
int genpw = 0, ch, ret, timeout = CONNECT_TIMEOUT;
|
||||||
const char *error = NULL, *rootdisk = NULL;
|
const char *error = NULL, *rootdisk = NULL;
|
||||||
char *args, *username = NULL;
|
char *args, *username = NULL;
|
||||||
|
|
||||||
if ((args = get_args(argc, argv)) == NULL)
|
if ((args = get_args(argc, argv)) == NULL)
|
||||||
fatalx("failed to save args");
|
fatalx("failed to save args");
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "nr:t:U:uv")) != -1) {
|
while ((ch = getopt(argc, argv, "np:r:t:U:uv")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'n':
|
case 'n':
|
||||||
dryrun = 1;
|
dryrun = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
genpw = strtonum(optarg, 8, 8192, &error);
|
||||||
|
if (error != NULL)
|
||||||
|
fatalx("invalid password length: %s", error);
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
rootdisk = optarg;
|
rootdisk = optarg;
|
||||||
break;
|
break;
|
||||||
|
@ -1217,6 +1279,19 @@ main(int argc, char *const *argv)
|
||||||
else
|
else
|
||||||
ret = openstack(sc);
|
ret = openstack(sc);
|
||||||
|
|
||||||
|
if (genpw) {
|
||||||
|
if (sc->sc_password_hash != NULL)
|
||||||
|
log_debug("%s: user password hash: %s", __func__,
|
||||||
|
sc->sc_password_hash);
|
||||||
|
else if ((sc->sc_password_plain = pwgen(genpw,
|
||||||
|
&sc->sc_password_hash)) != NULL) {
|
||||||
|
if (log_getverbose() > 2)
|
||||||
|
log_debug("%s: generated password: %s",
|
||||||
|
__func__, sc->sc_password_plain);
|
||||||
|
} else
|
||||||
|
log_warnx("failed to generate password");
|
||||||
|
}
|
||||||
|
|
||||||
/* Debug userdata */
|
/* Debug userdata */
|
||||||
if (sc->sc_dryrun && sc->sc_userdata) {
|
if (sc->sc_dryrun && sc->sc_userdata) {
|
||||||
if (agent_userdata(sc, sc->sc_userdata,
|
if (agent_userdata(sc, sc->sc_userdata,
|
||||||
|
|
|
@ -72,7 +72,8 @@ struct system_config {
|
||||||
|
|
||||||
char *sc_hostname;
|
char *sc_hostname;
|
||||||
char *sc_username;
|
char *sc_username;
|
||||||
char *sc_password;
|
char *sc_password_plain;
|
||||||
|
char *sc_password_hash;
|
||||||
char *sc_pubkey;
|
char *sc_pubkey;
|
||||||
char *sc_userdata;
|
char *sc_userdata;
|
||||||
char *sc_endpoint;
|
char *sc_endpoint;
|
||||||
|
|
Loading…
Reference in a new issue