Compare commits
No commits in common. "master" and "v0.1-alpha" have entirely different histories.
master
...
v0.1-alpha
22 changed files with 256 additions and 2668 deletions
69
CHANGELOG.md
69
CHANGELOG.md
|
|
@ -1,69 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
## v1.0 (2019-11-29)
|
|
||||||
|
|
||||||
* Append `/etc/resolv.conf.tail` to `/etc/resolv.conf` if it exists.
|
|
||||||
* Fixed usage.
|
|
||||||
|
|
||||||
## v0.9 (2019-06-26)
|
|
||||||
|
|
||||||
* Added support for `-c` to specify the probing order of different cloud stacks.
|
|
||||||
* Added support for OpenNebula's START_SCRIPT methods (user-data alike).
|
|
||||||
* Added support for OpenNebula's USERNAME method.
|
|
||||||
* Added support for generating a default user password and writing it into
|
|
||||||
`~/.ssh/authorized_keys`.
|
|
||||||
* Fixed handling of OpenNebula SSH_PUBLIC_KEY entries with multiple keys.
|
|
||||||
* Improved documentation, added `CHANGELOG.md` file.
|
|
||||||
|
|
||||||
## v0.8 (2019-06-02)
|
|
||||||
|
|
||||||
* Added support for growing the root disk and its last partition (optional).
|
|
||||||
* Fixed OpenStack support.
|
|
||||||
* Fixed compilation with LibreSSL on OpenBSD 6.5 or newer.
|
|
||||||
* Fixed probing order and OpenStack with `169.254.169.254` as the endpoint IP.
|
|
||||||
* Improved OpenNebula support.
|
|
||||||
|
|
||||||
## v0.7 (2018-08-15)
|
|
||||||
|
|
||||||
* Added initial support for OpenNebula contextualization.
|
|
||||||
* Added support for setting a custom login user or "root" with `-U`.
|
|
||||||
* Added support for writing `resolv.conf` and static network configuration.
|
|
||||||
* Fixed the generated pf rule that is loaded during cloud-agent operation.
|
|
||||||
|
|
||||||
## v0.6 (2018-05-15)
|
|
||||||
|
|
||||||
* Fixed compilation with (old) OpenSSL releases.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## v0.5 (2018-05-08)
|
|
||||||
|
|
||||||
* Fixed the user-data script by loading it from /etc/rc.user-data.
|
|
||||||
|
|
||||||
## v0.4 (2018-05-08)
|
|
||||||
|
|
||||||
* Added support for user-data that is not base64-encoded.
|
|
||||||
|
|
||||||
## v0.3 (2018-05-08)
|
|
||||||
|
|
||||||
* Added support for user-data scripts.
|
|
||||||
* Make the public key optional for stacks that supply a password (e.g. Azure).
|
|
||||||
|
|
||||||
## v0.2.2 (2018-05-07)
|
|
||||||
|
|
||||||
* Fixed issues in the v0.2.1 release.
|
|
||||||
|
|
||||||
## v0.2.2 (2018-05-07)
|
|
||||||
|
|
||||||
* Fixed issues in the v0.2 release.
|
|
||||||
|
|
||||||
## v0.2 (2018-01-10)
|
|
||||||
|
|
||||||
* Added support for OpenStack and its JSON-based meta data.
|
|
||||||
* Added support for Apache CloudStack.
|
|
||||||
* Try to get meta data from `dhcp-server-identifier` instead of
|
|
||||||
`169.254.169.254`.
|
|
||||||
|
|
||||||
## v0.1 (2017-07-03)
|
|
||||||
|
|
||||||
* Initial release with support for Microsoft Azure and Amazon AWS EC2.
|
|
||||||
|
|
@ -6,10 +6,10 @@ License
|
||||||
|
|
||||||
* `cloud-agent` is free software under OpenBSD's ISC-style license.
|
* `cloud-agent` is free software under OpenBSD's ISC-style license.
|
||||||
* Most of the code has been written by Reyk Floeter <reyk@openbsd.org>
|
* Most of the code has been written by Reyk Floeter <reyk@openbsd.org>
|
||||||
* The {http,json}.[ch] files were written by Kristaps Dzonsons <kristaps@bsd.lv>
|
* The http.[ch] files have been written by Kristaps Dzonsons <kristaps@bsd.lv>
|
||||||
* Please refer to the individual source files for other copyright holders!
|
* Please refer to the individual source files for other copyright holders!
|
||||||
|
|
||||||
> Copyright (c) 2017, 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
> Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
|
||||||
>
|
>
|
||||||
> Permission to use, copy, modify, and distribute this software for any
|
> Permission to use, copy, modify, and distribute this software for any
|
||||||
> purpose with or without fee is hereby granted, provided that the above
|
> purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
@ -26,5 +26,5 @@ License
|
||||||
`cms/`
|
`cms/`
|
||||||
------
|
------
|
||||||
|
|
||||||
* The CMS code is from OpenSSL and/or LibreSSL.
|
* The CMS code is from the OpenSSL and/or LibreSSL.
|
||||||
* Please refer to the individual source files for other copyright holders!
|
* Please refer to the individual source files for other copyright holders!
|
||||||
|
|
|
||||||
5
Makefile
5
Makefile
|
|
@ -1,13 +1,10 @@
|
||||||
#
|
#
|
||||||
# The Azure agents needs CMS to obtain the SSH public keys.
|
# The Azure agents needs CMS to obtain the SSH public keys.
|
||||||
# LibreSSL has removed CMS, so either use OpenSSL to decrypt CMS
|
# LibreSSL has removed CMS, so either use OpenSSL to decrypt CMS
|
||||||
# messages or compile the old CMS code for LibreSSL. Or use
|
# messages or compile the old CMS code for LibreSSL.
|
||||||
# CMS that has returned to newer versions of LibreSSL.
|
|
||||||
#
|
#
|
||||||
.ifdef USE_OPENSSL
|
.ifdef USE_OPENSSL
|
||||||
MAKE_FLAGS+= USE_OPENSSL=1
|
MAKE_FLAGS+= USE_OPENSSL=1
|
||||||
.elifdef USE_LIBRESSL_CMS
|
|
||||||
MAKE_FLAGS+= USE_LIBRESSL_CMS=1
|
|
||||||
.else
|
.else
|
||||||
SUBDIR= cms
|
SUBDIR= cms
|
||||||
.endif
|
.endif
|
||||||
|
|
|
||||||
27
README.md
27
README.md
|
|
@ -1,6 +1,8 @@
|
||||||
cloud-agent for OpenBSD
|
cloud-agent for OpenBSD
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
**This is just experimental. Be warned.**
|
||||||
|
|
||||||
This is a simple OpenBSD-specific agent that aims to handle
|
This is a simple OpenBSD-specific agent that aims to handle
|
||||||
provisioning and cloud initialization on public clouds such as
|
provisioning and cloud initialization on public clouds such as
|
||||||
Microsoft Azure and Amazon AWS. For OpenBSD on Azure, it is a minimal
|
Microsoft Azure and Amazon AWS. For OpenBSD on Azure, it is a minimal
|
||||||
|
|
@ -23,40 +25,19 @@ has removed CMS which is required by Azure.
|
||||||
Usage
|
Usage
|
||||||
-----
|
-----
|
||||||
|
|
||||||
See the [cloud-agent(8)](cloud-agent.md) documentation for more
|
Installation is easy, `cloud-agent` detects the cloud type automatically.
|
||||||
information about the usage.
|
|
||||||
|
|
||||||
Basic installation is easy, `cloud-agent` detects the cloud type
|
|
||||||
automatically.
|
|
||||||
|
|
||||||
* On Microsoft Azure, create a file `/etc/hostname.hvn0`
|
* On Microsoft Azure, create a file `/etc/hostname.hvn0`
|
||||||
|
|
||||||
* On Amazon AWS, create a file `/etc/hostname.xnf0`
|
* On Amazon AWS, create a file `/etc/hostname.xnf0`
|
||||||
|
|
||||||
* On CloudStack, such as Exoscale, create a file `/etc/hostname.vio0`
|
|
||||||
|
|
||||||
* On OpenBSD VMM (with meta-data), create a file `/etc/hostname.vio0`
|
* On OpenBSD VMM (with meta-data), create a file `/etc/hostname.vio0`
|
||||||
|
|
||||||
* On OpenStack/VMware, create a file `/etc/hostname.vmx0`
|
* The content of the file is identical for all of them:
|
||||||
|
|
||||||
* The content of the file is identical for all of the above:
|
|
||||||
|
|
||||||
dhcp
|
dhcp
|
||||||
!/usr/local/libexec/cloud-agent "\$if"
|
!/usr/local/libexec/cloud-agent "\$if"
|
||||||
|
|
||||||
* On OpenNebula, such as Data Center Light, create a file `/etc/hostname.if`
|
|
||||||
where _if_ is the name of your primary interface.
|
|
||||||
The `dhcp` line should be ommitted in the file:
|
|
||||||
|
|
||||||
!/usr/local/libexec/cloud-agent "\$if"
|
|
||||||
|
|
||||||
Releases
|
|
||||||
--------
|
|
||||||
|
|
||||||
See the [Changelog](CHANGELOG.md) for a summary of changes and
|
|
||||||
download the releases from the
|
|
||||||
[release page](https://github.com/reyk/cloud-agent/releases).
|
|
||||||
|
|
||||||
Author
|
Author
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
PROG= cloud-agent
|
PROG= cloud-agent
|
||||||
SRCS= http.c json.c jsmn.c log.c main.c xml.c
|
SRCS= main.c xml.c azure.c cloudinit.c http.c log.c
|
||||||
SRCS+= azure.c cloudinit.c opennebula.c openstack.c
|
|
||||||
SRCS+= growdisk.c
|
|
||||||
BINDIR= /usr/local/libexec
|
BINDIR= /usr/local/libexec
|
||||||
MANDIR= /usr/local/man/man
|
MANDIR= /usr/local/man/man
|
||||||
|
|
||||||
|
|
@ -17,7 +15,7 @@ CFLAGS+= -Wmissing-declarations
|
||||||
CFLAGS+= -Wshadow -Wpointer-arith
|
CFLAGS+= -Wshadow -Wpointer-arith
|
||||||
CFLAGS+= -Wsign-compare -Wcast-qual
|
CFLAGS+= -Wsign-compare -Wcast-qual
|
||||||
|
|
||||||
LDADD+= -lexpat -ltls -lssl -lcrypto -lutil
|
LDADD+= -lexpat -ltls -lssl -lcrypto
|
||||||
DPADD+= ${LIBEXPAT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO} ${LIBUTIL}
|
DPADD+= ${LIBEXPAT} ${LIBTLS} ${LIBSSL} ${LIBCRYPTO}
|
||||||
|
|
||||||
.include <bsd.prog.mk>
|
.include <bsd.prog.mk>
|
||||||
|
|
|
||||||
158
agent/azure.c
158
agent/azure.c
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
@ -23,11 +23,8 @@
|
||||||
#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 <openssl/opensslv.h>
|
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
|
@ -54,6 +51,7 @@ static struct httpget
|
||||||
|
|
||||||
static int azure_keys(struct system_config *);
|
static int azure_keys(struct system_config *);
|
||||||
static int azure_getpubkeys(struct system_config *);
|
static int azure_getpubkeys(struct system_config *);
|
||||||
|
static int azure_getendpoint(struct system_config *);
|
||||||
static int azure_getovfenv(struct system_config *);
|
static int azure_getovfenv(struct system_config *);
|
||||||
static int azure_versions(struct system_config *);
|
static int azure_versions(struct system_config *);
|
||||||
static int azure_goalstate(struct system_config *);
|
static int azure_goalstate(struct system_config *);
|
||||||
|
|
@ -63,64 +61,54 @@ static int azure_reporthealth(struct system_config *, const char *);
|
||||||
int
|
int
|
||||||
azure(struct system_config *sc)
|
azure(struct system_config *sc)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
|
||||||
if (sc->sc_state == STATE_INIT) {
|
/* Apply defaults */
|
||||||
free(sc->sc_username);
|
if ((sc->sc_username = strdup("azure-user")) == NULL) {
|
||||||
if ((sc->sc_username = strdup("azure-user")) == NULL) {
|
log_warnx("failed to set default user");
|
||||||
log_warnx("failed to set default user");
|
goto done;
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply defaults */
|
|
||||||
sc->sc_ovfenv = "/var/db/azure-ovf-env.xml";
|
|
||||||
sc->sc_priv = &az_config;
|
|
||||||
sc->sc_state = STATE_DHCP;
|
|
||||||
return (-1);
|
|
||||||
}
|
}
|
||||||
|
sc->sc_cdrom = "/dev/cd0c";
|
||||||
|
sc->sc_ovfenv = "/var/db/azure-ovf-env.xml";
|
||||||
|
sc->sc_priv = &az_config;
|
||||||
|
|
||||||
/* Don't try other endpoints */
|
if (azure_getendpoint(sc) != 0) {
|
||||||
sc->sc_state = STATE_DONE;
|
log_warnx("failed to get endpoint");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (azure_getovfenv(sc) != 0) {
|
if (azure_getovfenv(sc) != 0) {
|
||||||
log_warnx("failed to get ovf-env.xml");
|
log_warnx("failed to get ovf-env.xml");
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
if (dhcp_getendpoint(sc) != 0) {
|
|
||||||
log_warnx("failed to get endpoint");
|
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (azure_versions(sc) != 0) {
|
if (azure_versions(sc) != 0) {
|
||||||
log_warnx("failed to get endpoint versions");
|
log_warnx("failed to get endpoint versions");
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (azure_goalstate(sc) != 0) {
|
if (azure_goalstate(sc) != 0) {
|
||||||
log_warnx("failed to get goalstate");
|
log_warnx("failed to get goalstate");
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sc->sc_dryrun) {
|
if (azure_keys(sc) != 0) {
|
||||||
if (azure_keys(sc) != 0) {
|
log_warnx("failed to get transport keys");
|
||||||
log_warnx("failed to get transport keys");
|
goto done;
|
||||||
goto fail;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (azure_certificates(sc) != 0) {
|
if (azure_certificates(sc) != 0) {
|
||||||
log_warnx("failed to get certificates");
|
log_warnx("failed to get certificates");
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (azure_reporthealth(sc, "Ready") != 0) {
|
if (azure_reporthealth(sc, "Ready") != 0) {
|
||||||
log_warnx("failed to report health");
|
log_warnx("failed to report health");
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
done:
|
||||||
free(az_config.az_container);
|
free(az_config.az_container);
|
||||||
free(az_config.az_pubkeyval);
|
free(az_config.az_pubkeyval);
|
||||||
|
|
||||||
|
|
@ -443,16 +431,13 @@ azure_certificates(struct system_config *sc)
|
||||||
|
|
||||||
fd = disable_output(sc, STDERR_FILENO);
|
fd = disable_output(sc, STDERR_FILENO);
|
||||||
|
|
||||||
#if defined(USE_OPENSSL)
|
#ifdef USE_OPENSSL
|
||||||
/*
|
/*
|
||||||
* XXX Now comes the part that needs CMS which is only
|
* XXX Now comes the part that needs CMS which is only
|
||||||
* XXX present in OpenSSL but got removed from LibreSSL.
|
* XXX present in OpenSSL but got removed from LibreSSL.
|
||||||
*/
|
*/
|
||||||
log_debug("%s: running openssl cms", __func__);
|
log_debug("%s: running openssl cms", __func__);
|
||||||
if (shell("/usr/local/bin/eopenssl", "cms", /* )) */
|
if (shell("/usr/local/bin/eopenssl", "cms", /* )) */
|
||||||
#elif defined(USE_LIBRESSL_CMS) || LIBRESSL_VERSION_NUMBER > 0x3000200fL
|
|
||||||
/* And CMS returned to LibreSSL! */
|
|
||||||
if (shell("/usr/bin/openssl", "cms", /* )) */
|
|
||||||
#else
|
#else
|
||||||
if (shell("/usr/local/bin/cms",
|
if (shell("/usr/local/bin/cms",
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -667,22 +652,36 @@ azure_getovfenv(struct system_config *sc)
|
||||||
struct xml xml;
|
struct xml xml;
|
||||||
struct xmlelem *xp, *xe, *xk, *xv;
|
struct xmlelem *xp, *xe, *xk, *xv;
|
||||||
char *sshfp, *sshval, *str;
|
char *sshfp, *sshval, *str;
|
||||||
int ret = -1, fd = -1;
|
int mount = 0, ret = -1, fd = -1;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
|
/* Silently try to mount the cdrom */
|
||||||
|
fd = disable_output(sc, STDERR_FILENO);
|
||||||
|
ret = shell("mount", "-r", sc->sc_cdrom, "/mnt", NULL);
|
||||||
|
enable_output(sc, STDERR_FILENO, fd);
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
log_debug("%s: mounted %s", __func__, sc->sc_cdrom);
|
||||||
|
mount = 1;
|
||||||
|
}
|
||||||
|
ret = -1;
|
||||||
|
|
||||||
if (xml_init(&xml) != 0) {
|
if (xml_init(&xml) != 0) {
|
||||||
log_debug("%s: xml", __func__);
|
log_debug("%s: xml", __func__);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* Fallback to and older ovf-env.xml file */
|
||||||
* Assume that the cdrom is already mounted.
|
|
||||||
* Fallback to and older ovf-env.xml file.
|
|
||||||
*/
|
|
||||||
if (xml_parse(&xml, "/mnt/ovf-env.xml") == -1 &&
|
if (xml_parse(&xml, "/mnt/ovf-env.xml") == -1 &&
|
||||||
xml_parse(&xml, sc->sc_ovfenv) == -1)
|
xml_parse(&xml, sc->sc_ovfenv) == -1)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
/* unmount if we mounted the cdrom before */
|
||||||
|
if (mount && shell("umount", "/mnt", NULL) == 0) {
|
||||||
|
log_debug("%s: unmounted %s", __func__, sc->sc_cdrom);
|
||||||
|
}
|
||||||
|
|
||||||
if ((xp = xml_findl(&xml.ox_root,
|
if ((xp = xml_findl(&xml.ox_root,
|
||||||
"Environment", "wa:ProvisioningSection",
|
"Environment", "wa:ProvisioningSection",
|
||||||
"LinuxProvisioningConfigurationSet", NULL)) == NULL) {
|
"LinuxProvisioningConfigurationSet", NULL)) == NULL) {
|
||||||
|
|
@ -731,7 +730,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_hash = calloc(1, _PASSWORD_LEN)) == NULL) {
|
if ((sc->sc_password = calloc(1, 128)) == NULL) {
|
||||||
log_debug("%s: password failed", __func__);
|
log_debug("%s: password failed", __func__);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
@ -739,14 +738,13 @@ 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_hash, _PASSWORD_LEN) != 0) {
|
sc->sc_password, 128) != 0) {
|
||||||
log_debug("%s: password hashing failed", __func__);
|
log_debug("%s: password hashing failed", __func__);
|
||||||
free(sc->sc_password_hash);
|
free(sc->sc_password);
|
||||||
sc->sc_password_hash = NULL;
|
sc->sc_password = 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 */
|
||||||
|
|
@ -756,11 +754,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_hash);
|
xe->xe_data = strdup(sc->sc_password);
|
||||||
xe->xe_datalen = strlen(sc->sc_password_hash);
|
xe->xe_datalen = strlen(sc->sc_password);
|
||||||
} 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_hash =
|
if ((sc->sc_password =
|
||||||
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;
|
||||||
|
|
@ -793,3 +791,53 @@ azure_getovfenv(struct system_config *sc)
|
||||||
xml_free(&xml);
|
xml_free(&xml);
|
||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
azure_getendpoint(struct system_config *sc)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX], buf[BUFSIZ], *ep = NULL;
|
||||||
|
int a[4];
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
if ((size_t)snprintf(path, sizeof(path), "/var/db/dhclient.leases.%s",
|
||||||
|
sc->sc_interface) >= sizeof(path)) {
|
||||||
|
log_debug("%s: invalid path", __func__);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fp = fopen(path, "r")) == NULL) {
|
||||||
|
log_debug("%s: failed to open %s", __func__, path);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp) != NULL) {
|
||||||
|
buf[strcspn(buf, ";\n")] = '\0';
|
||||||
|
|
||||||
|
/* Find last occurence of option-245 */
|
||||||
|
if (sscanf(buf, " option option-245 %x:%x:%x:%x",
|
||||||
|
&a[0], &a[1], &a[2], &a[3]) == 4) {
|
||||||
|
free(ep);
|
||||||
|
if (asprintf(&ep, "%d.%d.%d.%d",
|
||||||
|
a[0], a[1], a[2], a[3]) == -1) {
|
||||||
|
log_debug("%s: asprintf", __func__);
|
||||||
|
fclose(fp);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
if (ep == NULL) {
|
||||||
|
log_debug("%s: endpoint not found", __func__);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sc->sc_endpoint = ep;
|
||||||
|
sc->sc_addr.ip = sc->sc_endpoint;
|
||||||
|
sc->sc_addr.family = 4;
|
||||||
|
|
||||||
|
log_debug("%s: %s", __func__, ep);
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
.\" $OpenBSD: mdoc.template,v 1.15 2014/03/31 00:09:54 dlg Exp $
|
.\" $OpenBSD: mdoc.template,v 1.15 2014/03/31 00:09:54 dlg Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2017, 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
.\" Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
|
||||||
.\"
|
.\"
|
||||||
.\" Permission to use, copy, modify, and distribute this software for any
|
.\" Permission to use, copy, modify, and distribute this software for any
|
||||||
.\" purpose with or without fee is hereby granted, provided that the above
|
.\" purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
@ -23,75 +23,17 @@
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm cloud-agent
|
.Nm cloud-agent
|
||||||
.Op Fl nuv
|
.Op Fl nuv
|
||||||
.Op Fl c Ar cloud Ns Op , Ns Ar cloud Ns ...
|
|
||||||
.Op Fl p Ar length
|
|
||||||
.Op Fl r Ar rootdisk
|
|
||||||
.Op Fl t Ar timeout
|
|
||||||
.Op Fl U Ar username
|
|
||||||
.Ar interface
|
.Ar interface
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
program manages the OpenBSD provisioning and VM interaction in cloud
|
program manages the OpenBSD provisioning and VM interaction in cloud
|
||||||
environments.
|
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 c Ar cloud Ns Op , Ns Ar cloud Ns ...
|
|
||||||
Probe a list of cloud stacks for provisioning in the specified order.
|
|
||||||
If this option is not specified,
|
|
||||||
.Nm
|
|
||||||
tries to detect the environment and possible cloud stacks automatically.
|
|
||||||
Supported
|
|
||||||
.Ar cloud
|
|
||||||
stacks are:
|
|
||||||
.Pp
|
|
||||||
.Bl -tag -width opennebula -offset indent -compact
|
|
||||||
.It Ic azure
|
|
||||||
Microsoft Azure
|
|
||||||
.It Ic cloudinit
|
|
||||||
Generic cloud-init
|
|
||||||
.It Ic ec2
|
|
||||||
Amazon AWS EC2
|
|
||||||
.It Ic opennebula
|
|
||||||
OpenNebula
|
|
||||||
.It Ic openstack
|
|
||||||
OpenStack
|
|
||||||
.El
|
|
||||||
.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
|
|
||||||
Change the HTTP timeout.
|
|
||||||
The default is 3 seconds.
|
|
||||||
.It Fl U Ar username
|
|
||||||
Change the default user.
|
|
||||||
The default is
|
|
||||||
.Dq ec2-user
|
|
||||||
on AWS,
|
|
||||||
.Dq azure-user
|
|
||||||
on Azure, and
|
|
||||||
.Dq puffy
|
|
||||||
everywhere else.
|
|
||||||
The default user is used when it is not obtained from the cloud
|
|
||||||
configuration.
|
|
||||||
Using
|
|
||||||
.Dq root
|
|
||||||
is supported, but not recommended.
|
|
||||||
.It Fl r Ar rootdisk
|
|
||||||
Automatically grow the last
|
|
||||||
.Ox
|
|
||||||
FFS partition of the root disk to use all the available space.
|
|
||||||
.It Fl u
|
.It Fl u
|
||||||
Deprovision and unconfigure the system.
|
Deprovision and unconfigure the system.
|
||||||
This deletes keys, passwords, and logs files without asking for permission.
|
This deletes keys, passwords, and logs files without asking for permission.
|
||||||
|
|
@ -103,17 +45,14 @@ Enable
|
||||||
.Nm
|
.Nm
|
||||||
in the
|
in the
|
||||||
.Xr hostname.if 5
|
.Xr hostname.if 5
|
||||||
of the VM's primary networking interface and automatically the last
|
of the VM's primary networking interface:
|
||||||
partition of the root disk:
|
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
# cat /etc/hostname.hvn0
|
# cat /etc/hostname.hvn0
|
||||||
dhcp
|
dhcp
|
||||||
!/usr/local/libexec/cloud-agent -r sd0 "\e$if"
|
!/usr/local/libexec/cloud-agent "\$if"
|
||||||
.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
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
@ -30,69 +30,101 @@
|
||||||
#include "xml.h"
|
#include "xml.h"
|
||||||
|
|
||||||
static int cloudinit_fetch(struct system_config *);
|
static int cloudinit_fetch(struct system_config *);
|
||||||
|
static char *cloudinit_get(struct system_config *, const char *,
|
||||||
|
enum strtype);
|
||||||
|
|
||||||
int
|
int
|
||||||
ec2(struct system_config *sc)
|
ec2(struct system_config *sc)
|
||||||
{
|
{
|
||||||
if (sc->sc_state == STATE_INIT) {
|
if ((sc->sc_username = strdup("ec2-user")) == NULL ||
|
||||||
free(sc->sc_username);
|
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
||||||
if ((sc->sc_username = strdup("ec2-user")) == NULL) {
|
log_warnx("failed to set defaults");
|
||||||
log_warnx("failed to set default user");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
sc->sc_state = STATE_169;
|
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
return cloudinit_fetch(sc);
|
|
||||||
|
return (cloudinit_fetch(sc));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cloudinit(struct system_config *sc)
|
cloudinit(struct system_config *sc)
|
||||||
{
|
{
|
||||||
if (sc->sc_state == STATE_INIT) {
|
/* XXX get endpoint from DHCP lease file */
|
||||||
sc->sc_state = STATE_DHCP;
|
if ((sc->sc_username = strdup("puffy")) == NULL ||
|
||||||
|
(sc->sc_endpoint = strdup("169.254.169.254")) == NULL) {
|
||||||
|
log_warnx("failed to set defaults");
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
return cloudinit_fetch(sc);
|
|
||||||
|
return (cloudinit_fetch(sc));
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
cloudinit_get(struct system_config *sc, const char *path, enum strtype type)
|
||||||
|
{
|
||||||
|
struct httpget *g = NULL;
|
||||||
|
char *str = NULL;
|
||||||
|
|
||||||
|
log_debug("%s: %s", __func__, path);
|
||||||
|
|
||||||
|
g = http_get(&sc->sc_addr, 1,
|
||||||
|
sc->sc_endpoint, 80, path, NULL, 0, NULL);
|
||||||
|
if (g != NULL && g->code == 200 && g->bodypartsz > 0) {
|
||||||
|
switch (type) {
|
||||||
|
case TEXT:
|
||||||
|
/* multi-line string, always printable */
|
||||||
|
str = get_string(g->bodypart, g->bodypartsz);
|
||||||
|
break;
|
||||||
|
case LINE:
|
||||||
|
str = get_line(g->bodypart, g->bodypartsz);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
str = get_word(g->bodypart, g->bodypartsz);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
http_get_free(g);
|
||||||
|
|
||||||
|
return (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cloudinit_fetch(struct system_config *sc)
|
cloudinit_fetch(struct system_config *sc)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = 0;
|
||||||
char *str = NULL;
|
char *str = NULL;
|
||||||
|
|
||||||
sc->sc_addr.ip = sc->sc_endpoint;
|
sc->sc_addr.ip = sc->sc_endpoint;
|
||||||
sc->sc_addr.family = 4;
|
sc->sc_addr.family = 4;
|
||||||
|
|
||||||
/* instance-id */
|
/* instance-id */
|
||||||
if ((sc->sc_instance = metadata(sc,
|
if ((sc->sc_instance = cloudinit_get(sc,
|
||||||
"/latest/meta-data/instance-id", WORD)) == NULL)
|
"/latest/meta-data/instance-id", WORD)) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* hostname */
|
/* hostname */
|
||||||
if ((sc->sc_hostname = metadata(sc,
|
if ((sc->sc_hostname = cloudinit_get(sc,
|
||||||
"/latest/meta-data/local-hostname", WORD)) == NULL)
|
"/latest/meta-data/local-hostname", WORD)) == NULL)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* optional pubkey */
|
/* pubkey */
|
||||||
if ((str = metadata(sc,
|
if ((str = cloudinit_get(sc,
|
||||||
"/latest/meta-data/public-keys/0/openssh-key", LINE)) == NULL &&
|
"/latest/meta-data/public-keys/0/openssh-key", LINE)) == NULL)
|
||||||
(str = metadata(sc,
|
goto fail;
|
||||||
"/latest/meta-data/public-keys", LINE)) == NULL)
|
if (agent_addpubkey(sc, str, NULL) != 0)
|
||||||
log_warnx("failed to get public key");
|
|
||||||
else if (agent_addpubkey(sc, str, NULL) != 0)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* optional username - this is an extension by meta-data(8) */
|
/* optional username - this is an extension by meta-data(8) */
|
||||||
if ((str = metadata(sc, "/latest/meta-data/username", WORD)) != NULL) {
|
if ((str = cloudinit_get(sc,
|
||||||
|
"/latest/meta-data/username", WORD)) != NULL) {
|
||||||
free(sc->sc_username);
|
free(sc->sc_username);
|
||||||
sc->sc_username = str;
|
sc->sc_username = str;
|
||||||
str = NULL;
|
str = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* userdata (optional) */
|
/* userdata */
|
||||||
sc->sc_userdata = metadata(sc, "/latest/user-data", TEXT);
|
if ((sc->sc_userdata = cloudinit_get(sc,
|
||||||
|
"/latest/user-data", TEXT)) == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
fail:
|
fail:
|
||||||
|
|
|
||||||
173
agent/growdisk.c
173
agent/growdisk.c
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Reyk Floeter <reyk@openbsd.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/param.h> /* DEV_BSIZE */
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/ioctl.h>
|
|
||||||
#include <sys/dkio.h>
|
|
||||||
#define DKTYPENAMES
|
|
||||||
#include <sys/disklabel.h>
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <util.h>
|
|
||||||
#include <err.h>
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
#define MEG(_n) ((_n) * DEV_BSIZE / 1024 / 1024)
|
|
||||||
|
|
||||||
static uint16_t dkcksum(struct disklabel *);
|
|
||||||
|
|
||||||
static uint16_t
|
|
||||||
dkcksum(struct disklabel *lp)
|
|
||||||
{
|
|
||||||
uint16_t *start, *end, sum;
|
|
||||||
start = (uint16_t *)lp;
|
|
||||||
end = (uint16_t *)&lp->d_partitions[lp->d_npartitions];
|
|
||||||
for (sum = 0; start < end;)
|
|
||||||
sum ^= *start++;
|
|
||||||
return (sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
growdisk(struct system_config *sc)
|
|
||||||
{
|
|
||||||
char c, last_part = 0, *out = NULL, *path = NULL;
|
|
||||||
int ret = -1, i, errfd, outfd;
|
|
||||||
uint64_t bend, psize;
|
|
||||||
struct partition *pp, *p = NULL;
|
|
||||||
struct disklabel lp;
|
|
||||||
uint16_t cksum;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Grow the OpenBSD MBR partition
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* XXX this is a bit ugly but easier to do */
|
|
||||||
if (!sc->sc_dryrun &&
|
|
||||||
shellout("e 3\n\n\n\n*\nw\nq\n", &out,
|
|
||||||
"fdisk", "-e", sc->sc_rootdisk, NULL) != 0) {
|
|
||||||
log_warnx("failed to grow OpenBSD partition");
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
free(out);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Grow the last partition in the disklabel
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ((fd = opendev(sc->sc_rootdisk,
|
|
||||||
O_RDWR, OPENDEV_PART, NULL)) == -1) {
|
|
||||||
log_warn("failed to open %s", sc->sc_rootdisk);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(fd, DIOCGDINFO, &lp) == -1) {
|
|
||||||
log_warn("failed to get disklabel");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lp.d_magic != DISKMAGIC || lp.d_magic2 != DISKMAGIC) {
|
|
||||||
log_warnx("invalid disklabel magic bytes");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
cksum = lp.d_checksum;
|
|
||||||
lp.d_checksum = 0;
|
|
||||||
|
|
||||||
if (dkcksum(&lp) != cksum) {
|
|
||||||
log_warnx("invalid disklabel checksum");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
pp = lp.d_partitions;
|
|
||||||
for (i = 0, pp = lp.d_partitions; i < lp.d_npartitions; i++, pp++) {
|
|
||||||
if (!DL_GETPSIZE(pp))
|
|
||||||
continue;
|
|
||||||
c = 'a' + i;
|
|
||||||
if (pp->p_fstype == FS_BSDFFS) {
|
|
||||||
last_part = c;
|
|
||||||
p = pp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (last_part == 0) {
|
|
||||||
log_warnx("last BSD partition not found");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
bend = DL_GETDSIZE(&lp) - DL_GETBSTART(&lp);
|
|
||||||
psize = bend - DL_GETPOFFSET(p);
|
|
||||||
|
|
||||||
/* Only grow, but never shring the disk */
|
|
||||||
if (bend <= DL_GETBEND(&lp) && psize <= DL_GETPSIZE(p)) {
|
|
||||||
log_debug("%s: not growing %s%c, size is %lluMB",
|
|
||||||
__func__, sc->sc_rootdisk, last_part, MEG(psize));
|
|
||||||
ret = 0;
|
|
||||||
} else {
|
|
||||||
log_info("growing %s%c from %lluMB to %lluMB",
|
|
||||||
sc->sc_rootdisk, last_part,
|
|
||||||
MEG(DL_GETPSIZE(p)), MEG(psize));
|
|
||||||
ret = -1;
|
|
||||||
}
|
|
||||||
if (sc->sc_dryrun || ret == 0) {
|
|
||||||
ret = 0;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update OpenBSD boundaries */
|
|
||||||
DL_SETBEND(&lp, bend);
|
|
||||||
|
|
||||||
/* Update the size of the last partition */
|
|
||||||
DL_SETPSIZE(p, psize);
|
|
||||||
|
|
||||||
lp.d_checksum = dkcksum(&lp);
|
|
||||||
|
|
||||||
if (ioctl(fd, DIOCWDINFO, &lp) == -1) {
|
|
||||||
log_warn("failed to write disklabel");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Grow the filesystem
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (asprintf(&path, "/dev/%s%c", sc->sc_rootdisk, last_part) == -1)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
errfd = disable_output(sc, STDERR_FILENO);
|
|
||||||
outfd = disable_output(sc, STDOUT_FILENO);
|
|
||||||
|
|
||||||
(void)shell("umount", "-f", path, NULL);
|
|
||||||
(void)shell("growfs", "-yq", path, NULL);
|
|
||||||
if ((ret = shell("fsck", "-y", path, NULL)) != 0)
|
|
||||||
ret = -1;
|
|
||||||
(void)shell("mount", "-a", "-t", "nonfs,vnd", NULL);
|
|
||||||
|
|
||||||
enable_output(sc, STDERR_FILENO, errfd);
|
|
||||||
enable_output(sc, STDOUT_FILENO, outfd);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
done:
|
|
||||||
free(path);
|
|
||||||
close(fd);
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
@ -277,8 +277,8 @@ again:
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
warn("%s: socket", addrs[cur].ip);
|
warn("%s: socket", addrs[cur].ip);
|
||||||
goto again;
|
goto again;
|
||||||
} else if (connect_wait(fd, (struct sockaddr *)&ss, len) == -1) {
|
} else if (connect(fd, (struct sockaddr *)&ss, len) == -1) {
|
||||||
warn("http://%s%s", addrs[cur].ip, path);
|
warn("%s: connect", addrs[cur].ip);
|
||||||
close(fd);
|
close(fd);
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
332
agent/jsmn.c
332
agent/jsmn.c
|
|
@ -1,332 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2010 Serge A. Zaitsev
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.*
|
|
||||||
*/
|
|
||||||
#include "jsmn.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates a fresh unused token from the token pull.
|
|
||||||
*/
|
|
||||||
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
|
||||||
jsmntok_t *tokens, size_t num_tokens) {
|
|
||||||
jsmntok_t *tok;
|
|
||||||
if (parser->toknext >= num_tokens) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
tok = &tokens[parser->toknext++];
|
|
||||||
tok->start = tok->end = -1;
|
|
||||||
tok->size = 0;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
tok->parent = -1;
|
|
||||||
#endif
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills token type and boundaries.
|
|
||||||
*/
|
|
||||||
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
|
||||||
int start, int end) {
|
|
||||||
token->type = type;
|
|
||||||
token->start = start;
|
|
||||||
token->end = end;
|
|
||||||
token->size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills next available token with JSON primitive.
|
|
||||||
*/
|
|
||||||
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
|
||||||
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
|
||||||
jsmntok_t *token;
|
|
||||||
int start;
|
|
||||||
|
|
||||||
start = parser->pos;
|
|
||||||
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
switch (js[parser->pos]) {
|
|
||||||
#ifndef JSMN_STRICT
|
|
||||||
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
|
||||||
case ':':
|
|
||||||
#endif
|
|
||||||
case '\t' : case '\r' : case '\n' : case ' ' :
|
|
||||||
case ',' : case ']' : case '}' :
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef JSMN_STRICT
|
|
||||||
/* In strict mode primitive must be followed by a comma/object/array */
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
found:
|
|
||||||
if (tokens == NULL) {
|
|
||||||
parser->pos--;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
parser->pos--;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills next token with JSON string.
|
|
||||||
*/
|
|
||||||
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
|
||||||
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
|
||||||
jsmntok_t *token;
|
|
||||||
|
|
||||||
int start = parser->pos;
|
|
||||||
|
|
||||||
parser->pos++;
|
|
||||||
|
|
||||||
/* Skip starting quote */
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
char c = js[parser->pos];
|
|
||||||
|
|
||||||
/* Quote: end of string */
|
|
||||||
if (c == '\"') {
|
|
||||||
if (tokens == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Backslash: Quoted symbol expected */
|
|
||||||
if (c == '\\' && parser->pos + 1 < len) {
|
|
||||||
int i;
|
|
||||||
parser->pos++;
|
|
||||||
switch (js[parser->pos]) {
|
|
||||||
/* Allowed escaped symbols */
|
|
||||||
case '\"': case '/' : case '\\' : case 'b' :
|
|
||||||
case 'f' : case 'r' : case 'n' : case 't' :
|
|
||||||
break;
|
|
||||||
/* Allows escaped symbol \uXXXX */
|
|
||||||
case 'u':
|
|
||||||
parser->pos++;
|
|
||||||
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
|
|
||||||
/* If it isn't a hex character we have an error */
|
|
||||||
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
|
||||||
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
|
||||||
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
parser->pos++;
|
|
||||||
}
|
|
||||||
parser->pos--;
|
|
||||||
break;
|
|
||||||
/* Unexpected symbol */
|
|
||||||
default:
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse JSON string and fill tokens.
|
|
||||||
*/
|
|
||||||
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
|
||||||
jsmntok_t *tokens, unsigned int num_tokens) {
|
|
||||||
int r;
|
|
||||||
int i;
|
|
||||||
jsmntok_t *token;
|
|
||||||
int count = parser->toknext;
|
|
||||||
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
char c;
|
|
||||||
jsmntype_t type;
|
|
||||||
|
|
||||||
c = js[parser->pos];
|
|
||||||
switch (c) {
|
|
||||||
case '{': case '[':
|
|
||||||
count++;
|
|
||||||
if (tokens == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL)
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
if (parser->toksuper != -1) {
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
|
||||||
token->start = parser->pos;
|
|
||||||
parser->toksuper = parser->toknext - 1;
|
|
||||||
break;
|
|
||||||
case '}': case ']':
|
|
||||||
if (tokens == NULL)
|
|
||||||
break;
|
|
||||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
if (parser->toknext < 1) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
token = &tokens[parser->toknext - 1];
|
|
||||||
for (;;) {
|
|
||||||
if (token->start != -1 && token->end == -1) {
|
|
||||||
if (token->type != type) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
token->end = parser->pos + 1;
|
|
||||||
parser->toksuper = token->parent;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (token->parent == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
token = &tokens[token->parent];
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
|
||||||
token = &tokens[i];
|
|
||||||
if (token->start != -1 && token->end == -1) {
|
|
||||||
if (token->type != type) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
parser->toksuper = -1;
|
|
||||||
token->end = parser->pos + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Error if unmatched closing bracket */
|
|
||||||
if (i == -1) return JSMN_ERROR_INVAL;
|
|
||||||
for (; i >= 0; i--) {
|
|
||||||
token = &tokens[i];
|
|
||||||
if (token->start != -1 && token->end == -1) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
|
||||||
if (r < 0) return r;
|
|
||||||
count++;
|
|
||||||
if (parser->toksuper != -1 && tokens != NULL)
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
break;
|
|
||||||
case '\t' : case '\r' : case '\n' : case ' ':
|
|
||||||
break;
|
|
||||||
case ':':
|
|
||||||
parser->toksuper = parser->toknext - 1;
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
if (tokens != NULL && parser->toksuper != -1 &&
|
|
||||||
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
|
||||||
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
parser->toksuper = tokens[parser->toksuper].parent;
|
|
||||||
#else
|
|
||||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
|
||||||
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
|
||||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef JSMN_STRICT
|
|
||||||
/* In strict mode primitives are: numbers and booleans */
|
|
||||||
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
|
||||||
case '5': case '6': case '7' : case '8': case '9':
|
|
||||||
case 't': case 'f': case 'n' :
|
|
||||||
/* And they must not be keys of the object */
|
|
||||||
if (tokens != NULL && parser->toksuper != -1) {
|
|
||||||
jsmntok_t *t = &tokens[parser->toksuper];
|
|
||||||
if (t->type == JSMN_OBJECT ||
|
|
||||||
(t->type == JSMN_STRING && t->size != 0)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* In non-strict mode every unquoted value is a primitive */
|
|
||||||
default:
|
|
||||||
#endif
|
|
||||||
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
|
||||||
if (r < 0) return r;
|
|
||||||
count++;
|
|
||||||
if (parser->toksuper != -1 && tokens != NULL)
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef JSMN_STRICT
|
|
||||||
/* Unexpected char in strict mode */
|
|
||||||
default:
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens != NULL) {
|
|
||||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
|
||||||
/* Unmatched opened object or array */
|
|
||||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new parser based over a given buffer with an array of tokens
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
void jsmn_init(jsmn_parser *parser) {
|
|
||||||
parser->pos = 0;
|
|
||||||
parser->toknext = 0;
|
|
||||||
parser->toksuper = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
97
agent/jsmn.h
97
agent/jsmn.h
|
|
@ -1,97 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright (c) 2010 Serge A. Zaitsev
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.*
|
|
||||||
*/
|
|
||||||
#ifndef __JSMN_H_
|
|
||||||
#define __JSMN_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON type identifier. Basic types are:
|
|
||||||
* o Object
|
|
||||||
* o Array
|
|
||||||
* o String
|
|
||||||
* o Other primitive: number, boolean (true/false) or null
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
JSMN_UNDEFINED = 0,
|
|
||||||
JSMN_OBJECT = 1,
|
|
||||||
JSMN_ARRAY = 2,
|
|
||||||
JSMN_STRING = 3,
|
|
||||||
JSMN_PRIMITIVE = 4
|
|
||||||
} jsmntype_t;
|
|
||||||
|
|
||||||
enum jsmnerr {
|
|
||||||
/* Not enough tokens were provided */
|
|
||||||
JSMN_ERROR_NOMEM = -1,
|
|
||||||
/* Invalid character inside JSON string */
|
|
||||||
JSMN_ERROR_INVAL = -2,
|
|
||||||
/* The string is not a full JSON packet, more bytes expected */
|
|
||||||
JSMN_ERROR_PART = -3
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON token description.
|
|
||||||
* @param type type (object, array, string etc.)
|
|
||||||
* @param start start position in JSON data string
|
|
||||||
* @param end end position in JSON data string
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
jsmntype_t type;
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
int size;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
int parent;
|
|
||||||
#endif
|
|
||||||
} jsmntok_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON parser. Contains an array of token blocks available. Also stores
|
|
||||||
* the string being parsed now and current position in that string
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int pos; /* offset in the JSON string */
|
|
||||||
unsigned int toknext; /* next token to allocate */
|
|
||||||
int toksuper; /* superior token node, e.g parent object or array */
|
|
||||||
} jsmn_parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create JSON parser over an array of tokens
|
|
||||||
*/
|
|
||||||
void jsmn_init(jsmn_parser *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
|
|
||||||
* a single JSON object.
|
|
||||||
*/
|
|
||||||
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
|
||||||
jsmntok_t *tokens, unsigned int num_tokens);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __JSMN_H_ */
|
|
||||||
319
agent/json.c
319
agent/json.c
|
|
@ -1,319 +0,0 @@
|
||||||
/* $OpenBSD: json.c,v 1.9 2017/01/24 13:32:55 jsing Exp $ */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "jsmn.h"
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
struct jsmnp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Objects consist of node pairs: the left-hand side (before the colon)
|
|
||||||
* and the right-hand side---the data.
|
|
||||||
*/
|
|
||||||
struct jsmnp {
|
|
||||||
struct jsmnn *lhs; /* left of colon */
|
|
||||||
struct jsmnn *rhs; /* right of colon */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Object for converting the JSMN token array into a tree.
|
|
||||||
*/
|
|
||||||
struct parse {
|
|
||||||
struct jsmnn *nodes; /* all nodes */
|
|
||||||
size_t cur; /* current number */
|
|
||||||
size_t max; /* nodes in "nodes" */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Recursive part for convertin a JSMN token array into a tree.
|
|
||||||
* See "example/jsondump.c" for its construction (it's the same except
|
|
||||||
* for how it handles allocation errors).
|
|
||||||
*/
|
|
||||||
static ssize_t
|
|
||||||
build(struct parse *parse, struct jsmnn **np,
|
|
||||||
jsmntok_t *t, const char *js, size_t sz)
|
|
||||||
{
|
|
||||||
size_t i, j;
|
|
||||||
struct jsmnn *n;
|
|
||||||
ssize_t tmp;
|
|
||||||
|
|
||||||
if (sz == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
assert(parse->cur < parse->max);
|
|
||||||
n = *np = &parse->nodes[parse->cur++];
|
|
||||||
n->p = parse;
|
|
||||||
n->type = t->type;
|
|
||||||
|
|
||||||
switch (t->type) {
|
|
||||||
case JSMN_STRING:
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case JSMN_PRIMITIVE:
|
|
||||||
n->fields = 1;
|
|
||||||
n->d.str = strndup
|
|
||||||
(js + t->start,
|
|
||||||
t->end - t->start);
|
|
||||||
if (n->d.str == NULL)
|
|
||||||
break;
|
|
||||||
return 1;
|
|
||||||
case JSMN_OBJECT:
|
|
||||||
n->fields = t->size;
|
|
||||||
n->d.obj = calloc(n->fields,
|
|
||||||
sizeof(struct jsmnp));
|
|
||||||
if (n->d.obj == NULL)
|
|
||||||
break;
|
|
||||||
for (i = j = 0; i < (size_t)t->size; i++) {
|
|
||||||
tmp = build(parse,
|
|
||||||
&n->d.obj[i].lhs,
|
|
||||||
t + 1 + j, js, sz - j);
|
|
||||||
if (tmp < 0)
|
|
||||||
break;
|
|
||||||
j += tmp;
|
|
||||||
tmp = build(parse,
|
|
||||||
&n->d.obj[i].rhs,
|
|
||||||
t + 1 + j, js, sz - j);
|
|
||||||
if (tmp < 0)
|
|
||||||
break;
|
|
||||||
j += tmp;
|
|
||||||
}
|
|
||||||
if (i < (size_t)t->size)
|
|
||||||
break;
|
|
||||||
return j + 1;
|
|
||||||
case JSMN_ARRAY:
|
|
||||||
n->fields = t->size;
|
|
||||||
n->d.array = calloc(n->fields,
|
|
||||||
sizeof(struct jsmnn *));
|
|
||||||
if (n->d.array == NULL)
|
|
||||||
break;
|
|
||||||
for (i = j = 0; i < (size_t)t->size; i++) {
|
|
||||||
tmp = build(parse,
|
|
||||||
&n->d.array[i],
|
|
||||||
t + 1 + j, js, sz - j);
|
|
||||||
if (tmp < 0)
|
|
||||||
break;
|
|
||||||
j += tmp;
|
|
||||||
}
|
|
||||||
if (i < (size_t)t->size)
|
|
||||||
break;
|
|
||||||
return j + 1;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fully free up a parse sequence.
|
|
||||||
* This handles all nodes sequentially, not recursively.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
jsmnparse_free(struct parse *p)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (p == NULL)
|
|
||||||
return;
|
|
||||||
for (i = 0; i < p->max; i++) {
|
|
||||||
struct jsmnn *n = &p->nodes[i];
|
|
||||||
switch (n->type) {
|
|
||||||
case JSMN_ARRAY:
|
|
||||||
free(n->d.array);
|
|
||||||
break;
|
|
||||||
case JSMN_OBJECT:
|
|
||||||
free(n->d.obj);
|
|
||||||
break;
|
|
||||||
case JSMN_PRIMITIVE:
|
|
||||||
free(n->d.str);
|
|
||||||
break;
|
|
||||||
case JSMN_STRING:
|
|
||||||
free(n->d.str);
|
|
||||||
break;
|
|
||||||
case JSMN_UNDEFINED:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(p->nodes);
|
|
||||||
free(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allocate a tree representation of "t".
|
|
||||||
* This returns NULL on allocation failure or when sz is zero, in which
|
|
||||||
* case all resources allocated along the way are freed already.
|
|
||||||
*/
|
|
||||||
static struct jsmnn *
|
|
||||||
jsmntree_alloc(jsmntok_t *t, const char *js, size_t sz)
|
|
||||||
{
|
|
||||||
struct jsmnn *first;
|
|
||||||
struct parse *p;
|
|
||||||
|
|
||||||
if (sz == 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
p = calloc(1, sizeof(struct parse));
|
|
||||||
if (p == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
p->max = sz;
|
|
||||||
p->nodes = calloc(p->max, sizeof(struct jsmnn));
|
|
||||||
if (p->nodes == NULL) {
|
|
||||||
free(p);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (build(p, &first, t, js, sz) < 0) {
|
|
||||||
jsmnparse_free(p);
|
|
||||||
first = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Call through to free parse contents.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
json_free(struct jsmnn *first)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (first != NULL)
|
|
||||||
jsmnparse_free(first->p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Just check that the array object is in fact an object.
|
|
||||||
*/
|
|
||||||
struct jsmnn *
|
|
||||||
json_getarrayobj(struct jsmnn *n)
|
|
||||||
{
|
|
||||||
|
|
||||||
return n->type != JSMN_OBJECT ? NULL : n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extract an array from the returned JSON object, making sure that it's
|
|
||||||
* the correct type.
|
|
||||||
* Returns NULL on failure.
|
|
||||||
*/
|
|
||||||
struct jsmnn *
|
|
||||||
json_getarray(struct jsmnn *n, const char *name)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (n->type != JSMN_OBJECT)
|
|
||||||
return NULL;
|
|
||||||
for (i = 0; i < n->fields; i++) {
|
|
||||||
if (n->d.obj[i].lhs->type != JSMN_STRING &&
|
|
||||||
n->d.obj[i].lhs->type != JSMN_PRIMITIVE)
|
|
||||||
continue;
|
|
||||||
else if (strcmp(name, n->d.obj[i].lhs->d.str))
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == n->fields)
|
|
||||||
return NULL;
|
|
||||||
if (n->d.obj[i].rhs->type != JSMN_ARRAY)
|
|
||||||
return NULL;
|
|
||||||
return n->d.obj[i].rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extract a single string from the returned JSON object, making sure
|
|
||||||
* that it's the correct type.
|
|
||||||
* Returns NULL on failure.
|
|
||||||
*/
|
|
||||||
char *
|
|
||||||
json_getstr(struct jsmnn *n, const char *name)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
char *cp;
|
|
||||||
|
|
||||||
if (n->type != JSMN_OBJECT)
|
|
||||||
return NULL;
|
|
||||||
for (i = 0; i < n->fields; i++) {
|
|
||||||
if (n->d.obj[i].lhs->type != JSMN_STRING &&
|
|
||||||
n->d.obj[i].lhs->type != JSMN_PRIMITIVE)
|
|
||||||
continue;
|
|
||||||
else if (strcmp(name, n->d.obj[i].lhs->d.str))
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i == n->fields)
|
|
||||||
return NULL;
|
|
||||||
if (n->d.obj[i].rhs->type != JSMN_STRING &&
|
|
||||||
n->d.obj[i].rhs->type != JSMN_PRIMITIVE)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
cp = strdup(n->d.obj[i].rhs->d.str);
|
|
||||||
if (cp == NULL)
|
|
||||||
warn("strdup");
|
|
||||||
return cp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse an HTTP response body from a buffer of size "sz".
|
|
||||||
* Returns an opaque pointer on success, otherwise NULL on error.
|
|
||||||
*/
|
|
||||||
struct jsmnn *
|
|
||||||
json_parse(const char *buf, size_t sz)
|
|
||||||
{
|
|
||||||
struct jsmnn *n;
|
|
||||||
jsmn_parser p;
|
|
||||||
jsmntok_t *tok;
|
|
||||||
int r;
|
|
||||||
size_t tokcount;
|
|
||||||
|
|
||||||
jsmn_init(&p);
|
|
||||||
tokcount = 128;
|
|
||||||
|
|
||||||
/* Do this until we don't need any more tokens. */
|
|
||||||
again:
|
|
||||||
tok = calloc(tokcount, sizeof(jsmntok_t));
|
|
||||||
if (tok == NULL) {
|
|
||||||
warn("calloc");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Actually try to parse the JSON into the tokens. */
|
|
||||||
|
|
||||||
r = jsmn_parse(&p, buf, sz, tok, tokcount);
|
|
||||||
if (r < 0 && r == JSMN_ERROR_NOMEM) {
|
|
||||||
tokcount *= 2;
|
|
||||||
free(tok);
|
|
||||||
goto again;
|
|
||||||
} else if (r < 0) {
|
|
||||||
warnx("jsmn_parse: %d", r);
|
|
||||||
free(tok);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now parse the tokens into a tree. */
|
|
||||||
|
|
||||||
n = jsmntree_alloc(tok, buf, r);
|
|
||||||
free(tok);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
900
agent/main.c
900
agent/main.c
File diff suppressed because it is too large
Load diff
116
agent/main.h
116
agent/main.h
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
* Copyright (c) 2017 Reyk Floeter <reyk@openbsd.org>
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
|
@ -19,26 +19,10 @@
|
||||||
|
|
||||||
#include <sys/queue.h>
|
#include <sys/queue.h>
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
#include "jsmn.h"
|
|
||||||
|
|
||||||
#define DEFAULT_ENDPOINT "169.254.169.254"
|
|
||||||
#define CONNECT_TIMEOUT 10 /* in seconds */
|
|
||||||
|
|
||||||
enum cloudname {
|
|
||||||
AZURE,
|
|
||||||
CLOUDINIT,
|
|
||||||
EC2,
|
|
||||||
OPENNEBULA,
|
|
||||||
OPENSTACK
|
|
||||||
};
|
|
||||||
#define CLOUDNAMES { \
|
|
||||||
"azure", "cloudinit", "ec2", "opennebula", "openstack", NULL \
|
|
||||||
}
|
|
||||||
|
|
||||||
enum strtype {
|
enum strtype {
|
||||||
WORD,
|
WORD,
|
||||||
|
|
@ -46,13 +30,6 @@ enum strtype {
|
||||||
TEXT
|
TEXT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum state {
|
|
||||||
STATE_INIT,
|
|
||||||
STATE_DHCP,
|
|
||||||
STATE_169,
|
|
||||||
STATE_DONE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssh_pubkey {
|
struct ssh_pubkey {
|
||||||
char *ssh_keyval;
|
char *ssh_keyval;
|
||||||
char *ssh_keyfp;
|
char *ssh_keyfp;
|
||||||
|
|
@ -61,91 +38,26 @@ struct ssh_pubkey {
|
||||||
};
|
};
|
||||||
TAILQ_HEAD(ssh_pubkeys, ssh_pubkey);
|
TAILQ_HEAD(ssh_pubkeys, ssh_pubkey);
|
||||||
|
|
||||||
enum net_type {
|
|
||||||
NET_IP,
|
|
||||||
NET_MASK,
|
|
||||||
NET_PREFIX,
|
|
||||||
NET_MAC,
|
|
||||||
NET_MTU,
|
|
||||||
NET_GATEWAY,
|
|
||||||
NET_DNS,
|
|
||||||
NET_DNS_DOMAIN,
|
|
||||||
NET_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
struct net_addr {
|
|
||||||
enum net_type net_type;
|
|
||||||
unsigned short net_ifunit;
|
|
||||||
char *net_value;
|
|
||||||
struct sockaddr_storage net_addr;
|
|
||||||
unsigned int net_num;
|
|
||||||
|
|
||||||
TAILQ_ENTRY(net_addr) net_entry;
|
|
||||||
};
|
|
||||||
TAILQ_HEAD(net_addrs, net_addr);
|
|
||||||
|
|
||||||
struct system_config;
|
|
||||||
struct cloud {
|
|
||||||
enum cloudname cloud_name;
|
|
||||||
int (*fetch)(struct system_config *);
|
|
||||||
TAILQ_ENTRY(cloud) cloud_entry;
|
|
||||||
};
|
|
||||||
TAILQ_HEAD(clouds, cloud);
|
|
||||||
|
|
||||||
struct system_config {
|
struct system_config {
|
||||||
const char *sc_stack;
|
|
||||||
char *sc_args;
|
|
||||||
|
|
||||||
char *sc_hostname;
|
char *sc_hostname;
|
||||||
char *sc_username;
|
char *sc_username;
|
||||||
char *sc_password_plain;
|
char *sc_password;
|
||||||
char *sc_password_hash;
|
|
||||||
char *sc_pubkey;
|
char *sc_pubkey;
|
||||||
char *sc_userdata;
|
char *sc_userdata;
|
||||||
char *sc_endpoint;
|
char *sc_endpoint;
|
||||||
enum state sc_state;
|
|
||||||
struct clouds *sc_clouds;
|
|
||||||
char *sc_instance;
|
char *sc_instance;
|
||||||
int sc_timeout;
|
|
||||||
|
|
||||||
const char *sc_ovfenv;
|
const char *sc_ovfenv;
|
||||||
const char *sc_interface;
|
const char *sc_interface;
|
||||||
const char *sc_cdrom;
|
const char *sc_cdrom;
|
||||||
const char *sc_rootdisk;
|
|
||||||
int sc_mount;
|
|
||||||
|
|
||||||
struct source sc_addr;
|
struct source sc_addr;
|
||||||
struct ssh_pubkeys sc_pubkeys;
|
struct ssh_pubkeys sc_pubkeys;
|
||||||
|
|
||||||
int sc_network;
|
|
||||||
struct net_addrs sc_netaddrs;
|
|
||||||
unsigned int sc_netmtu;
|
|
||||||
|
|
||||||
int sc_nullfd;
|
int sc_nullfd;
|
||||||
int sc_dryrun;
|
|
||||||
void *sc_priv;
|
void *sc_priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct jsmnp;
|
|
||||||
struct jsmnn {
|
|
||||||
struct parse *p;
|
|
||||||
union {
|
|
||||||
char *str;
|
|
||||||
struct jsmnp *obj;
|
|
||||||
struct jsmnn **array;
|
|
||||||
} d;
|
|
||||||
size_t fields;
|
|
||||||
jsmntype_t type;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* json.c */
|
|
||||||
struct jsmnn *json_parse(const char *, size_t);
|
|
||||||
void json_free(struct jsmnn *);
|
|
||||||
struct jsmnn *json_getarrayobj(struct jsmnn *);
|
|
||||||
struct jsmnn *json_getarray(struct jsmnn *, const char *);
|
|
||||||
struct jsmnn *json_getobj(struct jsmnn *, const char *);
|
|
||||||
char *json_getstr(struct jsmnn *, const char *);
|
|
||||||
|
|
||||||
/* azure.c */
|
/* azure.c */
|
||||||
int azure(struct system_config *);
|
int azure(struct system_config *);
|
||||||
|
|
||||||
|
|
@ -153,33 +65,17 @@ int azure(struct system_config *);
|
||||||
int ec2(struct system_config *);
|
int ec2(struct system_config *);
|
||||||
int cloudinit(struct system_config *);
|
int cloudinit(struct system_config *);
|
||||||
|
|
||||||
/* opennebula.c */
|
|
||||||
int opennebula(struct system_config *);
|
|
||||||
|
|
||||||
/* openstack.c */
|
|
||||||
int openstack(struct system_config *);
|
|
||||||
|
|
||||||
/* growdisk.c */
|
|
||||||
int growdisk(struct system_config *);
|
|
||||||
|
|
||||||
/* main.c */
|
/* main.c */
|
||||||
int shell(const char *, ...);
|
int shell(const char *, ...);
|
||||||
int shellout(const char *, char **, const char *, ...);
|
int shellout(const char *, char **, const char *, ...);
|
||||||
int disable_output(struct system_config *, int);
|
int disable_output(struct system_config *, int);
|
||||||
int enable_output(struct system_config *, int, int);
|
int enable_output(struct system_config *, int, int);
|
||||||
char *get_string(const unsigned char *, size_t);
|
char *get_string(u_int8_t *, size_t);
|
||||||
char *get_line(const unsigned char *, size_t);
|
char *get_line(u_int8_t *, size_t);
|
||||||
char *get_word(const unsigned char *, size_t);
|
char *get_word(u_int8_t *, size_t);
|
||||||
int agent_addpubkey(struct system_config *, const char *, const char *);
|
int agent_addpubkey(struct system_config *, const char *, const char *);
|
||||||
int agent_setpubkey(struct system_config *, const char *, const char *);
|
int agent_setpubkey(struct system_config *, const char *, const char *);
|
||||||
struct net_addr *
|
int agent_configure(struct system_config *, int);
|
||||||
agent_getnetaddr(struct system_config *, struct net_addr *);
|
|
||||||
int agent_addnetaddr(struct system_config *, unsigned int,
|
|
||||||
const char *, int, enum net_type);
|
|
||||||
char *metadata(struct system_config *, const char *, enum strtype);
|
|
||||||
char *metadata_file(struct system_config *, const char *, enum strtype);
|
|
||||||
int connect_wait(int, const struct sockaddr *, socklen_t);
|
|
||||||
int dhcp_getendpoint(struct system_config *);
|
|
||||||
|
|
||||||
/* log.c */
|
/* log.c */
|
||||||
void log_init(int, int);
|
void log_init(int, int);
|
||||||
|
|
|
||||||
|
|
@ -1,291 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fnmatch.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <sha2.h>
|
|
||||||
#include <err.h>
|
|
||||||
#include <util.h>
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
opennebula(struct system_config *sc)
|
|
||||||
{
|
|
||||||
FILE *fp;
|
|
||||||
const char *delim = "\\\\\0", *errstr;
|
|
||||||
char *line = NULL, *k, *v, *p, q;
|
|
||||||
char *value = NULL, *next = NULL, *last;
|
|
||||||
char *hname = NULL, *uname = NULL;
|
|
||||||
size_t len, lineno = 0, i;
|
|
||||||
int ret = -1;
|
|
||||||
unsigned short unit;
|
|
||||||
|
|
||||||
if (sc->sc_state == STATE_INIT) {
|
|
||||||
sc->sc_state = STATE_169;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return silently without error */
|
|
||||||
if ((fp = fopen("/mnt/context.sh", "r")) == NULL)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
while ((line = fparseln(fp, &len, &lineno,
|
|
||||||
delim, FPARSELN_UNESCALL)) != NULL) {
|
|
||||||
/* key */
|
|
||||||
k = line + strspn(line, " \t\r");
|
|
||||||
|
|
||||||
/* a context always starts with this header */
|
|
||||||
if (lineno == 1) {
|
|
||||||
ret = strcmp(k,
|
|
||||||
"# Context variables generated by OpenNebula");
|
|
||||||
if (ret != 0) {
|
|
||||||
log_debug("%s: unsupported context", __func__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
free(line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Strip comments that do not occur within a value */
|
|
||||||
if (*k == '#') {
|
|
||||||
free(line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* value */
|
|
||||||
if ((v = strchr(line, '=')) == NULL || *(v + 1) == '\0') {
|
|
||||||
free(line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*v++ = '\0';
|
|
||||||
|
|
||||||
/* value is quoted */
|
|
||||||
q = *v;
|
|
||||||
if (strspn(v, "\"'") == 0) {
|
|
||||||
free(line);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*v++ = '\0';
|
|
||||||
|
|
||||||
/* quoted value can be continued on multiple lines */
|
|
||||||
if ((value = strdup("")) == NULL) {
|
|
||||||
log_debug("%s: strdup", __func__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
next = v;
|
|
||||||
do {
|
|
||||||
if ((p = strrchr(next, q)) != NULL)
|
|
||||||
*p++ = '\0';
|
|
||||||
if (*next) {
|
|
||||||
last = value;
|
|
||||||
if (asprintf(&value, "%s%s\n",
|
|
||||||
last, next) == -1) {
|
|
||||||
log_debug("%s: asprintf", __func__);
|
|
||||||
if (next != v)
|
|
||||||
free(next);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
free(last);
|
|
||||||
}
|
|
||||||
if (next != v)
|
|
||||||
free(next);
|
|
||||||
} while (p == NULL &&
|
|
||||||
(next = fparseln(fp, &len, &lineno,
|
|
||||||
delim, FPARSELN_UNESCALL)) != NULL);
|
|
||||||
next = NULL;
|
|
||||||
v = value;
|
|
||||||
|
|
||||||
/* strip trailing newline */
|
|
||||||
if ((p = strrchr(v, '\n')) != NULL)
|
|
||||||
*p = '\0';
|
|
||||||
|
|
||||||
/* continue if value is empty */
|
|
||||||
if (*v == '\0') {
|
|
||||||
free(line);
|
|
||||||
free(value);
|
|
||||||
value = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* print key/value unless it is a multi-line value */
|
|
||||||
if (strcasecmp("SSH_PUBLIC_KEY", k) != 0 &&
|
|
||||||
strcasecmp("START_SCRIPT", k) != 0 &&
|
|
||||||
strcasecmp("START_SCRIPT_BASE64", k) != 0)
|
|
||||||
log_debug("%s: %s = %s", __func__, k, v);
|
|
||||||
|
|
||||||
if (strcasecmp("NETWORK", k) == 0) {
|
|
||||||
if (strcasecmp("YES", v) == 0)
|
|
||||||
sc->sc_network = 1;
|
|
||||||
else if (strcasecmp("YES", v) == 0)
|
|
||||||
sc->sc_network = 0;
|
|
||||||
} else if (fnmatch("ETH*_*", k, 0) != FNM_NOMATCH) {
|
|
||||||
/* Extract interface unit */
|
|
||||||
if ((p = strdup(k + 3)) == NULL) {
|
|
||||||
log_debug("%s: %s", __func__, k);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
p[strcspn(p, "_")] = '\0';
|
|
||||||
unit = strtonum(p, 0, UINT16_MAX, &errstr);
|
|
||||||
free(p);
|
|
||||||
if (errstr != NULL) {
|
|
||||||
log_debug("%s: %s", __func__, k);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get subkey */
|
|
||||||
k += strcspn(k, "_") + 1;
|
|
||||||
|
|
||||||
if (strcasecmp("DNS", k) == 0) {
|
|
||||||
/* We don't support per-interface DNS */
|
|
||||||
for (p = v; *p != '\0'; v = p) {
|
|
||||||
p = v + strcspn(v, " \t");
|
|
||||||
*p++ = '\0';
|
|
||||||
if ((ret = agent_addnetaddr(sc, 0,
|
|
||||||
v, AF_UNSPEC, NET_DNS)) != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (strcasecmp("SEARCH_DOMAIN", k) == 0) {
|
|
||||||
for (p = v; *p != '\0'; v = p) {
|
|
||||||
p = v + strcspn(v, " \t");
|
|
||||||
*p++ = '\0';
|
|
||||||
if ((ret = agent_addnetaddr(sc, 0,
|
|
||||||
v, AF_UNSPEC, NET_DNS_DOMAIN)) != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (strcasecmp("IP", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_INET, NET_IP);
|
|
||||||
} else if (strcasecmp("MASK", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_INET, NET_MASK);
|
|
||||||
} else if (strcasecmp("GATEWAY", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_INET, NET_GATEWAY);
|
|
||||||
} else if (strcasecmp("IP6", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_INET6, NET_IP);
|
|
||||||
} else if (strcasecmp("GATEWAY6", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_INET6, NET_GATEWAY);
|
|
||||||
} else if (strcasecmp("PREFIX_LENGTH", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_INET6, NET_PREFIX);
|
|
||||||
} else if (strcasecmp("MAC", k) == 0) {
|
|
||||||
if (unit == 0 && hname == NULL) {
|
|
||||||
/* Fake a hostname using the mac */
|
|
||||||
if ((hname = p = calloc(1,
|
|
||||||
strlen(v) + 3)) == NULL) {
|
|
||||||
log_debug("%s: calloc",
|
|
||||||
__func__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
*p++ = 'v';
|
|
||||||
*p++ = 'm';
|
|
||||||
for (i = 0; i < strlen(v); i++) {
|
|
||||||
if (!isalnum(v[i]))
|
|
||||||
continue;
|
|
||||||
*p++ = v[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_UNSPEC, NET_MAC);
|
|
||||||
} else if (strcasecmp("MTU", k) == 0) {
|
|
||||||
ret = agent_addnetaddr(sc, unit,
|
|
||||||
v, AF_UNSPEC, NET_MTU);
|
|
||||||
} else
|
|
||||||
ret = 0;
|
|
||||||
if (ret != 0) {
|
|
||||||
log_debug("%s: failed to parse %s",
|
|
||||||
__func__, k);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
} else if (strcasecmp("HOSTNAME", k) == 0) {
|
|
||||||
if ((hname = strdup(v)) == NULL)
|
|
||||||
log_warnx("failed to set hostname");
|
|
||||||
} else if (strcasecmp("SSH_PUBLIC_KEY", k) == 0) {
|
|
||||||
do {
|
|
||||||
p = v + strcspn(v, "\n");
|
|
||||||
*p++ = '\0';
|
|
||||||
if (*v)
|
|
||||||
log_debug("%s: %s = %s",
|
|
||||||
__func__, k, v);
|
|
||||||
if (*v && agent_addpubkey(sc, v, NULL) != 0)
|
|
||||||
log_warnx("failed to set ssh pubkey");
|
|
||||||
v = p + strspn(p, "\n");
|
|
||||||
} while (*v != '\0');
|
|
||||||
} else if (strcasecmp("START_SCRIPT", k) == 0 ||
|
|
||||||
strcasecmp("START_SCRIPT_BASE64", k) == 0) {
|
|
||||||
log_debug("%s: %s = ...", __func__, k);
|
|
||||||
|
|
||||||
/* We will detect and decode base64 later */
|
|
||||||
if ((sc->sc_userdata = strdup(v)) == NULL)
|
|
||||||
log_warnx("failed to set userdata");
|
|
||||||
} else if (strcasecmp("USERNAME", k) == 0) {
|
|
||||||
if ((uname = strdup(v)) == NULL)
|
|
||||||
log_warnx("failed to set username");
|
|
||||||
else {
|
|
||||||
free(sc->sc_username);
|
|
||||||
sc->sc_username = uname;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(line);
|
|
||||||
free(value);
|
|
||||||
value = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
fp = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* OpenNebula doesn't provide an instance id so we
|
|
||||||
* calculate one using the hash of the context file.
|
|
||||||
* This might break if the context is not consistent.
|
|
||||||
*/
|
|
||||||
if ((sc->sc_instance =
|
|
||||||
calloc(1, SHA256_DIGEST_STRING_LENGTH)) == NULL ||
|
|
||||||
SHA256File("/mnt/context.sh", sc->sc_instance) == NULL) {
|
|
||||||
log_debug("%s: failed to calculate instance hash",
|
|
||||||
__func__);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
log_debug("%s: context instance %s", __func__, sc->sc_instance);
|
|
||||||
|
|
||||||
/* Even the hostname is optional */
|
|
||||||
if (hname != NULL) {
|
|
||||||
free(sc->sc_hostname);
|
|
||||||
sc->sc_hostname = hname;
|
|
||||||
log_debug("%s: hostname %s", __func__, hname);
|
|
||||||
}
|
|
||||||
|
|
||||||
line = NULL;
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (fp != NULL)
|
|
||||||
fclose(fp);
|
|
||||||
free(line);
|
|
||||||
free(value);
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018, 2019 Reyk Floeter <reyk@openbsd.org>
|
|
||||||
*
|
|
||||||
* Permission to use, copy, modify, and distribute this software for any
|
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
|
||||||
* copyright notice and this permission notice appear in all copies.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <sys/queue.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <err.h>
|
|
||||||
|
|
||||||
#include "main.h"
|
|
||||||
#include "http.h"
|
|
||||||
#include "xml.h"
|
|
||||||
|
|
||||||
static int openstack_fetch(struct system_config *);
|
|
||||||
|
|
||||||
int
|
|
||||||
openstack(struct system_config *sc)
|
|
||||||
{
|
|
||||||
if (sc->sc_state == STATE_INIT) {
|
|
||||||
sc->sc_state = STATE_DHCP;
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
return openstack_fetch(sc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
openstack_fetch(struct system_config *sc)
|
|
||||||
{
|
|
||||||
int ret = -1;
|
|
||||||
char *json = NULL, *str;
|
|
||||||
struct jsmnn *j = NULL, *o, *f;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
sc->sc_addr.ip = sc->sc_endpoint;
|
|
||||||
sc->sc_addr.family = 4;
|
|
||||||
|
|
||||||
/* meta_data, we don't handle vendor_data */
|
|
||||||
if ((json = metadata(sc,
|
|
||||||
"/openstack/latest/meta_data.json", TEXT)) == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if ((j = json_parse(json, strlen(json))) == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* instance-id */
|
|
||||||
if ((sc->sc_instance = json_getstr(j, "uuid")) == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* hostname */
|
|
||||||
if ((sc->sc_hostname = json_getstr(j, "hostname")) == NULL)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
/* public keys */
|
|
||||||
if ((o = json_getarray(j, "keys")) == NULL)
|
|
||||||
goto fail;
|
|
||||||
for (i = 0; i < o->fields; i++) {
|
|
||||||
if ((f = json_getarrayobj(o->d.array[i])) == NULL)
|
|
||||||
continue;
|
|
||||||
if ((str = json_getstr(f, "data")) == NULL)
|
|
||||||
continue;
|
|
||||||
if (agent_addpubkey(sc, str, NULL) != 0) {
|
|
||||||
free(str);
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
free(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* userdata (optional) */
|
|
||||||
sc->sc_userdata = metadata(sc, "/openstack/latest/user_data", TEXT);
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
fail:
|
|
||||||
json_free(j);
|
|
||||||
free(json);
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
@ -342,10 +342,9 @@ xml_parse(struct xml *env, const char *file)
|
||||||
ssize_t len;
|
ssize_t len;
|
||||||
|
|
||||||
if ((fd = open(file, O_RDONLY)) == -1) {
|
if ((fd = open(file, O_RDONLY)) == -1) {
|
||||||
log_debug("%s: failed to open %s", __func__, file);
|
log_debug("%s: open %s", __func__, file);
|
||||||
return (-1);
|
return (-1);
|
||||||
} else
|
}
|
||||||
log_debug("%s: opened %s", __func__, file);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if ((xml = XML_GetBuffer(parser, BUFSIZ)) == NULL)
|
if ((xml = XML_GetBuffer(parser, BUFSIZ)) == NULL)
|
||||||
|
|
|
||||||
150
cloud-agent.md
150
cloud-agent.md
|
|
@ -1,150 +0,0 @@
|
||||||
CLOUD-AGENT(8) - System Manager's Manual
|
|
||||||
|
|
||||||
# NAME
|
|
||||||
|
|
||||||
**cloud-agent** - cloud provisioning for OpenBSD VMs
|
|
||||||
|
|
||||||
# SYNOPSIS
|
|
||||||
|
|
||||||
**cloud-agent**
|
|
||||||
\[**-nuv**]
|
|
||||||
\[**-c** *cloud*\[,*cloud*...]]
|
|
||||||
\[**-p** *length*]
|
|
||||||
\[**-r** *rootdisk*]
|
|
||||||
\[**-t** *timeout*]
|
|
||||||
\[**-U** *username*]
|
|
||||||
*interface*
|
|
||||||
|
|
||||||
# DESCRIPTION
|
|
||||||
|
|
||||||
The
|
|
||||||
**cloud-agent**
|
|
||||||
program manages the OpenBSD provisioning and VM interaction in cloud
|
|
||||||
environments.
|
|
||||||
|
|
||||||
The options are as follows:
|
|
||||||
|
|
||||||
**-c** *cloud*\[,*cloud*...]
|
|
||||||
|
|
||||||
> Probe a list of cloud stacks for provisioning in the specified order.
|
|
||||||
> If this option is not specified,
|
|
||||||
> **cloud-agent**
|
|
||||||
> tries to detect the environment and possible cloud stacks automatically.
|
|
||||||
> Supported
|
|
||||||
> *cloud*
|
|
||||||
> stacks are:
|
|
||||||
|
|
||||||
> **azure**
|
|
||||||
|
|
||||||
> > Microsoft Azure
|
|
||||||
|
|
||||||
> **cloudinit**
|
|
||||||
|
|
||||||
> > Generic cloud-init
|
|
||||||
|
|
||||||
> **ec2**
|
|
||||||
|
|
||||||
> > Amazon AWS EC2
|
|
||||||
|
|
||||||
> **opennebula**
|
|
||||||
|
|
||||||
> > OpenNebula
|
|
||||||
|
|
||||||
> **openstack**
|
|
||||||
|
|
||||||
> > OpenStack
|
|
||||||
|
|
||||||
**-p** *length*
|
|
||||||
|
|
||||||
> Generate and set a random password for the default user.
|
|
||||||
> The password will be written in its plain form into the
|
|
||||||
> *~/.ssh/authorized\_keys*
|
|
||||||
> file.
|
|
||||||
> This allows to use the
|
|
||||||
> doas(1)
|
|
||||||
> command to gain root privileges.
|
|
||||||
> The minimum
|
|
||||||
> *length*
|
|
||||||
> is 8 characters and the default is an empty password.
|
|
||||||
|
|
||||||
**-n**
|
|
||||||
|
|
||||||
> Do not configure the system and skip the provisioning step.
|
|
||||||
|
|
||||||
**-t** *timeout*
|
|
||||||
|
|
||||||
> Change the HTTP timeout.
|
|
||||||
> The default is 3 seconds.
|
|
||||||
|
|
||||||
**-U** *username*
|
|
||||||
|
|
||||||
> Change the default user.
|
|
||||||
> The default is
|
|
||||||
> "ec2-user"
|
|
||||||
> on AWS,
|
|
||||||
> "azure-user"
|
|
||||||
> on Azure, and
|
|
||||||
> "puffy"
|
|
||||||
> everywhere else.
|
|
||||||
> The default user is used when it is not obtained from the cloud
|
|
||||||
> configuration.
|
|
||||||
> Using
|
|
||||||
> "root"
|
|
||||||
> is supported, but not recommended.
|
|
||||||
|
|
||||||
**-r** *rootdisk*
|
|
||||||
|
|
||||||
> Automatically grow the last
|
|
||||||
> OpenBSD
|
|
||||||
> FFS partition of the root disk to use all the available space.
|
|
||||||
|
|
||||||
**-u**
|
|
||||||
|
|
||||||
> Deprovision and unconfigure the system.
|
|
||||||
> This deletes keys, passwords, and logs files without asking for permission.
|
|
||||||
|
|
||||||
**-v**
|
|
||||||
|
|
||||||
> Produce more verbose output.
|
|
||||||
|
|
||||||
Enable
|
|
||||||
**cloud-agent**
|
|
||||||
in the
|
|
||||||
hostname.if(5)
|
|
||||||
of the VM's primary networking interface and automatically the last
|
|
||||||
partition of the root disk:
|
|
||||||
|
|
||||||
# cat /etc/hostname.hvn0
|
|
||||||
dhcp
|
|
||||||
!/usr/local/libexec/cloud-agent -r sd0 "\$if"
|
|
||||||
|
|
||||||
# FILES
|
|
||||||
|
|
||||||
*~/.ssh/authorized\_keys*
|
|
||||||
|
|
||||||
> The location of the agent-configured SSH public keys and optional password.
|
|
||||||
|
|
||||||
*/usr/local/libexec/cloud-agent*
|
|
||||||
|
|
||||||
> The agent itself.
|
|
||||||
|
|
||||||
*/usr/local/bin/cms*
|
|
||||||
|
|
||||||
> The CMS binary that is used to decrypt messages from the Azure fabric.
|
|
||||||
|
|
||||||
*/var/db/cloud-instance*
|
|
||||||
|
|
||||||
> The instance ID as reported by the cloud.
|
|
||||||
> **cloud-agent**
|
|
||||||
> reprovisions the system when the value has changed.
|
|
||||||
|
|
||||||
# SEE ALSO
|
|
||||||
|
|
||||||
meta-data(8),
|
|
||||||
vmd(8)
|
|
||||||
|
|
||||||
# AUTHORS
|
|
||||||
|
|
||||||
Reyk Floeter <[reyk@openbsd.org](mailto:reyk@openbsd.org)>
|
|
||||||
|
|
||||||
OpenBSD 6.5 - June 26, 2019
|
|
||||||
|
|
@ -80,13 +80,6 @@ DECLARE_ASN1_FUNCTIONS(CMS_ContentInfo)
|
||||||
DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
|
DECLARE_ASN1_FUNCTIONS(CMS_ReceiptRequest)
|
||||||
DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
|
DECLARE_ASN1_PRINT_FUNCTION(CMS_ContentInfo)
|
||||||
|
|
||||||
#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20900000L
|
|
||||||
#define M_ASN1_new_of(type) \
|
|
||||||
(type *)ASN1_item_new(ASN1_ITEM_rptr(type))
|
|
||||||
#define M_ASN1_free_of(x, type) \
|
|
||||||
ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# define CMS_SIGNERINFO_ISSUER_SERIAL 0
|
# define CMS_SIGNERINFO_ISSUER_SERIAL 0
|
||||||
# define CMS_SIGNERINFO_KEYIDENTIFIER 1
|
# define CMS_SIGNERINFO_KEYIDENTIFIER 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -353,11 +353,7 @@ void cms_DigestAlgorithm_set(X509_ALGOR *alg, const EVP_MD *md)
|
||||||
BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
|
BIO *cms_DigestAlgorithm_init_bio(X509_ALGOR *digestAlgorithm)
|
||||||
{
|
{
|
||||||
BIO *mdbio = NULL;
|
BIO *mdbio = NULL;
|
||||||
#if LIBRESSL_VERSION_NUMBER >= 0x2080000fL
|
|
||||||
const ASN1_OBJECT *digestoid;
|
|
||||||
#else
|
|
||||||
ASN1_OBJECT *digestoid;
|
ASN1_OBJECT *digestoid;
|
||||||
#endif
|
|
||||||
const EVP_MD *digest;
|
const EVP_MD *digest;
|
||||||
X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
|
X509_ALGOR_get0(&digestoid, NULL, NULL, digestAlgorithm);
|
||||||
digest = EVP_get_digestbyobj(digestoid);
|
digest = EVP_get_digestbyobj(digestoid);
|
||||||
|
|
@ -384,11 +380,7 @@ int cms_DigestAlgorithm_find_ctx(EVP_MD_CTX *mctx, BIO *chain,
|
||||||
X509_ALGOR *mdalg)
|
X509_ALGOR *mdalg)
|
||||||
{
|
{
|
||||||
int nid;
|
int nid;
|
||||||
#if LIBRESSL_VERSION_NUMBER >= 0x2080000fL
|
|
||||||
const ASN1_OBJECT *mdoid;
|
|
||||||
#else
|
|
||||||
ASN1_OBJECT *mdoid;
|
ASN1_OBJECT *mdoid;
|
||||||
#endif
|
|
||||||
X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
|
X509_ALGOR_get0(&mdoid, NULL, NULL, mdalg);
|
||||||
nid = OBJ_obj2nid(mdoid);
|
nid = OBJ_obj2nid(mdoid);
|
||||||
/* Look for digest type to match signature */
|
/* Look for digest type to match signature */
|
||||||
|
|
|
||||||
|
|
@ -328,11 +328,7 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms,
|
||||||
|
|
||||||
/* See if digest is present in digestAlgorithms */
|
/* See if digest is present in digestAlgorithms */
|
||||||
for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) {
|
for (i = 0; i < sk_X509_ALGOR_num(sd->digestAlgorithms); i++) {
|
||||||
#if LIBRESSL_VERSION_NUMBER >= 0x2080000fL
|
|
||||||
const ASN1_OBJECT *aoid;
|
|
||||||
#else
|
|
||||||
ASN1_OBJECT *aoid;
|
ASN1_OBJECT *aoid;
|
||||||
#endif
|
|
||||||
alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
|
alg = sk_X509_ALGOR_value(sd->digestAlgorithms, i);
|
||||||
X509_ALGOR_get0(&aoid, NULL, NULL, alg);
|
X509_ALGOR_get0(&aoid, NULL, NULL, alg);
|
||||||
if (OBJ_obj2nid(aoid) == EVP_MD_type(md))
|
if (OBJ_obj2nid(aoid) == EVP_MD_type(md))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue