gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1572Shell 203Rust 109Markdown 993728 Sutichaykuna

⎇ main recipes/incoming-gnome/accountsservice-fgetspent_r-musl.patch 103 siq'ikuna · 4.2 KB Ñawpa willay ch'uya

gnome: accountsservice SELLA (b3:0328b0d0) — cae la frontera de la C-ABI de logind 08fc1d4b9 · sergio ·

1accountsservice bajo musl: `fgetspent_r` no existe.
2
3QUÉ ES: la variante reentrante de la API de /etc/shadow. Es **extensión de glibc** — musl provee
4`fgetspent()` (no reentrante) y `getspnam_r()`, pero no ésta. La usa `src/daemon.c` en el bucle que
5lee /etc/shadow para decidir qué cuentas son locales.
6
7POR QUÉ NO ALCANZA CON USAR `fgetspent()` A SECAS: el llamador GUARDA los buffers. Cada iteración
8reserva un `shadow_entry_buffers` y lo mete en un GHashTable indexado por nombre de usuario; después
9de leer el fichero entero, consulta esa tabla. `fgetspent()` devuelve un puntero a un `struct spwd`
10ESTÁTICO cuyas cadenas se reescriben en la llamada siguiente, así que sustituirla a secas dejaría
11todas las entradas de la tabla apuntando al último usuario leído. Silencioso y falso — justo lo que
12no se puede permitir un servicio que responde "¿esta cuenta es local?".
13
14LO QUE HACE EL PARCHE: implementa `fgetspent_r()` sobre `fgetspent()`, copiando las dos cadenas del
15registro (`sp_namp`, `sp_pwdp`) al buffer que pasa el llamador y los campos numéricos por valor. Con
16eso cada entrada de la tabla es dueña de su copia y la semántica vuelve a ser la de glibc.
17
18DÓNDE VIVE: en `src/fgetspent_r.c`, incluido desde `daemon.c` bajo `#ifndef HAVE_FGETSPENT_R`. **Es
19el patrón que accountsservice YA usa**: trae un `src/fgetpwent.c` propio incluido bajo
20`#ifndef HAVE_FGETPWENT` para el mismo problema con /etc/passwd (upstream lo escribió para plataformas
21sin esa función). O sea que el parche no inventa una estructura: extiende la que el proyecto eligió.
22El símbolo `HAVE_FGETSPENT_R` no lo define nunca su meson, así que la rama entra siempre; se deja el
23`#ifndef` igual, para que el día que lo definan esto se apague solo.
24
25CONTRATO: 0 si leyó un registro; `ENOENT` en fin de fichero; `ERANGE` si el buffer del llamador se
26queda corto — los mismos valores que devuelve glibc, que es lo que `daemon.c` espera (`ret == 0`, y
27si no corta el bucle salvo EINTR).
28
29diff -Naur a/src/daemon.c b/src/daemon.c
30--- a/src/daemon.c
31+++ b/src/daemon.c
32@@ -175,6 +175,10 @@
33 #include "fgetpwent.c"
34 #endif
35 
36+#ifndef HAVE_FGETSPENT_R
37+#include "fgetspent_r.c"
38+#endif
39+
40 #ifndef MAX_LOCAL_USERS
41 #define MAX_LOCAL_USERS 50
42 #endif
43diff -Naur a/src/fgetspent_r.c b/src/fgetspent_r.c
44--- a/src/fgetspent_r.c	1969-12-31 20:00:00.000000000 -0400
45+++ b/src/fgetspent_r.c
46@@ -0,0 +1,57 @@
47+/* fgetspent_r() para musl — ver recipes/incoming-gnome/accountsservice-fgetspent_r-musl.patch
48+ *
49+ * musl no trae esta extension de glibc. Se implementa sobre fgetspent(), que si tiene, copiando
50+ * el registro al buffer del llamador: daemon.c GUARDA esos buffers en un GHashTable, asi que no
51+ * puede quedarse con el struct estatico que fgetspent() reusa en cada llamada.
52+ */
53+
54+static int
55+fgetspent_r (FILE         *fp,
56+             struct spwd  *result_buf,
57+             char         *buffer,
58+             size_t        buflen,
59+             struct spwd **result)
60+{
61+        struct spwd *ent;
62+        size_t namp_len;
63+        size_t pwdp_len;
64+        size_t needed;
65+
66+        if (result != NULL) {
67+                *result = NULL;
68+        }
69+        if (fp == NULL || result_buf == NULL || buffer == NULL || result == NULL) {
70+                return EINVAL;
71+        }
72+
73+        errno = 0;
74+        ent = fgetspent (fp);
75+        if (ent == NULL) {
76+                /* Fin de fichero (o linea invalida): glibc devuelve ENOENT. */
77+                return errno != 0 ? errno : ENOENT;
78+        }
79+
80+        namp_len = ent->sp_namp != NULL ? strlen (ent->sp_namp) + 1 : 0;
81+        pwdp_len = ent->sp_pwdp != NULL ? strlen (ent->sp_pwdp) + 1 : 0;
82+        needed = namp_len + pwdp_len;
83+        if (needed > buflen) {
84+                return ERANGE;
85+        }
86+
87+        *result_buf = *ent;
88+        result_buf->sp_namp = NULL;
89+        result_buf->sp_pwdp = NULL;
90+
91+        if (namp_len > 0) {
92+                memcpy (buffer, ent->sp_namp, namp_len);
93+                result_buf->sp_namp = buffer;
94+                buffer += namp_len;
95+        }
96+        if (pwdp_len > 0) {
97+                memcpy (buffer, ent->sp_pwdp, pwdp_len);
98+                result_buf->sp_pwdp = buffer;
99+        }
100+
101+        *result = result_buf;
102+        return 0;
103+}