configuration UPDATE auth user YANG data creation
New API function, which creates the 'client-authentication' subtree of
ietf-netconf-server module, added. Only public key configuration is
supported for now. SSH authentication bugfix.
diff --git a/src/config_new.c b/src/config_new.c
index 24db6f0..b3ba1d2 100644
--- a/src/config_new.c
+++ b/src/config_new.c
@@ -22,13 +22,16 @@
#include <stdlib.h>
#include <string.h>
+#include <openssl/buffer.h>
#include <openssl/err.h>
+#include <openssl/evp.h>
#include <openssl/pem.h>
#include "compat.h"
#include "config_new.h"
#include "libnetconf.h"
#include "server_config.h"
+#include "session_server.h"
static int
nc_server_config_ssh_new_get_keys(const char *privkey_path, const char *pubkey_path,
@@ -258,6 +261,12 @@
goto cleanup;
}
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
+
cleanup:
EVP_PKEY_free(priv_pkey);
free(priv_key);
@@ -272,7 +281,7 @@
{
int ret = 0;
char *tree_path = NULL;
- struct lyd_node *new_tree;
+ struct lyd_node *new_tree, *port_node;
if (!address || !port || !ctx || !endpt_name || !config) {
ERRARG("args");
@@ -297,9 +306,13 @@
*config = new_tree;
}
- /* lyd_new_path sets the out param to the first node created,
- * so in case the original tree was empty new_tree has to be set correctly */
- ret = lyd_find_path(new_tree, tree_path, 0, &new_tree);
+ if (!new_tree) {
+ /* no new nodes were created */
+ ret = lyd_find_path(*config, tree_path, 0, &new_tree);
+ } else {
+ /* config was NULL */
+ ret = lyd_find_path(new_tree, tree_path, 0, &new_tree);
+ }
if (ret) {
ERR(NULL, "Unable to find tcp-server-parameters container.");
goto cleanup;
@@ -310,11 +323,22 @@
goto cleanup;
}
- ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL);
+ ret = lyd_find_path(new_tree, "local-port", 0, &port_node);
+ if (!ret) {
+ ret = lyd_change_term(port_node, port);
+ } else if (ret == LY_ENOTFOUND) {
+ ret = lyd_new_term(new_tree, NULL, "local-port", port, 0, NULL);
+ }
+
if (ret) {
goto cleanup;
}
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
cleanup:
free(tree_path);
return ret;
@@ -343,6 +367,14 @@
goto cleanup;
}
+ if (!*alg_tree) {
+ /* no new nodes added */
+ ret = lyd_find_path(config, tree_path, 0, alg_tree);
+ if (ret) {
+ goto cleanup;
+ }
+ }
+
cleanup:
free(tree_path);
return ret;
@@ -440,6 +472,11 @@
goto cleanup;
}
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
cleanup:
return ret;
}
@@ -468,6 +505,11 @@
goto cleanup;
}
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
cleanup:
return ret;
}
@@ -496,6 +538,11 @@
goto cleanup;
}
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
cleanup:
return ret;
}
@@ -524,6 +571,275 @@
goto cleanup;
}
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
cleanup:
return ret;
}
+
+static int
+nc_server_config_ssh_read_openssh_pubkey(FILE *f, char **pubkey)
+{
+ int ret = 0;
+ char *buffer = NULL;
+ size_t len = 0;
+ char *start, *end;
+
+ if (getline(&buffer, &len, f) < 0) {
+ ERR(NULL, "Reading line from file failed.");
+ return 1;
+ }
+
+ if (len < 8) {
+ ERR(NULL, "Unexpected public key format.");
+ ret = 1;
+ goto cleanup;
+ }
+
+ start = buffer;
+ if (!strncmp(buffer, "ssh-rsa ", 8)) {
+ start += strlen("ssh-rsa ");
+ end = strchr(start, ' ');
+ if (!end) {
+ ERR(NULL, "Unexpected public key format.");
+ ret = 1;
+ goto cleanup;
+ }
+
+ *pubkey = strdup(start);
+ if (!*pubkey) {
+ ERRMEM;
+ ret = 1;
+ goto cleanup;
+ }
+
+ (*pubkey)[strlen(*pubkey) - strlen(end)] = '\0';
+ }
+
+cleanup:
+ free(buffer);
+ return ret;
+}
+
+static int
+nc_server_config_ssh_read_ssh2_pubkey(FILE *f, char **pubkey)
+{
+ char *buffer = NULL;
+ size_t len = 0;
+ size_t pubkey_len = 0;
+ void *tmp;
+
+ while (getline(&buffer, &len, f) > 0) {
+ if (!strncmp(buffer, "----", 4)) {
+ free(buffer);
+ buffer = NULL;
+ continue;
+ }
+
+ if (!strncmp(buffer, "Comment:", 8)) {
+ free(buffer);
+ buffer = NULL;
+ continue;
+ }
+
+ len = strlen(buffer);
+
+ tmp = realloc(*pubkey, pubkey_len + len + 1);
+ if (!tmp) {
+ ERRMEM;
+ free(buffer);
+ buffer = NULL;
+ return 1;
+ }
+
+ *pubkey = tmp;
+ memcpy(*pubkey + pubkey_len, buffer, len);
+ pubkey_len += len;
+ free(buffer);
+ buffer = NULL;
+ }
+
+ if (!pubkey_len) {
+ ERR(NULL, "Unexpected public key format.");
+ return 1;
+ }
+
+ (*pubkey)[pubkey_len - 1] = '\0';
+ free(buffer);
+ return 0;
+}
+
+static int
+nc_server_config_ssh_read_subject_pubkey(FILE *f, char **pubkey)
+{
+ int ret = 0;
+ EVP_PKEY *pkey;
+ BIO *bio;
+ BUF_MEM *mem;
+ char *tmp;
+
+ pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
+ if (!pkey) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ bio = BIO_new(BIO_s_mem());
+ if (!bio) {
+ ret = -1;
+ goto cleanup;
+ }
+
+ ret = PEM_write_bio_PUBKEY(bio, pkey);
+ if (!ret) {
+ ret = -1;
+ goto cleanup;
+ }
+ ret = 0;
+
+ BIO_get_mem_ptr(bio, &mem);
+ tmp = malloc(mem->length + 1);
+ if (!tmp) {
+ ERRMEM;
+ ret = 1;
+ goto cleanup;
+ }
+
+ memcpy(tmp, mem->data, mem->length);
+ tmp[mem->length] = '\0';
+
+ *pubkey = strdup(tmp + strlen("-----BEGIN PUBLIC KEY-----\n"));
+ (*pubkey)[strlen(*pubkey) - strlen("\n-----END PUBLIC KEY-----\n")] = '\0';
+
+cleanup:
+ if (ret == -1) {
+ ERR(NULL, "Error getting public key from file (OpenSSL Error): \"%s\".", ERR_reason_error_string(ERR_get_error()));
+ ret = 1;
+ }
+
+ BIO_free(bio);
+ EVP_PKEY_free(pkey);
+ free(tmp);
+
+ return ret;
+}
+
+static int
+nc_server_config_ssh_new_get_pubkey(const char *pubkey_path, char **pubkey, NC_SSH_PUBKEY_TYPE *pubkey_type)
+{
+ int ret = 0;
+ FILE *f = NULL;
+ char *buffer = NULL;
+ size_t len = 0;
+
+ *pubkey = NULL;
+
+ f = fopen(pubkey_path, "r");
+ if (!f) {
+ ERR(NULL, "Unable to open file \"%s\".", pubkey_path);
+ ret = 1;
+ goto cleanup;
+ }
+
+ if (getline(&buffer, &len, f) < 0) {
+ ERR(NULL, "Error reading header from file \"%s\".", pubkey_path);
+ ret = 1;
+ goto cleanup;
+ }
+
+ rewind(f);
+
+ if (!strncmp(buffer, "-----BEGIN PUBLIC KEY-----\n", strlen("-----BEGIN PUBLIC KEY-----\n"))) {
+ ret = nc_server_config_ssh_read_subject_pubkey(f, pubkey);
+ *pubkey_type = NC_SSH_PUBKEY_X509;
+ } else if (!strncmp(buffer, "---- BEGIN SSH2 PUBLIC KEY ----\n", strlen("---- BEGIN SSH2 PUBLIC KEY ----\n"))) {
+ ret = nc_server_config_ssh_read_ssh2_pubkey(f, pubkey);
+ *pubkey_type = NC_SSH_PUBKEY_SSH2;
+ } else {
+ ret = nc_server_config_ssh_read_openssh_pubkey(f, pubkey);
+ *pubkey_type = NC_SSH_PUBKEY_SSH2;
+ }
+
+ if (ret) {
+ ERR(NULL, "Error getting public key from file \"%s\".", pubkey_path);
+ goto cleanup;
+ }
+
+cleanup:
+ if (f) {
+ fclose(f);
+ }
+
+ free(buffer);
+
+ return ret;
+}
+
+API int
+nc_server_config_ssh_new_user(const char *pubkey_path, const struct ly_ctx *ctx, const char *endpt_name,
+ const char *user_name, const char *pubkey_name, struct lyd_node **config)
+{
+ int ret = 0;
+ char *pubkey = NULL, *tree_path = NULL;
+ struct lyd_node *new_tree;
+ NC_SSH_PUBKEY_TYPE pubkey_type;
+
+ ret = nc_server_config_ssh_new_get_pubkey(pubkey_path, &pubkey, &pubkey_type);
+ if (ret) {
+ goto cleanup;
+ }
+
+ /* prepare path where leaves will get inserted */
+ asprintf(&tree_path, "/ietf-netconf-server:netconf-server/listen/endpoint[name='%s']/ssh/ssh-server-parameters/client-authentication/"
+ "users/user[name='%s']/public-keys/local-definition/public-key[name='%s']", endpt_name, user_name, pubkey_name);
+ if (!tree_path) {
+ ERRMEM;
+ ret = 1;
+ goto cleanup;
+ }
+
+ /* create all the nodes in the path if they weren't there */
+ ret = lyd_new_path(*config, ctx, tree_path, NULL, LYD_NEW_PATH_UPDATE, &new_tree);
+ if (ret) {
+ goto cleanup;
+ }
+ if (!*config) {
+ *config = new_tree;
+ }
+
+ /* find the node where leaves will get inserted */
+ ret = lyd_find_path(*config, tree_path, 0, &new_tree);
+ if (ret) {
+ goto cleanup;
+ }
+
+ /* insert pubkey format */
+ if (pubkey_type == NC_SSH_PUBKEY_SSH2) {
+ ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:ssh-public-key-format", 0, NULL);
+ } else {
+ ret = lyd_new_term(new_tree, NULL, "public-key-format", "ietf-crypto-types:subject-public-key-info-format", 0, NULL);
+ }
+ if (ret) {
+ goto cleanup;
+ }
+
+ /* insert pubkey b64 */
+ ret = lyd_new_term(new_tree, NULL, "public-key", pubkey, 0, NULL);
+ if (ret) {
+ goto cleanup;
+ }
+
+ /* Add all default nodes */
+ ret = lyd_new_implicit_tree(*config, LYD_IMPLICIT_NO_STATE, NULL);
+ if (ret) {
+ goto cleanup;
+ }
+
+cleanup:
+ free(tree_path);
+ free(pubkey);
+ return ret;
+}