If I do:
sudo cat /etc/resolv.conf | less It will prompt me for the password, even though less (presumably) takes stdin. Over what fd's is the password prompt shown and how does it get the input back?
Actually, a typical invocation of sudo does not read the password from stdin at all. Instead, sudo will directly access the controlling terminal (a tty or pty, via the /dev/tty special file) and output the prompt and read characters directly. This can be seen in the tgetpass.c file in the sudo source.
There are a few other scenarios:
askpass program is specified, e.g. in the -A param, that program will be invoked.sudo to read from stdin, e.g. with the -S flag -- and it will also write the prompt to stderr. This is the case where MadHatter's answer applies.tty available visiblepw flag in sudoers), sudo will report an error: no tty present and no askpass program specifiedsudo will fall back to using stdin and stderr even if it was not specifically requested. MadHatter's answer will also apply here.The pipe connects sudo cat's stdout to less's stdin, so sudo cat's stdin is unaffected, and able to receive the password.
As for the prompt, it goes out on sudo cat's stderr; in bash, try redirecting that along with stdout, using
sudo cat /etc/resolv.conf |& less and see how different the response is.
sudo's stdin is still connected to the terminal with the example command, that's not directly relevant to how it gets its password: by default sudo will not request passwords via stdin nor will it show the prompt via stderr -- you can try 2>/dev/null to confirm that. Instead, sudo directly accesses the tty. While both less and sudo access the terminal directly (by opening /dev/tty, in practice: even if sudo were to have its standard input redirected as well, the password prompt and the reading of its response will occur on the fd obtained by opening /dev/tty), they don't do so at the same time.
Indeed, less will not read from /dev/tty until it is time for it to query you for what to do next: in practice, when the terminal is full or its input has reached end-of-file (which in the case of a pipe occurs when it is orphaned, that is when the fd on the other side is closed for good), whichever comes first. However, sudo will prevent anything from going to standard output until it is done querying you over the terminal, so less can't possibly require your input before that.
But it is true that absolutely nothing enforces exclusion in that regard. For instance, if you were to execute sh -c 'echo "$1"; sudo cat /etc/resolv.conf' sh-c "$MORE_THAN_A_SCREENFUL_OF_HEADER" | less, then you will cause sudo and less to fight over the characters your enter in the terminal; at which point your best option is ctrl-C.