Merge pull request #19 from jktjkt/ssl-memleak-comp-methods

session BUGFIX fix memleak in OpenSSL uninitialization
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 52a1c38..f1f7375 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,7 +38,7 @@
 # set version
 set(LIBNETCONF2_MAJOR_VERSION 0)
 set(LIBNETCONF2_MINOR_VERSION 7)
-set(LIBNETCONF2_MICRO_VERSION 37)
+set(LIBNETCONF2_MICRO_VERSION 38)
 set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION})
 set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION})
 
diff --git a/src/session_client.c b/src/session_client.c
index 8ac22f3..dfc4a36 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -65,19 +65,15 @@
 
 /* SCHEMAS_DIR not used (implicitly) */
 static int
-ctx_check_and_load_model(struct nc_session *session, const char *cpblt)
+ctx_check_and_load_model(struct nc_session *session, const char *module_cpblt)
 {
     const struct lys_module *module;
     char *ptr, *ptr2;
     char *model_name, *revision = NULL, *features = NULL;
 
-    /* parse module */
-    ptr = strstr(cpblt, "module=");
-    if (!ptr) {
-        ERR("Unknown capability \"%s\" could not be parsed.", cpblt);
-        return -1;
-    }
-    ptr += 7;
+    assert(!strncmp(module_cpblt, "module=", 7));
+
+    ptr = (char *)module_cpblt + 7;
     ptr2 = strchr(ptr, '&');
     if (!ptr2) {
         ptr2 = ptr + strlen(ptr);
@@ -85,7 +81,7 @@
     model_name = strndup(ptr, ptr2 - ptr);
 
     /* parse revision */
-    ptr = strstr(cpblt, "revision=");
+    ptr = strstr(module_cpblt, "revision=");
     if (ptr) {
         ptr += 9;
         ptr2 = strchr(ptr, '&');
@@ -110,7 +106,7 @@
     free(model_name);
 
     /* parse features */
-    ptr = strstr(cpblt, "features=");
+    ptr = strstr(module_cpblt, "features=");
     if (ptr) {
         ptr += 9;
         ptr2 = strchr(ptr, '&');
@@ -293,6 +289,7 @@
 int
 nc_ctx_check_and_fill(struct nc_session *session)
 {
+    const char *module_cpblt;
     int i, get_schema_support = 0, ret = 0, r;
     ly_module_clb old_clb = NULL;
     void *old_data = NULL;
@@ -328,42 +325,41 @@
 
     /* load all other models */
     for (i = 0; session->cpblts[i]; ++i) {
-        if (!strncmp(session->cpblts[i], "urn:ietf:params:netconf:capability", 34)
-                || !strncmp(session->cpblts[i], "urn:ietf:params:netconf:base", 28)) {
-            continue;
-        }
-
-        r = ctx_check_and_load_model(session, session->cpblts[i]);
-        if (r == -1) {
-            ret = -1;
-            break;
-        }
-
-        /* failed to load schema, but let's try to find it using user callback (or locally, if not set),
-         * if it was using get-schema */
-        if (r == 1) {
-            if (get_schema_support) {
-                VRB("Trying to load the schema from a different source.");
-                /* works even if old_clb is NULL */
-                ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
-                r = ctx_check_and_load_model(session, session->cpblts[i]);
+        module_cpblt = strstr(session->cpblts[i], "module=");
+        /* this capability requires a module */
+        if (module_cpblt) {
+            r = ctx_check_and_load_model(session, module_cpblt);
+            if (r == -1) {
+                ret = -1;
+                break;
             }
 
-            /* fail again (or no other way to try), too bad */
-            if (r) {
-                ret = 1;
-            }
+            /* failed to load schema, but let's try to find it using user callback (or locally, if not set),
+            * if it was using get-schema */
+            if (r == 1) {
+                if (get_schema_support) {
+                    VRB("Trying to load the schema from a different source.");
+                    /* works even if old_clb is NULL */
+                    ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
+                    r = ctx_check_and_load_model(session, module_cpblt);
+                }
 
-            /* set get-schema callback back */
-            ly_ctx_set_module_clb(session->ctx, &libyang_module_clb, session);
+                /* fail again (or no other way to try), too bad */
+                if (r) {
+                    session->flags |= NC_SESSION_CLIENT_NOT_STRICT;
+                }
+
+                /* set get-schema callback back */
+                ly_ctx_set_module_clb(session->ctx, &libyang_module_clb, session);
+            }
         }
     }
 
     if (old_clb) {
         ly_ctx_set_module_clb(session->ctx, old_clb, old_data);
     }
-    if (ret == 1) {
-        WRN("Some models failed to be loaded, any data from these models will be ignored.");
+    if (session->flags & NC_SESSION_CLIENT_NOT_STRICT) {
+        WRN("Some models failed to be loaded, any data from these models (and any other unknown) will be ignored.");
     }
     return ret;
 }
@@ -1143,6 +1139,9 @@
         return NC_MSG_ERROR;
     }
     parseroptions &= ~(LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS);
+    if (!(session->flags & NC_SESSION_CLIENT_NOT_STRICT)) {
+        parseroptions &= LYD_OPT_STRICT;
+    }
     *reply = NULL;
 
     msgtype = get_msg(session, timeout, msgid, &xml);
@@ -1200,7 +1199,8 @@
         }
 
         /* notification body */
-        (*notif)->tree = lyd_parse_xml(session->ctx, &xml->child, LYD_OPT_NOTIF | LYD_OPT_DESTRUCT, NULL);
+        (*notif)->tree = lyd_parse_xml(session->ctx, &xml->child, LYD_OPT_NOTIF | LYD_OPT_DESTRUCT
+                                       | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL);
         lyxml_free(session->ctx, xml);
         xml = NULL;
         if (!(*notif)->tree) {
@@ -1357,7 +1357,8 @@
         if (rpc_gen->has_data) {
             data = rpc_gen->content.data;
         } else {
-            data = lyd_parse_mem(session->ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC | LYD_OPT_STRICT, NULL);
+            data = lyd_parse_mem(session->ctx, rpc_gen->content.xml_str, LYD_XML, LYD_OPT_RPC
+                                 | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL);
         }
         break;
 
@@ -1777,7 +1778,7 @@
         return NC_MSG_ERROR;
     }
 
-    if (lyd_validate(&data, LYD_OPT_RPC | LYD_OPT_STRICT, NULL)) {
+    if (lyd_validate(&data, LYD_OPT_RPC | (session->flags & NC_SESSION_CLIENT_NOT_STRICT ? 0 : LYD_OPT_STRICT), NULL)) {
         lyd_free(data);
         return NC_MSG_ERROR;
     }
diff --git a/src/session_p.h b/src/session_p.h
index bb662ae..061690d 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -267,9 +267,13 @@
     struct nc_msg_cont *replies;   /**< queue for RPC replies received instead of notifications */
     struct nc_msg_cont *notifs;    /**< queue for notifications received instead of RPC reply */
 
+    /* some server modules failed to load so the data from them will be ignored - not use strict flag for parsing */
+#   define NC_SESSION_CLIENT_NOT_STRICT 0x40
+
     /* server side only data */
     time_t session_start;          /**< time the session was created */
     time_t last_rpc;               /**< time the last RPC was received on this session */
+
 #ifdef NC_ENABLED_SSH
     /* SSH session authenticated */
 #   define NC_SESSION_SSH_AUTHENTICATED 0x04