From 77b5d99007cfef4d73d76fd6f0c26584891608e5 Mon Sep 17 00:00:00 2001
From: Daniel Markstedt <daniel@mindani.net>
Date: Tue, 25 Jun 2024 22:39:13 +0900
Subject: [PATCH] CVE-2024-38439,CVE-2024-38440,CVE-2024-38441: Harden user
 login

* Check that input buffer can accommodate null terminator
* Input buffer null pointer and length checks

Signed-off-by: Daniel Markstedt <daniel@mindani.net>
---
 etc/afpd/auth.c         | 10 ++++++++++
 etc/afpd/directory.c    |  3 +++
 etc/uams/uams_dhx_pam.c |  4 ++++
 etc/uams/uams_pam.c     |  2 ++
 etc/uams/uams_passwd.c  |  4 ++--
 5 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c
index bba99dae562..d682ec51192 100644
--- a/etc/afpd/auth.c
+++ b/etc/afpd/auth.c
@@ -610,6 +610,9 @@ int afp_login(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbufl
     if (ibuflen < 2)
         return send_reply(obj, AFPERR_BADVERS );
 
+    if (ibuf == NULL)
+        return send_reply(obj, AFPERR_PARAM);
+
     ibuf++;
     len = (unsigned char) *ibuf++;
     ibuflen -= 2;
@@ -664,6 +667,9 @@ int afp_login_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *r
     if (ibuflen < 5)
         return send_reply(obj, AFPERR_BADVERS );
 
+    if (ibuf == NULL)
+        return send_reply(obj, AFPERR_PARAM);
+
     ibuf++;
     ibuf++;     /* pad  */
     ibuf +=2;   /* flag */
@@ -751,6 +757,10 @@ int afp_login_ext(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *r
         return send_reply(obj, AFPERR_PARAM);
     }
 #endif
+    if (ibuflen < len) {
+        LOG(log_error, logtype_afpd, "login_ext: Login failed. Invalid directory service name!" );
+        return send_reply(obj, AFPERR_PARAM);
+    }
     ibuf += len;
     ibuflen -= len;
 
diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c
index 42215b4acc1..30c754d28b8 100644
--- a/etc/afpd/directory.c
+++ b/etc/afpd/directory.c
@@ -2330,6 +2330,9 @@ int afp_mapname(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t
         return( AFPERR_PARAM );
     }
 
+    if (len >= ibuflen - 1)
+        return AFPERR_PARAM;
+
     ibuf[ len ] = '\0';
 
     if ( len == 0 )
diff --git a/etc/uams/uams_dhx_pam.c b/etc/uams/uams_dhx_pam.c
index 650059f1e04..c093eb5db5d 100644
--- a/etc/uams/uams_dhx_pam.c
+++ b/etc/uams/uams_dhx_pam.c
@@ -682,6 +682,8 @@ static int pam_changepw(void *obj, unsigned char *username,
     /* Set these things up for the conv function. the old password
      * is at the end. */
     ibuf += KEYSIZE;
+    if (ibuflen <= PASSWDLEN + PASSWDLEN)
+        return AFPERR_PARAM;
     ibuf[PASSWDLEN + PASSWDLEN] = '\0';
     PAM_password = ibuf + PASSWDLEN;
 
@@ -712,6 +714,8 @@ static int pam_changepw(void *obj, unsigned char *username,
 
     /* new password */
     PAM_password = ibuf;
+    if (ibuflen <= PASSWDLEN)
+        return AFPERR_PARAM;
     ibuf[PASSWDLEN] = '\0';
 
     /* this really does need to be done as root */
diff --git a/etc/uams/uams_pam.c b/etc/uams/uams_pam.c
index cade1a338c7..7b51cdbb8c8 100644
--- a/etc/uams/uams_pam.c
+++ b/etc/uams/uams_pam.c
@@ -141,6 +141,8 @@ static int login(void *obj, char *username, int ulen,  struct passwd **uam_pwd,
 	hostname = NULL;
     }
 
+    if (ibuflen <= PASSWDLEN)
+        return AFPERR_PARAM;
     ibuf[ PASSWDLEN ] = '\0';
 
     if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
diff --git a/etc/uams/uams_passwd.c b/etc/uams/uams_passwd.c
index 6f0be909339..3d76261a77b 100644
--- a/etc/uams/uams_passwd.c
+++ b/etc/uams/uams_passwd.c
@@ -55,7 +55,7 @@ static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pw
     struct spwd *sp;
 #endif /* SHADOWPW */
 
-    if (ibuflen < PASSWDLEN) {
+    if (ibuflen <= PASSWDLEN) {
         return( AFPERR_PARAM );
     }
     ibuf[ PASSWDLEN ] = '\0';
@@ -158,7 +158,7 @@ static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
                              (void *) &username, &ulen) < 0)
         return AFPERR_MISC;
 
-    if (*uname != 3)
+    if (*uname != 3 || ibuflen < 2)
         return AFPERR_PARAM;
     uname++;
     memcpy(&temp16, uname, sizeof(temp16));
