From patchwork Mon Sep 30 12:48:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lennart Poettering X-Patchwork-Id: 1990970 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XHLTw3lGLz1xt8 for ; Mon, 30 Sep 2024 22:48:36 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 57BC63858D26 for ; Mon, 30 Sep 2024 12:48:34 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from gardel.0pointer.net (gardel.0pointer.net [85.214.157.71]) by sourceware.org (Postfix) with ESMTPS id D89F73858D26 for ; Mon, 30 Sep 2024 12:48:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D89F73858D26 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=poettering.net Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=poettering.net ARC-Filter: OpenARC Filter v1.0.0 sourceware.org D89F73858D26 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=85.214.157.71 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727700497; cv=none; b=nKKm6H42W1KDeGku+ojWGIx9PajpSEuw0F2Jc6k7GzlB3T4391/OSw3RoyFrtT3WfoFzjs96anmbZRE//NIMHNJf5mPaE59ktho4zMR8oxliMpEHeJ6XFXs30G1pnzuqNRaX+8ra+VniKSbScnlbR9k8C5emsBPah/U78NBSYhM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727700497; c=relaxed/simple; bh=+roXGIDMl4kbWy3RN6TdIb8pbrFy6cLMijvDX0qXuyo=; h=Date:From:To:Subject:Message-ID:MIME-Version; b=SMDbVPZh4545KONG4fZXCFxRYnBV0vM/kFnz4YzAvpxP2vl8D+J206V6wLyL3Uiixsx/W0cSgEpuCij/XNYNd5BegwOZAJB/LDrRSWCFu5u+WmBNTDc+XbUosfh0i80KG3nqZarCC0UTnzYfZbOjzLXySxAp2eSFDR2SJG21wko= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from gardel-login.0pointer.net (gardel-mail [85.214.157.71]) by gardel.0pointer.net (Postfix) with ESMTP id 7342FE8037C for ; Mon, 30 Sep 2024 14:48:05 +0200 (CEST) Received: by gardel-login.0pointer.net (Postfix, from userid 1000) id 2BCD01601C9; Mon, 30 Sep 2024 14:48:05 +0200 (CEST) Date: Mon, 30 Sep 2024 14:48:05 +0200 From: Lennart Poettering To: libc-alpha@sourceware.org Subject: [PATCH] nss: look for databases in /usr/share/nss/ if they don't exist in /etc/ Message-ID: MIME-Version: 1.0 Content-Disposition: inline X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org In order to improve compatibility with systems that implement a hermetic /usr/, this changes glibc NSS code to always look for its databases files in /usr/share/nss/ too in case they don't exist (ENOENT) in /etc/. This allows distributions to move /etc/protocols and similar data files into /usr/share/nss/. These days various of these files are kinda static anyway, and hence in many cases are better placed below the /usr/ hierarchy than below the configurable /etc/. This change should have zero effect on existing systems, as any database file in /etc/ will be consulted first, and only on ENOENT the matching counterpart in /usr/share/nss/ will be attempted. This also provides a clear path how administrators can still modify the files locally if they want to: just copy them from /usr/share/nss/ to /etc/ and edit them there. In that case the files in /usr/share/nss/ will have no effect anymore. Many systems that want to achieve this behaviour currently work around glibc's behaviour via modules such as nss-altfiles, an excercise that becomes unnecessary if glibc just directly looks at these fallback places. (Note that nss-altfiles has different semantics though, it merges rather then replaces the files) Also see: https://github.com/uapi-group/specifications/issues/76 (2nd version of the patch: moved from /usr/share/ to /usr/share/nss/, and I am now generating these two paths via stpcpy()/strcpy().) (3rd version of the patch: fallback on more errnos than just ENOENT.) --- include/nss_files.h | 8 ++++-- nss/Versions | 2 +- nss/nss_compat/compat-grp.c | 2 +- nss/nss_compat/compat-initgroups.c | 2 +- nss/nss_compat/compat-pwd.c | 2 +- nss/nss_compat/compat-spwd.c | 2 +- nss/nss_files/files-XXX.c | 8 +++--- nss/nss_files/files-alias.c | 7 +++--- nss/nss_files/files-initgroups.c | 2 +- nss/nss_files/files-netgrp.c | 4 +-- nss/nss_files_data.c | 12 ++++----- nss/nss_files_fopen.c | 40 ++++++++++++++++++++++++++++++ 12 files changed, 67 insertions(+), 24 deletions(-) -- 2.46.0 diff --git a/include/nss_files.h b/include/nss_files.h index adf934f3ea..c224dabe5f 100644 --- a/include/nss_files.h +++ b/include/nss_files.h @@ -25,6 +25,10 @@ #include #endif +/* Open DATABASE for reading. */ +FILE *__nss_files_fopen_database (const char *database); +libc_hidden_proto (__nss_files_fopen_database) + /* Open PATH for reading, as a data source for nss_files. */ FILE *__nss_files_fopen (const char *path); libc_hidden_proto (__nss_files_fopen) @@ -89,7 +93,7 @@ enum nss_files_file null. */ enum nss_status __nss_files_data_open (struct nss_files_per_file_data **pdata, enum nss_files_file file, - const char *path, + const char *database, int *errnop, int *herrnop); libc_hidden_proto (__nss_files_data_open) @@ -101,7 +105,7 @@ libc_hidden_proto (__nss_files_data_put) /* Performs the set*ent operation for FILE. PATH is the file to open. */ enum nss_status __nss_files_data_setent (enum nss_files_file file, - const char *path); + const char *database); libc_hidden_proto (__nss_files_data_setent) /* Performs the end*ent operation for FILE. */ diff --git a/nss/Versions b/nss/Versions index d765e1d3b6..9ea298cec0 100644 --- a/nss/Versions +++ b/nss/Versions @@ -108,7 +108,7 @@ libc { __nss_passwd_lookup2; __nss_group_lookup2; __nss_hosts_lookup2; __nss_services_lookup2; __nss_next2; __nss_lookup; __nss_hash; __nss_database_get; - __nss_files_fopen; __nss_readline; __nss_parse_line_result; + __nss_files_fopen; __nss_files_fopen_database; __nss_readline; __nss_parse_line_result; __nss_files_data_endent; __nss_files_data_open; __nss_files_data_put; diff --git a/nss/nss_compat/compat-grp.c b/nss/nss_compat/compat-grp.c index ede7503de7..3a9dcedb6a 100644 --- a/nss/nss_compat/compat-grp.c +++ b/nss/nss_compat/compat-grp.c @@ -108,7 +108,7 @@ internal_setgrent (ent_t *ent, int stayopen, int needent) if (ent->stream == NULL) { - ent->stream = __nss_files_fopen ("/etc/group"); + ent->stream = __nss_files_fopen_database ("group"); if (ent->stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; diff --git a/nss/nss_compat/compat-initgroups.c b/nss/nss_compat/compat-initgroups.c index 2598cfbc9a..2acef020ef 100644 --- a/nss/nss_compat/compat-initgroups.c +++ b/nss/nss_compat/compat-initgroups.c @@ -122,7 +122,7 @@ internal_setgrent (ent_t *ent) else ent->blacklist.current = 0; - ent->stream = __nss_files_fopen ("/etc/group"); + ent->stream = __nss_files_fopen_database ("group"); if (ent->stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; diff --git a/nss/nss_compat/compat-pwd.c b/nss/nss_compat/compat-pwd.c index 2f37e0f621..a7220dcd58 100644 --- a/nss/nss_compat/compat-pwd.c +++ b/nss/nss_compat/compat-pwd.c @@ -223,7 +223,7 @@ internal_setpwent (ent_t *ent, int stayopen, int needent) if (ent->stream == NULL) { - ent->stream = __nss_files_fopen ("/etc/passwd"); + ent->stream = __nss_files_fopen_database ("passwd"); if (ent->stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; diff --git a/nss/nss_compat/compat-spwd.c b/nss/nss_compat/compat-spwd.c index fac1e766cb..a67edb0ea8 100644 --- a/nss/nss_compat/compat-spwd.c +++ b/nss/nss_compat/compat-spwd.c @@ -178,7 +178,7 @@ internal_setspent (ent_t *ent, int stayopen, int needent) if (ent->stream == NULL) { - ent->stream = __nss_files_fopen ("/etc/shadow"); + ent->stream = __nss_files_fopen_database ("shadow"); if (ent->stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; diff --git a/nss/nss_files/files-XXX.c b/nss/nss_files/files-XXX.c index 558b2c364f..8537bb4410 100644 --- a/nss/nss_files/files-XXX.c +++ b/nss/nss_files/files-XXX.c @@ -39,8 +39,6 @@ #define ENTNAME_r CONCAT(ENTNAME,_r) -#define DATAFILE "/etc/" DATABASE - #ifdef NEED_H_ERRNO # include # define H_ERRNO_PROTO , int *herrnop @@ -73,7 +71,7 @@ internal_setent (FILE **stream) if (*stream == NULL) { - *stream = __nss_files_fopen (DATAFILE); + *stream = __nss_files_fopen_database (DATABASE); if (*stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; @@ -89,7 +87,7 @@ internal_setent (FILE **stream) enum nss_status CONCAT(_nss_files_set,ENTNAME) (int stayopen) { - return __nss_files_data_setent (CONCAT (nss_file_, ENTNAME), DATAFILE); + return __nss_files_data_setent (CONCAT (nss_file_, ENTNAME), DATABASE); } libc_hidden_def (CONCAT (_nss_files_set,ENTNAME)) @@ -170,7 +168,7 @@ CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer, struct nss_files_per_file_data *data; enum nss_status status = __nss_files_data_open (&data, CONCAT (nss_file_, ENTNAME), - DATAFILE, + DATABASE, errnop, H_ERRNO_ARG_OR_NULL); if (status != NSS_STATUS_SUCCESS) return status; diff --git a/nss/nss_files/files-alias.c b/nss/nss_files/files-alias.c index 14a59b4655..961e248317 100644 --- a/nss/nss_files/files-alias.c +++ b/nss/nss_files/files-alias.c @@ -42,7 +42,7 @@ internal_setent (FILE **stream) if (*stream == NULL) { - *stream = __nss_files_fopen ("/etc/aliases"); + *stream = __nss_files_fopen_database ("aliases"); if (*stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; @@ -58,7 +58,7 @@ internal_setent (FILE **stream) enum nss_status _nss_files_setaliasent (void) { - return __nss_files_data_setent (nss_file_aliasent, "/etc/aliases"); + return __nss_files_data_setent (nss_file_aliasent, "aliases"); } libc_hidden_def (_nss_files_setaliasent) @@ -338,7 +338,8 @@ _nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen, struct nss_files_per_file_data *data; enum nss_status status = __nss_files_data_open (&data, nss_file_aliasent, - "/etc/aliases", errnop, NULL); + "aliases", + errnop, NULL); if (status != NSS_STATUS_SUCCESS) return status; diff --git a/nss/nss_files/files-initgroups.c b/nss/nss_files/files-initgroups.c index 65189d3929..bec3a293c5 100644 --- a/nss/nss_files/files-initgroups.c +++ b/nss/nss_files/files-initgroups.c @@ -33,7 +33,7 @@ _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start, long int *size, gid_t **groupsp, long int limit, int *errnop) { - FILE *stream = __nss_files_fopen ("/etc/group"); + FILE *stream = __nss_files_fopen_database ("group"); if (stream == NULL) { *errnop = errno; diff --git a/nss/nss_files/files-netgrp.c b/nss/nss_files/files-netgrp.c index 92d8062e43..8c8ad6c21f 100644 --- a/nss/nss_files/files-netgrp.c +++ b/nss/nss_files/files-netgrp.c @@ -27,7 +27,7 @@ #include "netgroup.h" #include -#define DATAFILE "/etc/netgroup" +#define DATABASE "netgroup" libc_hidden_proto (_nss_files_endnetgrent) @@ -62,7 +62,7 @@ _nss_files_setnetgrent (const char *group, struct __netgrent *result) return NSS_STATUS_UNAVAIL; /* Find the netgroups file and open it. */ - fp = __nss_files_fopen (DATAFILE); + fp = __nss_files_fopen_database (DATABASE); if (fp == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; else diff --git a/nss/nss_files_data.c b/nss/nss_files_data.c index 261a01a775..1fab3b03b5 100644 --- a/nss/nss_files_data.c +++ b/nss/nss_files_data.c @@ -74,13 +74,13 @@ __nss_files_data_get (struct nss_files_per_file_data **pdata, /* Helper function for opening the backing file at PATH. */ static enum nss_status __nss_files_data_internal_open (struct nss_files_per_file_data *data, - const char *path) + const char *database) { enum nss_status status = NSS_STATUS_SUCCESS; if (data->stream == NULL) { - data->stream = __nss_files_fopen (path); + data->stream = __nss_files_fopen_database (database); if (data->stream == NULL) status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL; @@ -92,7 +92,7 @@ __nss_files_data_internal_open (struct nss_files_per_file_data *data, enum nss_status __nss_files_data_open (struct nss_files_per_file_data **pdata, - enum nss_files_file file, const char *path, + enum nss_files_file file, const char *database, int *errnop, int *herrnop) { enum nss_status status = __nss_files_data_get (pdata, file, errnop, herrnop); @@ -103,7 +103,7 @@ __nss_files_data_open (struct nss_files_per_file_data **pdata, if ((*pdata)->stream == NULL) { int saved_errno = errno; - status = __nss_files_data_internal_open (*pdata, path); + status = __nss_files_data_internal_open (*pdata, database); __set_errno (saved_errno); if (status != NSS_STATUS_SUCCESS) __nss_files_data_put (*pdata); @@ -122,7 +122,7 @@ __nss_files_data_put (struct nss_files_per_file_data *data) libc_hidden_def (__nss_files_data_put) enum nss_status -__nss_files_data_setent (enum nss_files_file file, const char *path) +__nss_files_data_setent (enum nss_files_file file, const char *database) { struct nss_files_per_file_data *data; enum nss_status status = __nss_files_data_get (&data, file, NULL, NULL); @@ -130,7 +130,7 @@ __nss_files_data_setent (enum nss_files_file file, const char *path) return status; if (data->stream == NULL) - status = __nss_files_data_internal_open (data, path); + status = __nss_files_data_internal_open (data, database); else rewind (data->stream); diff --git a/nss/nss_files_fopen.c b/nss/nss_files_fopen.c index e7c48d7bd8..307d1f61d4 100644 --- a/nss/nss_files_fopen.c +++ b/nss/nss_files_fopen.c @@ -21,6 +21,9 @@ #include #include +#define PRIMARY_PREFIX "/etc/" +#define FALLBACK_PREFIX "/usr/share/nss/" + FILE * __nss_files_fopen (const char *path) { @@ -45,3 +48,40 @@ __nss_files_fopen (const char *path) return fp; } libc_hidden_def (__nss_files_fopen) + +FILE * +__nss_files_fopen_database (const char *database) +{ + char buf[sizeof(FALLBACK_PREFIX) + NAME_MAX]; + + /* Protect against string overflow */ + size_t n = strlen (database); + if (n > NAME_MAX) + { + __set_errno (EINVAL); + return NULL; + } + + strcpy (stpcpy (buf, PRIMARY_PREFIX), database); + FILE *fp = __nss_files_fopen (buf); + if (fp != NULL) + return fp; + switch (errno) + { + case ENOENT: + case EISDIR: + case ENOTDIR: + case ELOOP: + /* If the path does not exist or is incorrectly set up, let's try to use the fallback database */ + break; + + default: + /* Propagate all other errors (in particular EACCESS) to the caller, since we shouldn't accidentally use + * the wrong database just because some MAC (or so) prohibited access to the primary database. */ + return NULL; + } + + strcpy (stpcpy (buf, FALLBACK_PREFIX), database); + return __nss_files_fopen (buf); +} +libc_hidden_def (__nss_files_fopen_database)