From patchwork Mon Sep 30 11:35:41 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lennart Poettering X-Patchwork-Id: 1990913 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=8.43.85.97; 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 [8.43.85.97]) (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 4XHJtH74sLz1xsc for ; Mon, 30 Sep 2024 21:36:07 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F09BA3860776 for ; Mon, 30 Sep 2024 11:36:05 +0000 (GMT) X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from gardel.0pointer.net (gardel.0pointer.net [IPv6:2a01:238:43ed:c300:10c3:bcf3:3266:da74]) by sourceware.org (Postfix) with ESMTPS id 3C72B3858D20 for ; Mon, 30 Sep 2024 11:35:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3C72B3858D20 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 3C72B3858D20 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2a01:238:43ed:c300:10c3:bcf3:3266:da74 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727696150; cv=none; b=xNYF941Ko4z39nkg9iY1czjKrVHXbLKUNsBOBlZgNBuRns+ckf17fXfztO8Up1KnSShLJ4UQ2lt7EQlRFJVvSHrxdFy4Wp2u2PnIsyHY3gSOWPDeHc0Nro1+WaPEWgd3EFLvnmnmoUBpHkvc7DZ+mW+ytHuvUeB3xxSS3dV1+Jk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1727696150; c=relaxed/simple; bh=hcpuWjIRhLzzUYLUHDXx4g3pidrzfA0/dcF+OFvBv1Q=; h=Date:From:To:Subject:Message-ID:MIME-Version; b=jWOUVOBhJJc6ieiq25rR2JTsf3LDhxJ4/lH2hY+xZNTRH7gEospgJu5RxxtBVpsu5/JdZZFp/clCmGLTFQMbhe+D+7o6h7ThqO1R1ZDgBKy7hKi+N0GGGOexQfL1YhLApgeEELyAz7jwWXHx6CWYKf+ue3jDU/2ZN87pu2hqeQc= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from gardel-login.0pointer.net (gardel-mail [IPv6:2a01:238:43ed:c300:10c3:bcf3:3266:da74]) by gardel.0pointer.net (Postfix) with ESMTP id 5B0D8E8037C for ; Mon, 30 Sep 2024 13:35:44 +0200 (CEST) Received: by gardel-login.0pointer.net (Postfix, from userid 1000) id CC72A1601C9; Mon, 30 Sep 2024 13:35:41 +0200 (CEST) Date: Mon, 30 Sep 2024 13:35:41 +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.3 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()) --- 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 | 26 ++++++++++++++++++++++++++ 12 files changed, 53 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..7e467e89ce 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,26 @@ __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 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 || errno != ENOENT) + return fp; + + strcpy (stpcpy (buf, FALLBACK_PREFIX), database); + return __nss_files_fopen (buf); +} +libc_hidden_def (__nss_files_fopen_database)