@@ -1526,7 +1526,7 @@ pub const UserInfo = struct {
1526
1526
gid : posix.gid_t ,
1527
1527
};
1528
1528
1529
- /// POSIX function which gets a uid from username.
1529
+ /// POSIX function which gets a uid and gid from username.
1530
1530
pub fn getUserInfo (name : []const u8 ) ! UserInfo {
1531
1531
return switch (native_os ) {
1532
1532
.linux ,
@@ -1547,9 +1547,27 @@ pub fn getUserInfo(name: []const u8) !UserInfo {
1547
1547
};
1548
1548
}
1549
1549
1550
- /// TODO this reads /etc/passwd. But sometimes the user/id mapping is in something else
1551
- /// like NIS, AD, etc. See `man nss` or look at an strace for `id myuser`.
1550
+ /// POSIX function to fetch uid and gid from username.
1551
+ ///
1552
+ /// Uses the `getpwnam` when linking against libc, otherwise reads from `/etc/passwd`.
1552
1553
pub fn posixGetUserInfo (name : []const u8 ) ! UserInfo {
1554
+ // Prefer getpwnam when linking against libc, as it looks not only in /etc/passwd,
1555
+ // but also in other sources like NIS, LDAP, Directory Services on MacOS, etc.
1556
+ // See https://man7.org/linux/man-pages/man3/getpwnam.3.html
1557
+ if (builtin .link_libc ) {
1558
+ // Make \0 terminated string.
1559
+ // 256 is a safe buffer size to cover all modern systems.
1560
+ var name_buf : [256 ]u8 = undefined ;
1561
+ const name_z = try std .fmt .bufPrintZ (& name_buf , "{s}" , .{name });
1562
+
1563
+ const passwd = std .c .getpwnam (name_z ) orelse return error .UserNotFound ;
1564
+
1565
+ return UserInfo {
1566
+ .uid = passwd .uid ,
1567
+ .gid = passwd .gid ,
1568
+ };
1569
+ }
1570
+
1553
1571
const file = try std .fs .openFileAbsolute ("/etc/passwd" , .{});
1554
1572
defer file .close ();
1555
1573
@@ -1651,6 +1669,18 @@ pub fn posixGetUserInfo(name: []const u8) !UserInfo {
1651
1669
}
1652
1670
}
1653
1671
1672
+ test posixGetUserInfo {
1673
+ if (! builtin .link_libc ) return error .SkipZigTest ;
1674
+
1675
+ const nobody = try posixGetUserInfo ("nobody" );
1676
+ try testing .expect (nobody .uid != 0 );
1677
+ try testing .expect (nobody .gid != 0 );
1678
+
1679
+ // Test with a non-existing user.
1680
+ const err = posixGetUserInfo ("non_existing_user" );
1681
+ try testing .expectError (error .UserNotFound , err );
1682
+ }
1683
+
1654
1684
pub fn getBaseAddress () usize {
1655
1685
switch (native_os ) {
1656
1686
.linux = > {
0 commit comments