server session FEATURE arbitrary size pwd and spwd entries
diff --git a/src/session_server_ssh.c b/src/session_server_ssh.c
index c84328c..b97c39f 100644
--- a/src/session_server_ssh.c
+++ b/src/session_server_ssh.c
@@ -677,32 +677,98 @@
     nc_server_ssh_del_hostkey(NULL, -1, opts);
 }
 
+#ifdef HAVE_SHADOW
+
+static struct passwd *
+auth_password_getpwnam(const char *username, struct passwd *pwd_buf, char **buf, size_t *buf_size)
+{
+    struct passwd *pwd = NULL;
+    char *mem;
+
+    do {
+        errno = 0;
+        getpwnam_r(username, pwd_buf, *buf, *buf_size, &pwd);
+        if (pwd) {
+            /* entry found */
+            break;
+        }
+
+        if (errno == ERANGE) {
+            /* small buffer, enlarge */
+            *buf_size <<= 2;
+            mem = realloc(*buf, *buf_size);
+            if (!mem) {
+                ERRMEM;
+                return NULL;
+            }
+            *buf = mem;
+        }
+    } while (errno == ERANGE);
+
+    return pwd;
+}
+
+static struct spwd *
+auth_password_getspnam(const char *username, struct spwd *spwd_buf, char **buf, size_t *buf_size)
+{
+    struct spwd *spwd = NULL;
+    char *mem;
+
+    do {
+        errno = 0;
+# ifndef __QNXNTO__
+        getspnam_r(username, spwd_buf, *buf, *buf_size, &spwd);
+# else
+        spwd = getspnam_r(username, spwd_buf, *buf, *buf_size);
+# endif
+        if (spwd) {
+            /* entry found */
+            break;
+        }
+
+        if (errno == ERANGE) {
+            /* small buffer, enlarge */
+            *buf_size <<= 2;
+            mem = realloc(*buf, *buf_size);
+            if (!mem) {
+                ERRMEM;
+                return NULL;
+            }
+            *buf = mem;
+        }
+    } while (errno == ERANGE);
+
+    return spwd;
+}
+
 static char *
 auth_password_get_pwd_hash(const char *username)
 {
-#ifdef HAVE_SHADOW
     struct passwd *pwd, pwd_buf;
     struct spwd *spwd, spwd_buf;
-    char *pass_hash = NULL, buf[256];
+    char *pass_hash = NULL, *buf = NULL;
+    size_t buf_size = 256;
 
-    getpwnam_r(username, &pwd_buf, buf, 256, &pwd);
+    buf = malloc(buf_size);
+    if (!buf) {
+        ERRMEM;
+        goto error;
+    }
+
+    pwd = auth_password_getpwnam(username, &pwd_buf, &buf, &buf_size);
     if (!pwd) {
         VRB(NULL, "User \"%s\" not found locally.", username);
-        return NULL;
+        goto error;
     }
 
     if (!strcmp(pwd->pw_passwd, "x")) {
-# ifndef __QNXNTO__
-        getspnam_r(username, &spwd_buf, buf, 256, &spwd);
-# else
-        spwd = getspnam_r(username, &spwd_buf, buf, 256);
-# endif
+        spwd = auth_password_getspnam(username, &spwd_buf, &buf, &buf_size);
         if (!spwd) {
             VRB(NULL, "Failed to retrieve the shadow entry for \"%s\".", username);
-            return NULL;
+            goto error;
         } else if ((spwd->sp_expire > -1) && (spwd->sp_expire <= (time(NULL) / (60 * 60 * 24)))) {
             WRN(NULL, "User \"%s\" account has expired.", username);
-            return NULL;
+            goto error;
         }
 
         pass_hash = spwd->sp_pwdp;
@@ -712,25 +778,38 @@
 
     if (!pass_hash) {
         ERR(NULL, "No password could be retrieved for \"%s\".", username);
-        return NULL;
+        goto error;
     }
 
     /* check the hash structure for special meaning */
     if (!strcmp(pass_hash, "*") || !strcmp(pass_hash, "!")) {
         VRB(NULL, "User \"%s\" is not allowed to authenticate using a password.", username);
-        return NULL;
+        goto error;
     }
     if (!strcmp(pass_hash, "*NP*")) {
         VRB(NULL, "Retrieving password for \"%s\" from a NIS+ server not supported.", username);
-        return NULL;
+        goto error;
     }
 
+    free(buf);
     return strdup(pass_hash);
-#else
-    return strdup("");
-#endif
+
+error:
+    free(buf);
+    return NULL;
 }
 
+#else
+
+static char *
+auth_password_get_pwd_hash(const char *username)
+{
+    (void)username;
+    return strdup("");
+}
+
+#endif
+
 static int
 auth_password_compare_pwd(const char *pass_hash, const char *pass_clear)
 {