Alright, to the source code we go!
util-linux's login program is in charge by the time my login prompt appears. Let's start there, more specifically in the login-utils/login.c file.
Now, login appears to be in charge of the login prompt, since it generates it in loginpam_get_prompt and registers it with PAM in init_loginpam. The loginpam_auth function then takes over, and control goes to PAM's pam_authenticate function. This means that login merely defines a prompt for the username and that's it.
To PAM then: what we're interested in clearly happens in pam_authenticate :
The pam_authenticate function is used to authenticate the user. The user is required to provide an authentication token depending upon the authentication service, usually this is a password, but could also be a finger print.
Now, shadow-based authentication (/etc/passwd, /etc/shadow) is handled by the pam_unix module. My distribution (Arch) provides PAM through the pam package, which means our journey continues over to linux-pam.org and its source code. modules/pam_unix/pam_unix_auth.c seems a good place to start. PAM modules provide their authentication mechanism through a pam_sm_authenticate function, which we find here. The password (or "authentication token", see above) is fetched with a call to PAM's pam_get_authtok function. It is declared in the security/pam_ext.h header file, so that's where we're going next.
extern int PAM_NONNULL((1,3))
pam_get_authtok (pam_handle_t *pamh,
int item,
const char **authtok,
const char *prompt);
Nothing too promising in those arguments but well... Let's see the definition. pam_unix passed NULL for the prompt argument and PAM_AUTHTOK for item, so we end up here. Now that hardcoded PAM_PROMPT_ECHO_OFF given to pam_prompt just doesn't look good for me...
retval = pam_prompt (pamh, PAM_PROMPT_ECHO_OFF, &resp[0], "%s", PROMPT);
By the way, the password PROMPT is also hardcoded (here), so there goes my dream of a more exotic password prompt... Anyway, let's go over to the pam_prompt function. The actual prompt happens here, where PAM calls a conversation function fetched a few lines above. A quick look at the pam_get_item and pam_set_item functions introduces us to the pam_conv structure defined here.
Now, finding information on the default PAM conversation function was a lot trickier than it should be (I think). Everywhere I looked, the structure remained uninitialised and pam_unix does not appear to define its own. However I managed to find the generic misc_conv function, which passes PAM_PROMPT_ECHO_OFF over to read_string and... here's where PAM deactivates input feedback.
Conclusion: the absence of password feedback is hardcoded. Too bad. A little digging got me to this GitHub issue and this Arch BBS thread. Apparently, the feature was available back when PAM wasn't a standard for authentication. I guess it makes sense not to have implemented it again - security and all - but you know, an option would have been nice.
Anyway, I've just ordered my new keyboard.