Branch data Line data Source code
1 : : /*
2 : : * libdpkg - Debian packaging suite library routines
3 : : * db-fsys-override.c - management of filesystem stat overrides database
4 : : *
5 : : * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
6 : : * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
7 : : * Copyright © 2008-2012 Guillem Jover <guillem@debian.org>
8 : : *
9 : : * This is free software; you can redistribute it and/or modify
10 : : * it under the terms of the GNU General Public License as published by
11 : : * the Free Software Foundation; either version 2 of the License, or
12 : : * (at your option) any later version.
13 : : *
14 : : * This is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : : * GNU General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU General Public License
20 : : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : : */
22 : :
23 : : #include <config.h>
24 : : #include <compat.h>
25 : :
26 : : #include <sys/types.h>
27 : : #include <sys/stat.h>
28 : :
29 : : #include <errno.h>
30 : : #include <string.h>
31 : : #include <pwd.h>
32 : : #include <grp.h>
33 : : #include <fcntl.h>
34 : : #include <unistd.h>
35 : : #include <stdlib.h>
36 : :
37 : : #include <dpkg/i18n.h>
38 : : #include <dpkg/dpkg.h>
39 : : #include <dpkg/dpkg-db.h>
40 : : #include <dpkg/fdio.h>
41 : : #include <dpkg/debug.h>
42 : : #include <dpkg/db-fsys.h>
43 : :
44 : : static char *statoverridename;
45 : :
46 : : uid_t
47 : 0 : statdb_parse_uid(const char *str)
48 : : {
49 : : char *endptr;
50 : : uid_t uid;
51 : :
52 [ # # ]: 0 : if (str[0] == '#') {
53 : : long int value;
54 : :
55 : 0 : errno = 0;
56 : 0 : value = strtol(str + 1, &endptr, 10);
57 [ # # # # : 0 : if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
# # # # ]
58 : 0 : ohshit(_("invalid statoverride uid %s"), str);
59 : 0 : uid = (uid_t)value;
60 : : } else {
61 : 0 : struct passwd *pw = getpwnam(str);
62 : :
63 [ # # ]: 0 : if (pw == NULL)
64 : 0 : uid = (uid_t)-1;
65 : : else
66 : 0 : uid = pw->pw_uid;
67 : : }
68 : :
69 : 0 : return uid;
70 : : }
71 : :
72 : : gid_t
73 : 0 : statdb_parse_gid(const char *str)
74 : : {
75 : : char *endptr;
76 : : gid_t gid;
77 : :
78 [ # # ]: 0 : if (str[0] == '#') {
79 : : long int value;
80 : :
81 : 0 : errno = 0;
82 : 0 : value = strtol(str + 1, &endptr, 10);
83 [ # # # # : 0 : if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
# # # # ]
84 : 0 : ohshit(_("invalid statoverride gid %s"), str);
85 : 0 : gid = (gid_t)value;
86 : : } else {
87 : 0 : struct group *gr = getgrnam(str);
88 : :
89 [ # # ]: 0 : if (gr == NULL)
90 : 0 : gid = (gid_t)-1;
91 : : else
92 : 0 : gid = gr->gr_gid;
93 : : }
94 : :
95 : 0 : return gid;
96 : : }
97 : :
98 : : mode_t
99 : 0 : statdb_parse_mode(const char *str)
100 : : {
101 : : char *endptr;
102 : : long int mode;
103 : :
104 : 0 : mode = strtol(str, &endptr, 8);
105 [ # # # # : 0 : if (str == endptr || *endptr || mode < 0 || mode > 07777)
# # # # ]
106 : 0 : ohshit(_("invalid statoverride mode %s"), str);
107 : :
108 : 0 : return (mode_t)mode;
109 : : }
110 : :
111 : : void
112 : 0 : ensure_statoverrides(enum statdb_parse_flags flags)
113 : : {
114 : : static struct stat sb_prev;
115 : : struct stat sb_next;
116 : : static FILE *file_prev;
117 : : FILE *file;
118 : : char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
119 : : struct file_stat *fso;
120 : : struct fsys_namenode *fnn;
121 : : struct fsys_hash_iter *iter;
122 : :
123 [ # # ]: 0 : if (statoverridename == NULL)
124 : 0 : statoverridename = dpkg_db_get_path(STATOVERRIDEFILE);
125 : :
126 : 0 : onerr_abort++;
127 : :
128 : 0 : file = fopen(statoverridename, "r");
129 [ # # ]: 0 : if (!file) {
130 [ # # ]: 0 : if (errno != ENOENT)
131 : 0 : ohshite(_("failed to open statoverride file"));
132 : : } else {
133 : 0 : setcloexec(fileno(file), statoverridename);
134 : :
135 [ # # ]: 0 : if (fstat(fileno(file), &sb_next))
136 : 0 : ohshite(_("failed to fstat statoverride file"));
137 : :
138 : : /*
139 : : * We need to keep the database file open so that the
140 : : * filesystem cannot reuse the inode number (f.ex. during
141 : : * multiple dpkg-statoverride invocations in a maintainer
142 : : * script), otherwise the following check might turn true,
143 : : * and we would skip reloading a modified database.
144 : : */
145 [ # # ]: 0 : if (file_prev &&
146 [ # # ]: 0 : sb_prev.st_dev == sb_next.st_dev &&
147 [ # # ]: 0 : sb_prev.st_ino == sb_next.st_ino) {
148 : 0 : fclose(file);
149 : 0 : onerr_abort--;
150 : 0 : debug(dbg_general, "%s: same, skipping", __func__);
151 : 0 : return;
152 : : }
153 : 0 : sb_prev = sb_next;
154 : : }
155 [ # # ]: 0 : if (file_prev)
156 : 0 : fclose(file_prev);
157 : 0 : file_prev = file;
158 : :
159 : : /* Reset statoverride information. */
160 : 0 : iter = fsys_hash_iter_new();
161 [ # # ]: 0 : while ((fnn = fsys_hash_iter_next(iter)))
162 : 0 : fnn->statoverride = NULL;
163 : 0 : fsys_hash_iter_free(iter);
164 : :
165 [ # # ]: 0 : if (!file) {
166 : 0 : onerr_abort--;
167 : 0 : debug(dbg_general, "%s: none, resetting", __func__);
168 : 0 : return;
169 : : }
170 : 0 : debug(dbg_general, "%s: new, (re)loading", __func__);
171 : :
172 : : /* If the statoverride list is empty we don't need to bother
173 : : * reading it. */
174 [ # # ]: 0 : if (!sb_next.st_size) {
175 : 0 : onerr_abort--;
176 : 0 : return;
177 : : }
178 : :
179 : 0 : loaded_list = m_malloc(sb_next.st_size);
180 : 0 : loaded_list_end = loaded_list + sb_next.st_size;
181 : :
182 [ # # ]: 0 : if (fd_read(fileno(file), loaded_list, sb_next.st_size) < 0)
183 : 0 : ohshite(_("reading statoverride file '%.250s'"), statoverridename);
184 : :
185 : 0 : thisline = loaded_list;
186 [ # # ]: 0 : while (thisline < loaded_list_end) {
187 : 0 : fso = nfmalloc(sizeof(*fso));
188 : :
189 : 0 : ptr = memchr(thisline, '\n', loaded_list_end - thisline);
190 [ # # ]: 0 : if (ptr == NULL)
191 : 0 : ohshit(_("statoverride file is missing final newline"));
192 : : /* Where to start next time around. */
193 : 0 : nextline = ptr + 1;
194 [ # # ]: 0 : if (ptr == thisline)
195 : 0 : ohshit(_("statoverride file contains empty line"));
196 : 0 : *ptr = '\0';
197 : :
198 : : /* Extract the uid. */
199 : 0 : ptr = memchr(thisline, ' ', nextline - thisline);
200 [ # # ]: 0 : if (ptr == NULL)
201 : 0 : ohshit(_("syntax error in statoverride file"));
202 : 0 : *ptr = '\0';
203 : :
204 : 0 : fso->uid = statdb_parse_uid(thisline);
205 [ # # ]: 0 : if (fso->uid == (uid_t)-1)
206 : 0 : fso->uname = nfstrsave(thisline);
207 : : else
208 : 0 : fso->uname = NULL;
209 : :
210 [ # # # # ]: 0 : if (fso->uid == (uid_t)-1 && !(flags & STATDB_PARSE_LAX))
211 : 0 : ohshit(_("unknown system user '%s' in statoverride file; the system user got removed\n"
212 : : "before the override, which is most probably a packaging bug, to recover you\n"
213 : : "can remove the override manually with %s"), thisline, DPKGSTAT);
214 : :
215 : : /* Move to the next bit */
216 : 0 : thisline = ptr + 1;
217 [ # # ]: 0 : if (thisline >= loaded_list_end)
218 : 0 : ohshit(_("unexpected end of line in statoverride file"));
219 : :
220 : : /* Extract the gid */
221 : 0 : ptr = memchr(thisline, ' ', nextline - thisline);
222 [ # # ]: 0 : if (ptr == NULL)
223 : 0 : ohshit(_("syntax error in statoverride file"));
224 : 0 : *ptr = '\0';
225 : :
226 : 0 : fso->gid = statdb_parse_gid(thisline);
227 [ # # ]: 0 : if (fso->gid == (gid_t)-1)
228 : 0 : fso->gname = nfstrsave(thisline);
229 : : else
230 : 0 : fso->gname = NULL;
231 : :
232 [ # # # # ]: 0 : if (fso->gid == (gid_t)-1 && !(flags & STATDB_PARSE_LAX))
233 : 0 : ohshit(_("unknown system group '%s' in statoverride file; the system group got removed\n"
234 : : "before the override, which is most probably a packaging bug, to recover you\n"
235 : : "can remove the override manually with %s"), thisline, DPKGSTAT);
236 : :
237 : : /* Move to the next bit */
238 : 0 : thisline = ptr + 1;
239 [ # # ]: 0 : if (thisline >= loaded_list_end)
240 : 0 : ohshit(_("unexpected end of line in statoverride file"));
241 : :
242 : : /* Extract the mode */
243 : 0 : ptr = memchr(thisline, ' ', nextline - thisline);
244 [ # # ]: 0 : if (ptr == NULL)
245 : 0 : ohshit(_("syntax error in statoverride file"));
246 : 0 : *ptr = '\0';
247 : :
248 : 0 : fso->mode = statdb_parse_mode(thisline);
249 : :
250 : : /* Move to the next bit */
251 : 0 : thisline = ptr + 1;
252 [ # # ]: 0 : if (thisline >= loaded_list_end)
253 : 0 : ohshit(_("unexpected end of line in statoverride file"));
254 : :
255 : 0 : fnn = fsys_hash_find_node(thisline, 0);
256 [ # # ]: 0 : if (fnn->statoverride)
257 : 0 : ohshit(_("multiple statoverrides present for file '%.250s'"),
258 : : thisline);
259 : 0 : fnn->statoverride = fso;
260 : :
261 : : /* Moving on... */
262 : 0 : thisline = nextline;
263 : : }
264 : :
265 : 0 : free(loaded_list);
266 : :
267 : 0 : onerr_abort--;
268 : : }
|