userdb: add birthDate field to JSON user records#40954
Conversation
303e1c4 to
418cc85
Compare
418cc85 to
e704ee3
Compare
|
The clang-tidy test failures appear to be pre-existing and don't seem to be related to my code. https://github.com/systemd/systemd/actions/runs/22697752278/job/65807875286?pr=40954 |
e704ee3 to
4110739
Compare
a60422b to
573b071
Compare
|
Sorry but I do actually mind a lot, as getting this right is extremely important, and it cannot get kicked in the long grass, so please fix it here, as there's no rush anyway and there's all the time in the world as we have to do a release anyway right now - thanks |
51fad6d to
23c6113
Compare
|
@bluca I've updated this PR so that it's not marked as sensitive again. |
That's great, thanks, but the earlier feedback was that explicit memory clearing and so on is too much for these, which is true. So please look into adding a new flag that doesn't do any of that, but just scrubs the field from dumps/logs/etc. That way everyone should be happy |
|
Hmm, do we really care? The additional clearing of memory if a milisecond or two of CPU time. I don't think we should get into the business of distinguishing whether a field is sensitive enough to wipe it or not… Why not just do the easy thing and always wipe it? |
Adding a whole new flag to avoid a few extra CPU cycles seems silly. This is completely negligible performance-wise. |
Personally I'm fine with it and have no issue one way or the other, and am ok with either option. But Lennart's feedback was that he didn't want these to be the same as password, with memory wiping and so on, hence why I proposed to add a new flag that goes halfway, as a compromise to try and make everyone happy: #40954 (comment) |
What I don't like about that is that would introduce complexity and it touch the code in more places. We'd probably have to add conditionals on whether or not to clear memory, which is a very cheap operation for something like a date of birth or a short string. I think adding a separate version of |
|
Yeah. The runtime complexity is negligible. I'd like to avoid the cognitive overhead of deciding between "this field is sensitive" and "this field is even more sensitive, needs to be wiped". |
|
I'm Jeremy from System76. We are in talks with legislators and there are likely to be amendments to the age verification bills, as well as conflicting requirements in different jurisdictions. It may even be the case that open source operating systems are exempted entirely. I detailed this on the xdg mailing list here: I have other concerns about this specific implementation. By relying on systemd, which is decidedly unportable to non-Linux operating systems, and not used across all Linux operating systems either, it will force at least one alternative implementation to exist. If these implementations end up having to collect jurisdiction specific requirements, that makes it much harder for compliance. |
It is possible that California law will be changed. But similar ideas are popping up in other contexts and it's unlikely that they'll all go away. This implementation is fairly generic and useful for other things besides age verification, so we shouldn't decide whether to merge it or not based on a single law in any jurisdiction.
The API is generic, so somebody can try to reimplement it later if they want to avoid this implementation. But for 99% of systems out there, putting it in systemd is very reasonable. |
The California and Colorado law do not require storing a date of birth, which is indirectly identifying PII in the US. An age could instead be stored. Yes, this means that the age bracket could be under-estimated, and may then need to be manually updated to unlock things, but it would significantly reduce the ability to determine an exact person from data stored on the filesystem. The point I want to illustrate is that an operating system using systemd and provided in one of these jurisdictions may want to store an alternative form of data to comply, with a minimum potentially being the age bracket itself. The piece of data stored may end up being jurisdiction dependent, with some jurisdictions explicitly forbidding the storage of an exact birthday while others explicitly require it.
I don't disagree that the userdb varlink API could be implemented on other open-source operating systems, and that systemd covers a wide set of them. |
So are the name and location. This is a user account mechanism, so it stores various information, including PII, as it's obvious it needs to. What upper layers do with that information, and whether to store it in the first place, is up to them, and is independent of specific requirements and whatnot. This implementation can be used just fine to implement any variety of requirements, or none at all, so it's fine as it is. |
|
This clearly got linked somewhere, so let's lock it for a while to avoid spam |
|
i still find the marking as sensitive silly, but i also don't care enough. lgtm |
|
@dylanmtaylor in the future, no need to request re-review… People who commented are notified automatically. |
|
Follow-up work (not in this PR): The accountsservice PR changed to require polkit authentication before showing the user's birthdate, even if you're the user yourself. Essentially, this constitutes a section in userdb similar to In userdb's case, I think it makes sense to keep |
|
BTW, just to emphasize this, and explain why i think adding this to userdb is fine: i actually believe that making sure apps cannot just read the birthday field is a good idea, but it's just one tiny piece of data among so so much more important stuff. if people run apps unsandboxed these apps get access to any file in $HOME and a tonload more stuff of the system. And that data is a lot more valuable than the birthday is. Hence, let's maybe not waste discussion around isolating apps from that single piece of information that is the birthday, while leaving everything else wide open. The answer to the PII issues is hence not restrictions in userdb, the answer is proper app sandboxing. And that even already exists in flatpak! It restricts access to $HOME already, and to userdb too! And that's the way to do it! Hence, just embrace app sandboxing! And if you come to me and say "hey, I run all my apps without sandboxing, but i want the birthday hidden anyway" then I can only say, your model is really really broken. Fix your security model first, then come back. So, I think userdb should reveal the birthday to per-user code, because that per-user code then can consume this and provide a portal or something to properly sandboxed apps that provides a more restrictive api, i.e. age brackets and so on. But that kind of stuff is outside of the scope of systemd, here in systemd we just provide you with a way to maintain the original data, the precise policy enforcement on it must happen in the sandbox. |
|
@claude review |
Move the YYYY-MM-DD date parsing and validation logic from sysupdate-resource.c into a shared parse_calendar_date() function in time-util, so it can be reused by other subsystems.
Add a birthDate field to the JSON user record, stored internally as a struct tm with INT_MIN/negative sentinels for unset fields. The field is serialized as a YYYY-MM-DD string in JSON and validated via parse_birth_date(), which shares its core logic with parse_calendar_date() through a new parse_calendar_date_full() function. For birth dates, timegm() is called directly (rather than mktime_or_timegm_usec) to support pre-epoch dates. The wday field is used to distinguish timegm() failure from a valid (time_t) -1 return. birthDate is excluded from user_record_self_modifiable_fields(), so only administrators can set or change it via homectl. The field remains in the regular (non-privileged) JSON section, keeping it readable by the user and applications.
Stores the user's birth date for age verification, as required by recent laws
in California (AB-1043), Colorado (SB26-051), Brazil (Lei 15.211/2025), etc.
The xdg-desktop-portal project is adding an age verification portal
(flatpak/xdg-desktop-portal#1922) that needs a data source for the user's age.
userdb already stores personal metadata (
emailAddress,realName,location)so
birthDateis a natural fit.Full date rather than just birth year: birth year alone has up to ~12 months of
imprecision at age boundaries, which could misclassify a 17-year-old as 18 or
vice versa.
Authorization
birthDateis excluded fromuser_record_self_modifiable_fields(), so onlyadministrators can set or change it via
homectl. The field remains in theregular (non-privileged) JSON section, keeping it readable by the user and
applications (e.g. xdg-desktop-portal).
Related