threads / discuss / 56805

Re: Is getpass(3) really obsolete?

Subject: Re: Is getpass(3) really obsolete?

## tl;dr

20 messages between Oct 29, 2021 and Sep 27, 2022.

replies: 19people: 9as markdown or json

Alejandro Colomar (man-pages)· Oct 29, 2021, 11:28 UTC · lore
[Add a few CCs, since I mentioned them.]
On 10/29/21 13:15, Alejandro Colomar wrote:
Show 11 quoted lines
> Hi,
> 
> As the manual pages says, SUSv2 marked it as LEGACY, and POSIX doesn't 
> have it at all.  The manual page goes further and says "This function is 
> obsolete. Do not use it." in its first lines.
> 
> But, glibc doesn't seem to have deprecated this function at all.  And it 
> seems to be the most portable way to get a password, even if it's not in 
> POSIX.
> 
> BSDs have readpassphrase(3), but glibc doesn't, so unless you recommend 

OpenBSD also marks getpass(3) as obsolete and recommends readpassphrase(3): <https://man.openbsd.org/getpass>

Show 14 quoted lines
> using readpassphrase(3) from libbsd, or plan to add it to glibc, I think 
> getpass(3) should be the recommended function in Linux, and therefore we 
> should remove the hard words against it.
> 
> As a real example, git(1) uses getpass(3).
> <https://github.com/git/git/blob/master/compat/terminal.c>
> 
> What are your thoughts?
> 
> Thanks,
> 
> Alex
> 
> 
-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/
Ævar Arnfjörð Bjarmason· Oct 29, 2021, 11:40 UTC · re: Alejandro Colomar (man-pages) · lore
On Fri, Oct 29 2021, Alejandro Colomar (man-pages) wrote:
> [Add a few CCs, since I mentioned them.]

[I'm not sure what the full context of this thread is, but just replying from the POV of git@ being CC'd on this]

Show 13 quoted lines
> On 10/29/21 13:15, Alejandro Colomar wrote:
>> Hi,
>> As the manual pages says, SUSv2 marked it as LEGACY, and POSIX
>> doesn't have it at all.  The manual page goes further and says "This
>> function is obsolete. Do not use it." in its first lines.
>> But, glibc doesn't seem to have deprecated this function at all. 
>> And it seems to be the most portable way to get a password, even if
>> it's not in POSIX.
>> BSDs have readpassphrase(3), but glibc doesn't, so unless you
>> recommend 
>
> OpenBSD also marks getpass(3) as obsolete and recommends readpassphrase(3):
> <https://man.openbsd.org/getpass>

Simply not being familiar with that case: Is that suggestive of getpass(3) being bad to use in general, or a case where OpenBSD's deprecation of it makes sense holistically on that OS, but not necessarily elsewhere?

Just skimming the linked man pages it looks like OpenBSD might have deprecated it at least partly due to getpass() accepting a password on stdin.

Even within OpenBSD I wonder what that case means for software such as git. I.e. is it better to be portable and accept the same behavior on OpenBSD as elsewhere, or conform more closely to platform-specific conventions.

I haven't looked closely out our getpass() integration, maybe that's a moot point either way.

Show 9 quoted lines
>> using readpassphrase(3) from libbsd, or plan to add it to glibc, I
>> think getpass(3) should be the recommended function in Linux, and
>> therefore we should remove the hard words against it.
>> As a real example, git(1) uses getpass(3).
>> <https://github.com/git/git/blob/master/compat/terminal.c>
>> What are your thoughts?
>> Thanks,
>> Alex
>> 

Just while we've got some OpenBSD people CC'd (added the devel/git maintainers). I occasionally test git on OpenBSD myself (on the GCC farm), and we've got a few broken tests on the platform.

Looking at the ports source there's at least a couple of OpenBSD portability patches in there that would make sense to upstream.

So if that's easy for you or you're willing to submit them upstream we'd be happy to take them. Usually the only reason we haven't fixed things like that already is because nobody told us, and we're not actively looking into the local patches local packagers apply.

Alejandro Colomar (man-pages)· Oct 29, 2021, 12:11 UTC · re: Ævar Arnfjörð Bjarmason · lore
Hi Ævar,
On 10/29/21 13:40, Ævar Arnfjörð Bjarmason wrote:
Show 7 quoted lines
> 
> On Fri, Oct 29 2021, Alejandro Colomar (man-pages) wrote:
> 
>> [Add a few CCs, since I mentioned them.]
> 
> [I'm not sure what the full context of this thread is, but just replying
> from the POV of git@ being CC'd on this]

The first message on this thread was mine from '10/29/21 13:15', so you've read it all.

The broader context is that I was trying to make the deprecation notices more consistent in the Linux manpages, by using the [[deprecated]] attribute where appropriate. While doing that, I found a few cases where the deprecation/obsoletion is not so clear to me, such as this one ([as]ctime[_r](3) is another one, since it is deprecated by POSIX, but not by the C standard, but I'll start a different thread with that; and isascii(3) is another one, since the user of it should know if the character set he's using is compatible with ascii, and in that case it's perfectly valid, it's only a case of garbage in garbage out, IMO).

Show 11 quoted lines
> 
>> On 10/29/21 13:15, Alejandro Colomar wrote:
>>> Hi,
>>> As the manual pages says, SUSv2 marked it as LEGACY, and POSIX
>>> doesn't have it at all.  The manual page goes further and says "This
>>> function is obsolete. Do not use it." in its first lines.
>>> But, glibc doesn't seem to have deprecated this function at all.
>>> And it seems to be the most portable way to get a password, even if
>>> it's not in POSIX.
>>> BSDs have readpassphrase(3), but glibc doesn't, so unless you
>>> recommend
[...]
Cheers,
Alex
-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/
Joseph Myers· Oct 29, 2021, 16:31 UTC · re: Alejandro Colomar (man-pages) · lore
On Fri, 29 Oct 2021, Alejandro Colomar (man-pages) via Libc-alpha wrote:
Show 6 quoted lines
> The broader context is that I was trying to make the deprecation notices more
> consistent in the Linux manpages, by using the [[deprecated]] attribute where
> appropriate.  While doing that, I found a few cases where the
> deprecation/obsoletion is not so clear to me, such as this one
> ([as]ctime[_r](3) is another one, since it is deprecated by POSIX, but not by
> the C standard, but I'll start a different thread with that; and isascii(3) is

See the discussion of deprecation starting with <https://sourceware.org/pipermail/libc-alpha/2021-May/126356.html> (C2X has also deprecated those functions). The comments in that thread supported marking the functions deprecated, but it needs someone to send a patch and I don't know what breakage might result in applications using those functions.

-- 
Joseph S. Myers
joseph@codesourcery.com
Alejandro Colomar (man-pages)· Oct 30, 2021, 12:24 UTC · re: Joseph Myers · lore
Hi Joseph,
On 10/29/21 18:31, Joseph Myers wrote:
Show 16 quoted lines
> On Fri, 29 Oct 2021, Alejandro Colomar (man-pages) via Libc-alpha wrote:
> 
>> The broader context is that I was trying to make the deprecation notices more
>> consistent in the Linux manpages, by using the [[deprecated]] attribute where
>> appropriate.  While doing that, I found a few cases where the
>> deprecation/obsoletion is not so clear to me, such as this one
>> ([as]ctime[_r](3) is another one, since it is deprecated by POSIX, but not by
>> the C standard, but I'll start a different thread with that; and isascii(3) is
> 
> See the discussion of deprecation starting with
> <https://sourceware.org/pipermail/libc-alpha/2021-May/126356.html> (C2X
> has also deprecated those functions).  The comments in that thread
> supported marking the functions deprecated, but it needs someone to send a
> patch and I don't know what breakage might result in applications using
> those functions.
> 

Thanks. The latest draft for C2x that I know of is N2596. Is there any newer draft that I can consult for these things? I see many proposals, but it's difficult to know which have been accepted and which not without an actual recent draft of the standard.

Cheers,
Alex
-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/
Joseph Myers· Nov 1, 2021, 21:31 UTC · re: Alejandro Colomar (man-pages) · lore
On Sat, 30 Oct 2021, Alejandro Colomar (man-pages) via Libc-alpha wrote:
Show 9 quoted lines
> > See the discussion of deprecation starting with
> > <https://sourceware.org/pipermail/libc-alpha/2021-May/126356.html> (C2X
> > has also deprecated those functions).  The comments in that thread
> > supported marking the functions deprecated, but it needs someone to send a
> > patch and I don't know what breakage might result in applications using
> > those functions.
> 
> Thanks.  The latest draft for C2x that I know of is N2596.  Is there any newer
> draft that I can consult for these things?  I see many proposals, but it's

The latest public draft is N2731, but there are still various accepted proposals not included in there, including N2566 (wording version 2) which I believe was accepted in October 2020 (I think issue 68 in the (private) C standard GitLab, for integrating that paper, has been incorrectly closed without integrating it).

-- 
Joseph S. Myers
joseph@codesourcery.com
rsbecker@nexbridge.com· Oct 29, 2021, 12:10 UTC · re: Alejandro Colomar (man-pages) · lore

RE: Is getpass(3) really obsolete?

On October 29, 2021 7:29 AM, Alejandro Colomar wrote:
Show 27 quoted lines
> On 10/29/21 13:15, Alejandro Colomar wrote:
> > Hi,
> >
> > As the manual pages says, SUSv2 marked it as LEGACY, and POSIX doesn't
> > have it at all.  The manual page goes further and says "This function
> > is obsolete. Do not use it." in its first lines.
> >
> > But, glibc doesn't seem to have deprecated this function at all.  And
> > it seems to be the most portable way to get a password, even if it's
> > not in POSIX.
> >
> > BSDs have readpassphrase(3), but glibc doesn't, so unless you
> > recommend
> 
> OpenBSD also marks getpass(3) as obsolete and recommends
> readpassphrase(3):
> <https://man.openbsd.org/getpass>
> 
> > using readpassphrase(3) from libbsd, or plan to add it to glibc, I
> > think
> > getpass(3) should be the recommended function in Linux, and therefore
> > we should remove the hard words against it.
> >
> > As a real example, git(1) uses getpass(3).
> > <https://github.com/git/git/blob/master/compat/terminal.c>
> >
> > What are your thoughts?
getpass() is obsolete in POSIX.2. However, some platforms still are on POSIX.1, so replacing it instead of providing a configure detection/switch for it might cause issues.
-Randall
Eugene Syromyatnikov· Oct 29, 2021, 13:55 UTC · re: rsbecker@nexbridge.com · lore
On Fri, Oct 29, 2021 at 2:40 PM <rsbecker@nexbridge.com> wrote:
> getpass() is obsolete in POSIX.2. However, some platforms still are on POSIX.1, so replacing it instead of providing a configure detection/switch for it might cause issues.

POSIX.2 is not a newer POSIX version, but rather a book (“Shell and utilities”) in pre-2001 standard revisions, and it has nothing to do with the system interfaces (that is POSIX.1). And the only mention of getpass() in POSIX (at least, since the 2001's edition) indeed seems to be [1], in the list of functions that have not been carried forward from XSH5, the 1997 revision of “System Interfaces and Headers” (that is, SUSv2)[2], where it is inherited from SUSv1[4] from XPG[5] and, as Alejandro already mentioned, marked as obsolete, per XPG3 to XPG4 migration guide[6]; the previous, 1988, version of POSIX[3] does not mention getpass() at all.

[1] https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap01.html [2] https://pubs.opengroup.org/onlinepubs/7908799/xsh/getpass.html [3] https://mirror.math.princeton.edu/pub/oldlinux/download/c953.pdf [4] https://pubs.opengroup.org/onlinepubs/9695969499/toc.pdf [5] https://bitsavers.computerhistory.org/pdf/xOpen/X_Open_Portability_Guide_1985/xpg_2_xopen_system_v_specification_2.pdf [6] http://archive.opengroup.org/publications/archive/CDROM/g501.pdf

-- 
Eugene Syromyatnikov
mailto:evgsyr@gmail.com
xmpp:esyr@jabber.{ru|org}
Theo de Raadt· Oct 29, 2021, 13:55 UTC · re: rsbecker@nexbridge.com · lore
<rsbecker@nexbridge.com> wrote:
Show 30 quoted lines
> On October 29, 2021 7:29 AM, Alejandro Colomar wrote:
> > On 10/29/21 13:15, Alejandro Colomar wrote:
> > > Hi,
> > >
> > > As the manual pages says, SUSv2 marked it as LEGACY, and POSIX doesn't
> > > have it at all.  The manual page goes further and says "This function
> > > is obsolete. Do not use it." in its first lines.
> > >
> > > But, glibc doesn't seem to have deprecated this function at all.  And
> > > it seems to be the most portable way to get a password, even if it's
> > > not in POSIX.
> > >
> > > BSDs have readpassphrase(3), but glibc doesn't, so unless you
> > > recommend
> > 
> > OpenBSD also marks getpass(3) as obsolete and recommends
> > readpassphrase(3):
> > <https://man.openbsd.org/getpass>
> > 
> > > using readpassphrase(3) from libbsd, or plan to add it to glibc, I
> > > think
> > > getpass(3) should be the recommended function in Linux, and therefore
> > > we should remove the hard words against it.
> > >
> > > As a real example, git(1) uses getpass(3).
> > > <https://github.com/git/git/blob/master/compat/terminal.c>
> > >
> > > What are your thoughts?
> 
> getpass() is obsolete in POSIX.2. However, some platforms still are on POSIX.1, so replacing it instead of providing a configure detection/switch for it might cause issues.
The community finally had the balls to get rid of gets(3).

getpass(3) shares the same flaw, that the buffer size isn't passed. This has been an issue in the past, and incorrectly led to readpassphrase(3)

readpassphrase(3) has a few too many features/extensions for my taste, but at least it is harder to abuse.

rsbecker@nexbridge.com· Oct 29, 2021, 14:18 UTC · re: Theo de Raadt · lore

RE: Is getpass(3) really obsolete?

On October 29, 2021 9:56 AM, Theo de Raadt wrote:
Show 33 quoted lines
> Subject: Re: Is getpass(3) really obsolete?
> <rsbecker@nexbridge.com> wrote:
> 
> > On October 29, 2021 7:29 AM, Alejandro Colomar wrote:
> > > On 10/29/21 13:15, Alejandro Colomar wrote:
> > > > Hi,
> > > >
> > > > As the manual pages says, SUSv2 marked it as LEGACY, and POSIX
> > > > doesn't have it at all.  The manual page goes further and says
> > > > "This function is obsolete. Do not use it." in its first lines.
> > > >
> > > > But, glibc doesn't seem to have deprecated this function at all.
> > > > And it seems to be the most portable way to get a password, even
> > > > if it's not in POSIX.
> > > >
> > > > BSDs have readpassphrase(3), but glibc doesn't, so unless you
> > > > recommend
> > >
> > > OpenBSD also marks getpass(3) as obsolete and recommends
> > > readpassphrase(3):
> > > <https://man.openbsd.org/getpass>
> > >
> > > > using readpassphrase(3) from libbsd, or plan to add it to glibc, I
> > > > think
> > > > getpass(3) should be the recommended function in Linux, and
> > > > therefore we should remove the hard words against it.
> > > >
> > > > As a real example, git(1) uses getpass(3).
> > > > <https://github.com/git/git/blob/master/compat/terminal.c>
> > > >
> > > > What are your thoughts?
> >
> > getpass() is obsolete in POSIX.2. However, some platforms still are on
POSIX.1,
> so replacing it instead of providing a configure detection/switch for it
might
Show 7 quoted lines
> cause issues.
> 
> 
> The community finally had the balls to get rid of gets(3).
> 
> getpass(3) shares the same flaw, that the buffer size isn't passed.
> This has been an issue in the past, and incorrectly led to
readpassphrase(3)
> 
> readpassphrase(3) has a few too many features/extensions for my taste, but
at
> least it is harder to abuse.

readpassphrase is not generally supported. This will break builds on many platforms.

Theo de Raadt· Oct 29, 2021, 14:21 UTC · re: rsbecker@nexbridge.com · lore
<rsbecker@nexbridge.com> wrote:
Show 19 quoted lines
> > > getpass() is obsolete in POSIX.2. However, some platforms still are on
> POSIX.1,
> > so replacing it instead of providing a configure detection/switch for it
> might
> > cause issues.
> > 
> > 
> > The community finally had the balls to get rid of gets(3).
> > 
> > getpass(3) shares the same flaw, that the buffer size isn't passed.
> > This has been an issue in the past, and incorrectly led to
> readpassphrase(3)
> > 
> > readpassphrase(3) has a few too many features/extensions for my taste, but
> at
> > least it is harder to abuse.
> 
> readpassphrase is not generally supported. This will break builds on many
> platforms.

Of course moving forward takes a long time. If a better API is supplied then there is a choice in 10 years. If a better API is not supplied, then 10 years from now this conversation can get a reply.

rsbecker@nexbridge.com· Oct 29, 2021, 14:33 UTC · re: Theo de Raadt · lore

RE: Is getpass(3) really obsolete?

October 29, 2031 10:21 AM, Theo de Raadt will write:
Show 28 quoted lines
> <rsbecker@nexbridge.com> wrote:
> 
> > > > getpass() is obsolete in POSIX.2. However, some platforms still
> > > > are on
> > POSIX.1,
> > > so replacing it instead of providing a configure detection/switch
> > > for it
> > might
> > > cause issues.
> > >
> > >
> > > The community finally had the balls to get rid of gets(3).
> > >
> > > getpass(3) shares the same flaw, that the buffer size isn't passed.
> > > This has been an issue in the past, and incorrectly led to
> > readpassphrase(3)
> > >
> > > readpassphrase(3) has a few too many features/extensions for my
> > > taste, but
> > at
> > > least it is harder to abuse.
> >
> > readpassphrase is not generally supported. This will break builds on
> > many platforms.
> 
> Of course moving forward takes a long time.  If a better API is supplied then
> there is a choice in 10 years.  If a better API is not supplied, then 10 years from
> now this conversation can get a reply.
I checked the API 10 years from now (check the above date) at it's still not there 😉 In the meantime, compatibility is important. I checked the latest release (last week's) on my platform and readpassphrase() is not available. Let's please put a compatibility layer in.
Alejandro Colomar (man-pages)· Oct 29, 2021, 14:44 UTC · re: rsbecker@nexbridge.com · lore
Hi Randall, Theo,
On 10/29/21 16:33, rsbecker@nexbridge.com wrote:
Show 17 quoted lines
> October 29, 2031 10:21 AM, Theo de Raadt will write:
>> <rsbecker@nexbridge.com> wrote:
>>
>>>>> getpass() is obsolete in POSIX.2. However, some platforms still
>>>>> are on
>>> POSIX.1,
>>>> so replacing it instead of providing a configure detection/switch
>>>> for it
>>> might
>>>> cause issues.
>>>>
>>>>
>>>> The community finally had the balls to get rid of gets(3).
>>>>
>>>> getpass(3) shares the same flaw, that the buffer size isn't passed.
>>>> This has been an issue in the past, and incorrectly led to
>>> readpassphrase(3)

That seems a good reason to keep the "Do not use it." note in the manual page. I think I'll add a recommendation for readpassphrase(3bsd) for the moment which is the only alternative available in Linux.

Show 8 quoted lines
>>>>
>>>> readpassphrase(3) has a few too many features/extensions for my
>>>> taste, but
>>> at
>>>> least it is harder to abuse.
>>>
>>> readpassphrase is not generally supported. This will break builds on
>>> many platforms.

I found readpassphrase(3) in FreeBSD and OpenBSD. It is also present in libbsd(7), which is available in most Linux distributions. I also found it on a Mac that I have access.

NetBSD has getpass_r(3) instead. It is not in any other system I have access.

Show 7 quoted lines
>>
>> Of course moving forward takes a long time.  If a better API is supplied then
>> there is a choice in 10 years.  If a better API is not supplied, then 10 years from
>> now this conversation can get a reply.
> 
> I checked the API 10 years from now (check the above date) at it's still not there 😉 In the meantime, compatibility is important. I checked the latest release (last week's) on my platform and readpassphrase() is not available. Let's please put a compatibility layer in.
> 

libbsd(7) is probably the compatibility layer that you're looking for. What system are you on?

<https://libbsd.freedesktop.org/wiki/>
Cheers,
Alex
-- 
Alejandro Colomar
Linux man-pages comaintainer; https://www.kernel.org/doc/man-pages/
http://www.alejandro-colomar.es/
rsbecker@nexbridge.com· Oct 29, 2021, 15:00 UTC · re: Alejandro Colomar (man-pages) · lore

RE: Is getpass(3) really obsolete?

On October 29, 2021 10:45 AM, Alejandro Colomar wrote:
Show 53 quoted lines
> On 10/29/21 16:33, rsbecker@nexbridge.com wrote:
> > October 29, 2031 10:21 AM, Theo de Raadt will write:
> >> <rsbecker@nexbridge.com> wrote:
> >>
> >>>>> getpass() is obsolete in POSIX.2. However, some platforms still
> >>>>> are on
> >>> POSIX.1,
> >>>> so replacing it instead of providing a configure detection/switch
> >>>> for it
> >>> might
> >>>> cause issues.
> >>>>
> >>>>
> >>>> The community finally had the balls to get rid of gets(3).
> >>>>
> >>>> getpass(3) shares the same flaw, that the buffer size isn't passed.
> >>>> This has been an issue in the past, and incorrectly led to
> >>> readpassphrase(3)
> 
> That seems a good reason to keep the "Do not use it." note in the manual page.
> I think I'll add a recommendation for readpassphrase(3bsd) for the moment
> which is the only alternative available in Linux.
> 
> >>>>
> >>>> readpassphrase(3) has a few too many features/extensions for my
> >>>> taste, but
> >>> at
> >>>> least it is harder to abuse.
> >>>
> >>> readpassphrase is not generally supported. This will break builds on
> >>> many platforms.
> I found readpassphrase(3) in FreeBSD and OpenBSD.
> It is also present in libbsd(7), which is available in most Linux distributions.
> I also found it on a Mac that I have access.
> 
> NetBSD has getpass_r(3) instead.  It is not in any other system I have access.
> 
> 
> >>
> >> Of course moving forward takes a long time.  If a better API is supplied then
> >> there is a choice in 10 years.  If a better API is not supplied, then 10 years
> from
> >> now this conversation can get a reply.
> >
> > I checked the API 10 years from now (check the above date) at it's still not
> there 😉 In the meantime, compatibility is important. I checked the latest
> release (last week's) on my platform and readpassphrase() is not available. Let's
> please put a compatibility layer in.
> >
> libbsd(7) is probably the compatibility layer that you're looking for.
> What system are you on?
> 
> <https://libbsd.freedesktop.org/wiki/>
I am on two variants (x86 and ia64) of HPE NonStop with current operating systems - and I do the build/test for git and OpenSSL. getpass() an alias to getpass2() but the other procs are not present. If this is going into git, I would suggest putting something into compat.c to abstract out the call. If it's there, we can handle it on a platform-by-platform basis.

Thanks, Randall

Zack Weinberg· Oct 29, 2021, 14:53 UTC · re: Theo de Raadt · lore
On Fri, Oct 29, 2021, at 9:55 AM, Theo de Raadt wrote:
Show 8 quoted lines
> <rsbecker@nexbridge.com> wrote:
>> On October 29, 2021 7:29 AM, Alejandro Colomar wrote:
>> > On 10/29/21 13:15, Alejandro Colomar wrote:
>> > > Hi,
>> > >
>> > > As the manual pages says, SUSv2 marked it as LEGACY, and POSIX doesn't
>> > > have it at all.  The manual page goes further and says "This function
>> > > is obsolete. Do not use it." in its first lines.
...
> The community finally had the balls to get rid of gets(3).
>
> getpass(3) shares the same flaw, that the buffer size isn't passed.
> This has been an issue in the past
I was about to post exactly the same thing.  getpass(3) is not deprecated because there's a better replacement, it's deprecated because it's _unsafe_.  The glibc implementation wraps getline(3) and therefore  doesn't truncate the passphrase or overflow a fixed-size buffer, no matter how long the input is, but portable code cannot rely on that.  And come to think of it, using getline(3) means that prefixes of the passphrase may be left lying around in malloc's free lists.
(getpass also cannot be made thread safe, due to recycling of a static buffer, but a program in which multiple threads are racing to prompt the user for passwords would be a UX disaster anyway, so I don't think that's a critical flaw the way it is for e.g. strtok(3).)
The Linux manpage project's documentation is, as I understand it, for Linux with glibc _first_, but not _only_; it should not describe this function as not-deprecated just because glibc has patched its worst problems and doesn't offer any better API.
> readpassphrase(3) has a few too many features/extensions for my taste, but
> at least it is harder to abuse.
I am inclined to agree that readpassphrase has too many knobs, and I can't think of any legitimate present-day use for several of them, which is not a good property for an API handling security-critical data.  Also, it relies on the caller to size the buffer for the passphrase, and therefore risks truncating people's passphrases.
With my libxcrypt hat on I've thought a bit about replacements for getpass.  The conclusion I came to is that the easy changes are all putting lipstick on a pig, and if I was going to work on this at all I was going to design a privilege-separated authentication service that could be asked to take over a tty, read a passphrase, check it, and return just success or failure to the caller.  Neither the passphrase itself, nor any strings derived from it, would ever be in the caller's address space.  But this is obviously well out of scope for the C library.
zw
Alejandro Colomar· Sep 27, 2022, 19:19 UTC · re: Zack Weinberg · lore

readpassphrase(3) in glibc, and agetpass() (Was: Is getpass(3) really obsolete?)

Hi Zack,
On 10/29/21 16:53, Zack Weinberg via Libc-alpha wrote:
Show 29 quoted lines
> On Fri, Oct 29, 2021, at 9:55 AM, Theo de Raadt wrote:
>> <rsbecker@nexbridge.com> wrote:
>>> On October 29, 2021 7:29 AM, Alejandro Colomar wrote:
>>>> On 10/29/21 13:15, Alejandro Colomar wrote:
>>>>> Hi,
>>>>>
>>>>> As the manual pages says, SUSv2 marked it as LEGACY, and POSIX doesn't
>>>>> have it at all.  The manual page goes further and says "This function
>>>>> is obsolete. Do not use it." in its first lines.
> ...
>> The community finally had the balls to get rid of gets(3).
>>
>> getpass(3) shares the same flaw, that the buffer size isn't passed.
>> This has been an issue in the past
> 
> I was about to post exactly the same thing.  getpass(3) is not deprecated because there's a better replacement, it's deprecated because it's _unsafe_.  The glibc implementation wraps getline(3) and therefore  doesn't truncate the passphrase or overflow a fixed-size buffer, no matter how long the input is, but portable code cannot rely on that.  And come to think of it, using getline(3) means that prefixes of the passphrase may be left lying around in malloc's free lists.
> 
> (getpass also cannot be made thread safe, due to recycling of a static buffer, but a program in which multiple threads are racing to prompt the user for passwords would be a UX disaster anyway, so I don't think that's a critical flaw the way it is for e.g. strtok(3).)
> 
> The Linux manpage project's documentation is, as I understand it, for Linux with glibc _first_, but not _only_; it should not describe this function as not-deprecated just because glibc has patched its worst problems and doesn't offer any better API.
> 
>> readpassphrase(3) has a few too many features/extensions for my taste, but
>> at least it is harder to abuse.
> 
> I am inclined to agree that readpassphrase has too many knobs, and I can't think of any legitimate present-day use for several of them, which is not a good property for an API handling security-critical data.  Also, it relies on the caller to size the buffer for the passphrase, and therefore risks truncating people's passphrases.
> 
> With my libxcrypt hat on I've thought a bit about replacements for getpass.  The conclusion I came to is that the easy changes are all putting lipstick on a pig, and if I was going to work on this at all I was going to design a privilege-separated authentication service that could be asked to take over a tty, read a passphrase, check it, and return just success or failure to the caller.  Neither the passphrase itself, nor any strings derived from it, would ever be in the caller's address space.  But this is obviously well out of scope for the C library.
> 
> zw

I happen to be working on replacing getpass(3) in shadow-utils. As there is no replacement in glibc, I'm making the code depend on libbsd on GNU systems.

I developed a function similar to getpass(3), but which allocates a buffer (similar to asprintf(3)). I only allocate once, and bail out if the password exceeds PASS_MAX, so no leaks in allocated memory (modulo bugs that I may have not noticed).

I also enforce both clearing and freeing the memory, by requiring a specific clean-up function.

The prototypes for the function and the clean-up are:

``` void erase_pass(char *p); [[gnu::malloc(erase_pass)]] char *shdw_getpass(const char *prompt);

```
And the implementation is:

``` #include "prototypes.h"

#include <limits.h> #include <readpassphrase.h> #include <stdio.h> #include <stdlib.h>

#if !defined(PASS_MAX) #define PASS_MAX BUFSIZ #endif

char *
agetpass(const char *prompt)
{
	char    *p;
	size_t  len;
	p = malloc(PASS_MAX);
	if (p == NULL)
		return NULL;
	if (readpassphrase(prompt, p, PASS_MAX, 0) == NULL)
		goto fail;
	len = strlen(p);
	if (len == 0)
		return p;
	if (p[len - 1] != '\n')
		goto truncated;
	p[len - 1] = '\0';
	return p;
truncated:
	memzero(p, PASS_MAX);
fail:
	free(p);
	return NULL;
}
void
erase_pass(char *p)
{
	if (p != NULL)
		memzero(p, PASS_MAX);
	free(p);
}
```

Would you mind implementing readpassphrase(3) in glibc so that it's easier to use something safe and portable without resorting to compatibility libraries? Also, I'd like some review of this function, if you think the API could be improved. Maybe agetpass() would be a simple almost-drop-in replacement for getpass(3), so if you like it for glibc, let's discuss it.

I chose a predefined buffer size to not have to pass a buffer size all the time, which could be error-prone. I also allocated the buffer internally, to make it easier to replace getpass(3). It may be desirable to use existing buffers, and pass them through a pointer, but for shadow-utils, it was simpler to keep the getpass(3) API.

I don't know what was the practice with PASS_MAX regarding the NUL byte, but to avoid creating a buffer of a power of two plus one, I decided that the NUL byte would be within PASS_MAX. Another solution would be to declare PASS_MAX to be something like BUFSIZ-1, and then use PASS_MAX+1, but I opted for simplicity.

What are your thoughts?
Cheers,
Alex
Alex Colomar· Sep 27, 2022, 19:33 UTC · re: Alejandro Colomar · lore

Re: readpassphrase(3) in glibc, and agetpass() (Was: Is getpass(3) really obsolete?)

On 9/27/22 21:19, Alejandro Colomar wrote: ...

Show 6 quoted lines
> 
> The prototypes for the function and the clean-up are:
> 
> ```
> void erase_pass(char *p);
> [[gnu::malloc(erase_pass)]] char *shdw_getpass(const char *prompt);
I edited the function name for the email, and forgot to fix it here :)
s/shdw_/a/
Cheers,
Alex
-- 
<http://www.alejandro-colomar.es/>
Sam James· Sep 27, 2022, 20:30 UTC · re: Alejandro Colomar · lore

Re: readpassphrase(3) in glibc, and agetpass() (Was: Is getpass(3) really obsolete?)

Show 39 quoted lines
> On 27 Sep 2022, at 20:19, Alejandro Colomar via Libc-alpha <libc-alpha@sourceware.org> wrote:
> 
> Hi Zack,
> 
> On 10/29/21 16:53, Zack Weinberg via Libc-alpha wrote:
>> On Fri, Oct 29, 2021, at 9:55 AM, Theo de Raadt wrote:
>>> <rsbecker@nexbridge.com> wrote:
>>>> On October 29, 2021 7:29 AM, Alejandro Colomar wrote:
>>>>> On 10/29/21 13:15, Alejandro Colomar wrote:
>>>>>> Hi,
>>>>>> 
>>>>>> As the manual pages says, SUSv2 marked it as LEGACY, and POSIX doesn't
>>>>>> have it at all.  The manual page goes further and says "This function
>>>>>> is obsolete. Do not use it." in its first lines.
>> ...
>>> The community finally had the balls to get rid of gets(3).
>>> 
>>> getpass(3) shares the same flaw, that the buffer size isn't passed.
>>> This has been an issue in the past
>> I was about to post exactly the same thing.  getpass(3) is not deprecated because there's a better replacement, it's deprecated because it's _unsafe_.  The glibc implementation wraps getline(3) and therefore  doesn't truncate the passphrase or overflow a fixed-size buffer, no matter how long the input is, but portable code cannot rely on that.  And come to think of it, using getline(3) means that prefixes of the passphrase may be left lying around in malloc's free lists.
>> (getpass also cannot be made thread safe, due to recycling of a static buffer, but a program in which multiple threads are racing to prompt the user for passwords would be a UX disaster anyway, so I don't think that's a critical flaw the way it is for e.g. strtok(3).)
>> The Linux manpage project's documentation is, as I understand it, for Linux with glibc _first_, but not _only_; it should not describe this function as not-deprecated just because glibc has patched its worst problems and doesn't offer any better API.
>>> readpassphrase(3) has a few too many features/extensions for my taste, but
>>> at least it is harder to abuse.
>> I am inclined to agree that readpassphrase has too many knobs, and I can't think of any legitimate present-day use for several of them, which is not a good property for an API handling security-critical data.  Also, it relies on the caller to size the buffer for the passphrase, and therefore risks truncating people's passphrases.
>> With my libxcrypt hat on I've thought a bit about replacements for getpass.  The conclusion I came to is that the easy changes are all putting lipstick on a pig, and if I was going to work on this at all I was going to design a privilege-separated authentication service that could be asked to take over a tty, read a passphrase, check it, and return just success or failure to the caller.  Neither the passphrase itself, nor any strings derived from it, would ever be in the caller's address space.  But this is obviously well out of scope for the C library.
>> zw
> 
> I happen to be working on replacing getpass(3) in shadow-utils.  As there is no replacement in glibc, I'm making the code depend on libbsd on GNU systems.
> 
> I developed a function similar to getpass(3), but which allocates a buffer (similar to asprintf(3)).  I only allocate once, and bail out if the password exceeds PASS_MAX, so no leaks in allocated memory (modulo bugs that I may have not noticed).
> 
> I also enforce both clearing and freeing the memory, by requiring a specific clean-up function.
> 
> The prototypes for the function and the clean-up are:
> 
> [snip]
> Would you mind implementing readpassphrase(3) in glibc so that it's easier to use something safe and portable without resorting to compatibility libraries?  Also, I'd like some review of this function, if you think the API could be improved.  Maybe agetpass() would be a simple almost-drop-in replacement for getpass(3), so if you like it for glibc, let's discuss it.
> 
I assume it'd be libxcrypt instead?

Best, sam

Alejandro Colomar· Oct 29, 2021, 15:27 UTC · re: Alejandro Colomar (man-pages) · lore

[PATCH] getpass.3: SYNOPSIS: Mark getpass() as [[deprecated]]

Suggest readpassphrase(3bsd) as an alternative.

See the long discussion in the mailing list for more details (link at the bottom of this commit message). I'll quote some relevant parts here:

Eugene Syromyatnikov <evgsyr@gmail.com>:
{
	And the only mention of getpass() in POSIX (at least,
	since the 2001's edition) indeed seems to be [1], in the
	list of functions that have not been carried forward from
	XSH5, the 1997 revision of “System Interfaces and Headers”
	(that is, SUSv2)[2], where it is inherited from SUSv1[4]
	from XPG[5] and, as Alejandro already mentioned, marked as
	obsolete, per XPG3 to XPG4 migration guide[6]; the
	previous, 1988, version of POSIX[3] does not mention
	getpass() at all.
	[1] https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap01.html
	[2] https://pubs.opengroup.org/onlinepubs/7908799/xsh/getpass.html
	[3] https://mirror.math.princeton.edu/pub/oldlinux/download/c953.pdf
	[4] https://pubs.opengroup.org/onlinepubs/9695969499/toc.pdf
	[5] https://bitsavers.computerhistory.org/pdf/xOpen/X_Open_Portability_Guide_1985/xpg_2_xopen_system_v_specification_2.pdf
	[6] http://archive.opengroup.org/publications/archive/CDROM/g501.pdf
}
Theo de Raadt <deraadt@openbsd.org>:
{
	The community finally had the balls to get rid of gets(3).
	getpass(3) shares the same flaw, that the buffer size
	isn't passed.  This has been an issue in the past, and
	incorrectly led to readpassphrase(3).
	readpassphrase(3) has a few too many features/extensions
	for my taste, but at least it is harder to abuse.
}
Alejandro Colomar <alx.manpages@gmail.com>:
{
	I found readpassphrase(3) in FreeBSD and OpenBSD.  It is
	also present in libbsd(7), which is available in most
	Linux distributions.  I also found it on a Mac that I have
	access.
	NetBSD has getpass_r(3) instead.  It is not in any other
	system I have access.
}
Zack Weinberg <zack@owlfolio.org>:
{
	I was about to post exactly the same thing.  getpass(3)
	is not deprecated because there's a better replacement,
	it's deprecated because it's _unsafe_.  The glibc
	implementation wraps getline(3) and therefore  doesn't
	truncate the passphrase or overflow a fixed-size buffer,
	no matter how long the input is, but portable code cannot
	rely on that.  And come to think of it, using getline(3)
	means that prefixes of the passphrase may be left lying
	around in malloc's free lists.
	(getpass also cannot be made thread safe, due to recycling
	of a static buffer, but a program in which multiple
	threads are racing to prompt the user for passwords would
	be a UX disaster anyway, so I don't think that's a
	critical flaw the way it is for e.g. strtok(3).)
	The Linux manpage project's documentation is, as I
	understand it, for Linux with glibc _first_, but not
	_only_; it should not describe this function as
	not-deprecated just because glibc has patched its worst
	problems and doesn't offer any better API.
}
List: linux-man <https://lore.kernel.org/linux-man/6d8642e9-71f7-4a83-9791-880d04f67d17@www.fastmail.com/T/#t>
Signed-off-by: Alejandro Colomar <alx.manpages@gmail.com>
Cc: Git <git@vger.kernel.org>
Cc: Glibc <libc-alpha@sourceware.org>
Cc: OpenBSD <tech@openbsd.org>
Cc: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Cc: Benoit Lecocq <benoit@openbsd.org>
Cc: Klemens Nanni <kn@openbsd.org>
Cc: Randall <rsbecker@nexbridge.com>
Cc: Eugene Syromyatnikov <evgsyr@gmail.com>
Cc: Theo de Raadt <deraadt@openbsd.org>
Cc: Zack Weinberg <zack@owlfolio.org>
Cc: Florian Weimer <libc-alpha@sourceware.org>
---
 man3/getpass.3 | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/man3/getpass.3 b/man3/getpass.3
index fa2031544..7d6da07fa 100644
--- a/man3/getpass.3
+++ b/man3/getpass.3
@@ -28,7 +28,7 @@ getpass \- get a password
 .nf
 .B #include <unistd.h>
 .PP
-.BI "char *getpass(const char *" prompt );
+.BI "[[deprecated]] char *getpass(const char *" prompt );
 .fi
 .PP
 .RS -4
@@ -48,6 +48,7 @@ Feature Test Macro Requirements for glibc (see
 .SH DESCRIPTION
 This function is obsolete.
 Do not use it.
+See NOTES.
 If you want to read input without terminal echoing enabled,
 see the description of the
 .I ECHO
@@ -126,7 +127,11 @@ Removed in POSIX.1-2001.
 .\" are transmitted as part of the password.
 .\" Since libc 5.4.19 also line editing is disabled, so that also
 .\" backspace and the like will be seen as part of the password.
-.
+You should use instead
+.BR readpassphrase (3bsd),
+provided by
+.IR libbsd .
+.PP
 In the GNU C library implementation, if
 .I /dev/tty
 cannot be opened, the prompt is written to
-- 
2.33.1
Jeff King· Oct 29, 2021, 20:27 UTC · re: Alejandro Colomar (man-pages) · lore
On Fri, Oct 29, 2021 at 01:28:56PM +0200, Alejandro Colomar (man-pages) wrote:
> > As a real example, git(1) uses getpass(3).
> > <https://github.com/git/git/blob/master/compat/terminal.c>

Sort of. It is the compile-time fallback of last resort. Most builds would use either termios with /dev/tty or a Windows-native equivalent.

You can see all the reasons we stopped using getpass() in the commit below.

-- >8 --
commit 21aeafceda2382d26bfa73a98ba45a937d65d77a
Author: Jeff King <peff@peff.net>
Date:   Sat Dec 10 05:41:01 2011 -0500
    add generic terminal prompt function
    
    When we need to prompt the user for input interactively, we
    want to access their terminal directly. We can't rely on
    stdio because it may be connected to pipes or files, rather
    than the terminal. Instead, we use "getpass()", because it
    abstracts the idea of prompting and reading from the
    terminal.  However, it has some problems:
    
      1. It never echoes the typed characters, which makes it OK
         for passwords but annoying for other input (like usernames).
    
      2. Some implementations of getpass() have an extremely
         small input buffer (e.g., Solaris 8 is reported to
         support only 8 characters).
    
      3. Some implementations of getpass() will fall back to
         reading from stdin (e.g., glibc). We explicitly don't
         want this, because our stdin may be connected to a pipe
         speaking a particular protocol, and reading will
         disrupt the protocol flow (e.g., the remote-curl
         helper).
    
      4. Some implementations of getpass() turn off signals, so
         that hitting "^C" on the terminal does not break out of
         the password prompt. This can be a mild annoyance.
    
    Instead, let's provide an abstract "git_terminal_prompt"
    function that addresses these concerns. This patch includes
    an implementation based on /dev/tty, enabled by setting
    HAVE_DEV_TTY. The fallback is to use getpass() as before.
    
    Signed-off-by: Jeff King <peff@peff.net>
    Signed-off-by: Junio C Hamano <gitster@pobox.com>

← back to recent threads