libnetconf2 CHANGE QNX compatibility (#220)

fixes #217
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ad7880a..f43ef03 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -251,8 +251,13 @@
     include_directories(${LIBSSH_INCLUDE_DIRS})
 
     # crypt
-    target_link_libraries(netconf2 -lcrypt)
-    list(APPEND CMAKE_REQUIRED_LIBRARIES crypt)
+    if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "QNX")
+        target_link_libraries(netconf2 -lcrypt)
+        list(APPEND CMAKE_REQUIRED_LIBRARIES crypt)
+    else()
+        target_link_libraries(netconf2 -llogin)
+        list(APPEND CMAKE_REQUIRED_LIBRARIES login)
+    endif()
 endif()
 
 # dependencies - libval
@@ -268,6 +273,20 @@
 target_link_libraries(netconf2 ${LIBYANG_LIBRARIES})
 include_directories(${LIBYANG_INCLUDE_DIRS})
 
+# header file compatibility - shadow.h and crypt.h
+check_include_file("shadow.h" HAVE_SHADOW)
+check_include_file("crypt.h" HAVE_CRYPT)
+
+# function compatibility - getpeereid on QNX
+if(${CMAKE_SYSTEM_NAME} MATCHES "QNX")
+    target_link_libraries(netconf2 -lsocket)
+    list(APPEND CMAKE_REQUIRED_LIBRARIES socket)
+    list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES pthread)
+    list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_QNX_SOURCE)
+    check_symbol_exists(getpeereid "sys/types.h;unistd.h" HAVE_GETPEEREID)
+    list(REMOVE_ITEM CMAKE_REQUIRED_DEFINITIONS -D_QNX_SOURCE)
+endif()
+
 # generate doxygen documentation for libnetconf2 API
 find_package(Doxygen)
 if(DOXYGEN_FOUND)
diff --git a/src/config.h.in b/src/config.h.in
index b69c8bd..0f0bbcc 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -48,6 +48,21 @@
 #cmakedefine HAVE_PTHREAD_MUTEX_TIMEDLOCK
 
 /*
+ * Support for getpeereid
+ */
+#cmakedefine HAVE_GETPEEREID
+
+/*
+ * Support for shadow file manipulation
+ */
+#cmakedefine HAVE_SHADOW
+
+/*
+ * Support for crypt.h
+ */
+#cmakedefine HAVE_CRYPT
+
+/*
  * Location of installed basic YIN/YANG schemas
  */
 #define NC_SCHEMAS_DIR "@SCHEMAS_DIR@"
diff --git a/src/session_server.c b/src/session_server.c
index 030ccf0..264a34c 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -11,6 +11,7 @@
  *
  *     https://opensource.org/licenses/BSD-3-Clause
  */
+#define _QNX_SOURCE /* getpeereid */
 #define _GNU_SOURCE /* signals, threads, SO_PEERCRED */
 
 #include <stdint.h>
@@ -1718,26 +1719,47 @@
 #if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
 
 static int
+nc_get_uid(int sock, uid_t *uid)
+{
+    #ifdef SO_PEERCRED
+        struct ucred ucred;
+        socklen_t len;
+        len = sizeof(ucred);
+        if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
+            ERR("Failed to get credentials from unix socket (%s).",
+                strerror(errno));
+            close(sock);
+            return -1;
+        }
+        *uid = ucred.uid;
+    #else
+        if (getpeereid(sock, uid, NULL) < 0) {
+            ERR("Failed to get credentials from unix socket (%s).",
+                strerror(errno));
+            close(sock);
+            return -1;
+        }
+    #endif
+
+    return 0;
+}
+
+static int
 nc_accept_unix(struct nc_session *session, int sock)
 {
-#ifdef SO_PEERCRED
+#if defined(SO_PEERCRED) || defined(HAVE_GETPEEREID)
     const struct passwd *pw;
-    struct ucred ucred;
     char *username;
-    socklen_t len;
     session->ti_type = NC_TI_UNIX;
+    uid_t uid;
 
-    len = sizeof(ucred);
-    if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) {
-        ERR("Failed to get credentials from unix socket (%s).",
-            strerror(errno));
-        close(sock);
+    if (nc_get_uid(sock, &uid) < 0) {
         return -1;
     }
 
-    pw = getpwuid(ucred.uid);
+    pw = getpwuid(uid);
     if (pw == NULL) {
-        ERR("Failed to find username for uid=%u (%s).\n", ucred.uid,
+        ERR("Failed to find username for uid=%u (%s).\n", uid,
             strerror(errno));
         close(sock);
         return -1;
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index 412fbac..215d2c6 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -14,21 +14,25 @@
 
 #define _GNU_SOURCE
 
+#include "config.h" /* Expose HAVE_SHADOW and HAVE_CRYPT */
+
+#ifdef HAVE_SHADOW
+    #include <shadow.h>
+#endif
+#ifdef HAVE_CRYPT
+    #include <crypt.h>
+#endif
+
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <pwd.h>
-#ifndef __APPLE__
-#include <shadow.h>
-#include <crypt.h>
-#endif
 #include <errno.h>
 #include <time.h>
 #include <fcntl.h>
 #include <unistd.h>
 
-#include "config.h"
 #include "session_server.h"
 #include "session_server_ch.h"
 #include "libnetconf.h"
@@ -664,7 +668,7 @@
 static char *
 auth_password_get_pwd_hash(const char *username)
 {
-#ifndef __APPLE__
+#ifdef HAVE_SHADOW
     struct passwd *pwd, pwd_buf;
     struct spwd *spwd, spwd_buf;
     char *pass_hash = NULL, buf[256];
@@ -676,7 +680,11 @@
     }
 
     if (!strcmp(pwd->pw_passwd, "x")) {
-        getspnam_r(username, &spwd_buf, buf, 256, &spwd);
+        #ifndef __QNXNTO__
+            getspnam_r(username, &spwd_buf, buf, 256, &spwd);
+        #else
+            spwd = getspnam_r(username, &spwd_buf, buf, 256);
+        #endif
         if (!spwd) {
             VRB("Failed to retrieve the shadow entry for \"%s\".", username);
             return NULL;