1. 51
  1. 30

    Excellent comment on this from the orange site, not copied since it’s the author’s story. https://news.ycombinator.com/item?id=29169848

    1. 2

      Thank you very much! This piece of background story was amazing to read.

      I am always very impressed by the work of Sun and love such stories :).

      1. 2

        Thank you for sharing that here, I absolutely love stories like these.

      2. 13

        mostly because /etc/passwd is world-readable by design for some arcane reason that I can’t find on Google

        I think it’s so you can map uids to usernames. And read all the other fun stuff like their real name, phone number, office location, etc.

        1. 5

          Exactly this. There are obviously other options Yellow Pages, Kerberos, Active Directory, etc, etc, etc. But this is the “I don’t need anything more” directory.

          1. 7

            Very early versions of Unix also had /etc/uids for this purpose, which was just a username↔UID mapping (e.g. dmr:7), but even early Research Unix systems tended to just read /etc/passwd. Some tools still printed “can’t read /etc/uids” as an error, but in fact read /etc/passwd.

            I guess it was just more useful to also get the group ID and other information from one file, and keeping two files in-sync is annoying.

            1. 1

              And not only (username, uid), but also “full user name”. Not sure any tools besides finger used this much..as well as “home dir” used for shell tilde expansion, as in ~joe from ~jim’s account. That is all probably early to mid-1980s era stuff.

        2. 8

          I think if we could redesign PAM from scratch, two things we want to change would be:

          • subprocesses instead of dlopen() for the plugins. This is Unix, we might as well act like it.
          • a test harness/simulator for loading your plugin and exercising its API. So that you can do a lot of testing for plugins prior to actually wiring them up to /bin/login.
          1. 3

            Sub-processes is how BSD auth works (the pam replacement used in OoenBSD) so there’s definitely some prior art proving this approach is viable.

            1. 2

              It’s definitely interesting that essentially everyone agrees making PAM modules share address space was a bad idea, which makes me wonder why it was done in the first place. I assume it was largely a case of performance.

              1. 5

                Honestly for the time and place it was invented, it wasn’t actually as bad of an idea as you’d think. In fact it could be useful to make up for API inadequacies. However society has moved on, especially with its security requirements.

                1. 5

                  That’s a good point - you really have to define an agreed marshalling scheme for complex data types to split it along process boundaries, whereas the C ABI gives you that “for free”. Plus it means you can do stuff like sharing/passing file descriptors without needing to (ab)use fork or domain sockets. Stuff that sounds pretty reasonable in the context of portability amidst UNIX Vendor Hell.

            2. 6

              Plus I also get to use this to point out the little question mark at the end of the third line of this code blurb. See that question mark? It is an “if err != nil, return nil, err” statement. It’s handled at compile time and it will even return the Ok side of the result if there is one. God I understand why Go can’t have that nice thing but it would take at least 7 lines of code out of my keyboard firmware if we had that nice thing in Go (not to mention countless editor macros for other people).

              Laughed at this because I have done this.

              1. 1

                And to head off folks who would (rightly) say “but fmt.Errorf should be included”: that can be done with the same syntax!

                If you implement the conversion trait Into for the target error type, it’ll convert the source type for you. And certain third-party error libraries will let you get the “I just want to throw a string in there for context” with just that:

                get().context("Getting status during auth failed")?

                1. 2

                  There was serious discussion of adding a try control flow operator to Go, but the community wasn’t happy with it, and it was pointed out that it would screw up code coverage estimates. The former was damaging to the proposal, but the latter was fatal AFAICT.