Package: proftpd-mod-ldap Severity: grave Tags: patch Hello,
When LDAPDoAuth specifies an invalid filter which leads to no results being returned, mod_ldap SIGSEGV with the following backtrace:
Program received signal SIGSEGV, Segmentation fault. [Switching to Thread 0x7f073be4f6f0 (LWP 16253)] 0x00007f0739e60e72 in handle_ldap_getgroups (cmd=0x11f1470) at mod_ldap.c:1054 1054 mod_ldap.c: No such file or directory. in mod_ldap.c (gdb) bt #0 0x00007f0739e60e72 in handle_ldap_getgroups (cmd=0x11f1470) at mod_ldap.c:1054 #1 0x000000000042f332 in pr_module_call (m=0x7f073a0676a0, func=0x7f0739e60ac0 <handle_ldap_getgroups>, cmd=0x1209c30) at modules.c:502 #2 0x0000000000431e28 in dispatch_auth (cmd=0x11f1470, match=0x47d172 "getgroups", m=0x0) at auth.c:266 #3 0x0000000000431f52 in pr_auth_getgroups (p=0x11f13f0, name=<value optimized out>, group_ids=0x6a9ce0, group_names=0x6a9ce8) at auth.c:980 #4 0x0000000000432577 in auth_anonymous_group (p=<value optimized out>, login_name=0x7fffac929ca0, user_name=<value optimized out>, anon_name=0x0) at auth.c:1041 #5 pr_auth_get_anon_config (p=<value optimized out>, login_name=0x7fffac929ca0, user_name=<value optimized out>, anon_name=0x0) at auth.c:1169 #6 0x000000000045750d in auth_user (cmd=0x11d9688) at mod_auth.c:1756 #7 0x000000000042f332 in pr_module_call (m=0x69bc20, func=0x457470 <auth_user>, cmd=0x1209c30) at modules.c:502 #8 0x0000000000413266 in _dispatch (cmd=0x11d9688, cmd_type=2, validate=<value optimized out>, match=0x11d9708 "USER") at main.c:459 #9 0x000000000041384b in pr_cmd_dispatch_phase (cmd=0x11d9688, phase=0, send_response=1) at main.c:725 #10 0x0000000000414cbc in cmd_loop (server=<value optimized out>, c=<value optimized out>) at main.c:916 #11 0x0000000000410655 in fork_server (fd=<value optimized out>, l=<value optimized out>, nofork=<value optimized out>) at main.c:1436 #12 0x0000000000412609 in daemon_loop () at main.c:1643 #13 0x00000000004149c5 in main (argc=1, argv=<value optimized out>, envp=<value optimized out>) at main.c:3044
Actually, `pw' pointer is dereferenced in `pr_log_debug(..., pw->pw_name, ...)' whereas `pw' might be NULL if `pr_ldap_user_lookup()' called by `pr_ldap_getpwnam()' returns NULL when there has been an error or no entry found. I have attached to this email a patch to fix this issue. If the `pr_user_lookup()' fails (either because of an error or the user does not exist), my patch makes `ldap_handle_getgroups()' just returns (after displaying an error message) as I think there is no point at checking the groups afterwards. I might be missing something though but as the code is not documented, this is a bit hard to tell ;). Regards, Arnaud Fontaine
--- proftpd-dfsg-1.3.2e/contrib/mod_ldap.c.orig 2010-04-06 17:24:00.065027336 +0100 +++ proftpd-dfsg-1.3.2e/contrib/mod_ldap.c 2010-04-06 17:19:38.737029792 +0100 @@ -978,15 +978,21 @@ } pw = pr_ldap_getpwnam(cmd->tmp_pool, cmd->argv[0]); - if (pw) { - gr = pr_ldap_getgrgid(cmd->tmp_pool, pw->pw_gid); - if (gr) { - pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": adding user %s primary group %s/%lu", pw->pw_name, gr->gr_name, (unsigned long)pw->pw_gid); - *((gid_t *) push_array(gids)) = pw->pw_gid; - *((char **) push_array(groups)) = pstrdup(session.pool, gr->gr_name); - } else { - pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": couldn't determine group name for user %s primary group %lu, skipping.", pw->pw_name, (unsigned long)pw->pw_gid); - } + /* If the user lookup fails, there is no point at looking at the groups */ + if (!pw) { + pr_log_pri(PR_LOG_ERR, MOD_LDAP_VERSION ": ldap_handle_getgroups(): Invalid user %s or authentication filter", + cmd->argv[0]); + + goto return_groups; + } + + gr = pr_ldap_getgrgid(cmd->tmp_pool, pw->pw_gid); + if (gr) { + pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": adding user %s primary group %s/%lu", pw->pw_name, gr->gr_name, (unsigned long)pw->pw_gid); + *((gid_t *) push_array(gids)) = pw->pw_gid; + *((char **) push_array(groups)) = pstrdup(session.pool, gr->gr_name); + } else { + pr_log_debug(DEBUG3, MOD_LDAP_VERSION ": couldn't determine group name for user %s primary group %lu, skipping.", pw->pw_name, (unsigned long)pw->pw_gid); } if (!ldap_gid_basedn) { @@ -1047,7 +1053,7 @@ continue; } - if (!pw || strtoul(LDAP_VALUE(gidNumber, 0), (char **)NULL, 10) != pw->pw_gid) { + if (strtoul(LDAP_VALUE(gidNumber, 0), (char **)NULL, 10) != pw->pw_gid) { *((gid_t *) push_array(gids)) = strtoul(LDAP_VALUE(gidNumber, 0), (char **)NULL, 10); *((char **) push_array(groups)) = pstrdup(session.pool, LDAP_VALUE(cn, 0));