dpkg (1.18.25) stretch; urgency=medium
[dpkg] / src / statdb.c
CommitLineData
1479465f
GJ
1/*
2 * dpkg - main program for package management
3 * statdb.c - management of database of ownership and mode of files
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
42#include "filesdb.h"
43#include "main.h"
44
45static char *statoverridename;
46
47uid_t
48statdb_parse_uid(const char *str)
49{
50 char *endptr;
51 uid_t uid;
52
53 if (str[0] == '#') {
54 long int value;
55
56 errno = 0;
57 value = strtol(str + 1, &endptr, 10);
58 if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
59 ohshit(_("invalid statoverride uid %s"), str);
60 uid = (uid_t)value;
61 } else {
62 struct passwd *pw = getpwnam(str);
63
64 if (pw == NULL)
65 uid = (uid_t)-1;
66 else
67 uid = pw->pw_uid;
68 }
69
70 return uid;
71}
72
73gid_t
74statdb_parse_gid(const char *str)
75{
76 char *endptr;
77 gid_t gid;
78
79 if (str[0] == '#') {
80 long int value;
81
82 errno = 0;
83 value = strtol(str + 1, &endptr, 10);
84 if (str + 1 == endptr || *endptr || value < 0 || errno != 0)
85 ohshit(_("invalid statoverride gid %s"), str);
86 gid = (gid_t)value;
87 } else {
88 struct group *gr = getgrnam(str);
89
90 if (gr == NULL)
91 gid = (gid_t)-1;
92 else
93 gid = gr->gr_gid;
94 }
95
96 return gid;
97}
98
99mode_t
100statdb_parse_mode(const char *str)
101{
102 char *endptr;
103 long int mode;
104
105 mode = strtol(str, &endptr, 8);
106 if (str == endptr || *endptr || mode < 0 || mode > 07777)
107 ohshit(_("invalid statoverride mode %s"), str);
108
109 return (mode_t)mode;
110}
111
112void
113ensure_statoverrides(enum statdb_parse_flags flags)
114{
115 static struct stat sb_prev;
116 struct stat sb_next;
117 static FILE *file_prev;
118 FILE *file;
119 char *loaded_list, *loaded_list_end, *thisline, *nextline, *ptr;
120 struct file_stat *fso;
121 struct filenamenode *fnn;
122 struct fileiterator *iter;
123
124 if (statoverridename == NULL)
125 statoverridename = dpkg_db_get_path(STATOVERRIDEFILE);
126
127 onerr_abort++;
128
129 file = fopen(statoverridename, "r");
130 if (!file) {
131 if (errno != ENOENT)
132 ohshite(_("failed to open statoverride file"));
133 } else {
134 setcloexec(fileno(file), statoverridename);
135
136 if (fstat(fileno(file), &sb_next))
137 ohshite(_("failed to fstat statoverride file"));
138
139 /*
140 * We need to keep the database file open so that the
141 * filesystem cannot reuse the inode number (f.ex. during
142 * multiple dpkg-statoverride invocations in a maintainer
143 * script), otherwise the following check might turn true,
144 * and we would skip reloading a modified database.
145 */
146 if (file_prev &&
147 sb_prev.st_dev == sb_next.st_dev &&
148 sb_prev.st_ino == sb_next.st_ino) {
149 fclose(file);
150 onerr_abort--;
151 debug(dbg_general, "%s: same, skipping", __func__);
152 return;
153 }
154 sb_prev = sb_next;
155 }
156 if (file_prev)
157 fclose(file_prev);
158 file_prev = file;
159
160 /* Reset statoverride information. */
161 iter = files_db_iter_new();
162 while ((fnn = files_db_iter_next(iter)))
163 fnn->statoverride = NULL;
164 files_db_iter_free(iter);
165
166 if (!file) {
167 onerr_abort--;
168 debug(dbg_general, "%s: none, resetting", __func__);
169 return;
170 }
171 debug(dbg_general, "%s: new, (re)loading", __func__);
172
173 /* If the statoverride list is empty we don't need to bother
174 * reading it. */
175 if (!sb_next.st_size) {
176 onerr_abort--;
177 return;
178 }
179
180 loaded_list = m_malloc(sb_next.st_size);
181 loaded_list_end = loaded_list + sb_next.st_size;
182
183 if (fd_read(fileno(file), loaded_list, sb_next.st_size) < 0)
184 ohshite(_("reading statoverride file '%.250s'"), statoverridename);
185
186 thisline = loaded_list;
187 while (thisline < loaded_list_end) {
188 fso = nfmalloc(sizeof(struct file_stat));
189
190 ptr = memchr(thisline, '\n', loaded_list_end - thisline);
191 if (ptr == NULL)
192 ohshit(_("statoverride file is missing final newline"));
193 /* Where to start next time around. */
194 nextline = ptr + 1;
195 if (ptr == thisline)
196 ohshit(_("statoverride file contains empty line"));
197 *ptr = '\0';
198
199 /* Extract the uid. */
200 ptr = memchr(thisline, ' ', nextline - thisline);
201 if (ptr == NULL)
202 ohshit(_("syntax error in statoverride file"));
203 *ptr = '\0';
204
205 fso->uid = statdb_parse_uid(thisline);
206 if (fso->uid == (uid_t)-1)
207 fso->uname = nfstrsave(thisline);
208 else
209 fso->uname = NULL;
210
211 if (fso->uid == (uid_t)-1 && !(flags & STATDB_PARSE_LAX))
212 ohshit(_("unknown user '%s' in statoverride file"),
213 thisline);
214
215 /* Move to the next bit */
216 thisline = ptr + 1;
217 if (thisline >= loaded_list_end)
218 ohshit(_("unexpected end of line in statoverride file"));
219
220 /* Extract the gid */
221 ptr = memchr(thisline, ' ', nextline - thisline);
222 if (ptr == NULL)
223 ohshit(_("syntax error in statoverride file"));
224 *ptr = '\0';
225
226 fso->gid = statdb_parse_gid(thisline);
227 if (fso->gid == (gid_t)-1)
228 fso->gname = nfstrsave(thisline);
229 else
230 fso->gname = NULL;
231
232 if (fso->gid == (gid_t)-1 && !(flags & STATDB_PARSE_LAX))
233 ohshit(_("unknown group '%s' in statoverride file"),
234 thisline);
235
236 /* Move to the next bit */
237 thisline = ptr + 1;
238 if (thisline >= loaded_list_end)
239 ohshit(_("unexpected end of line in statoverride file"));
240
241 /* Extract the mode */
242 ptr = memchr(thisline, ' ', nextline - thisline);
243 if (ptr == NULL)
244 ohshit(_("syntax error in statoverride file"));
245 *ptr = '\0';
246
247 fso->mode = statdb_parse_mode(thisline);
248
249 /* Move to the next bit */
250 thisline = ptr + 1;
251 if (thisline >= loaded_list_end)
252 ohshit(_("unexpected end of line in statoverride file"));
253
254 fnn = findnamenode(thisline, 0);
255 if (fnn->statoverride)
256 ohshit(_("multiple statoverrides present for file '%.250s'"),
257 thisline);
258 fnn->statoverride = fso;
259
260 /* Moving on... */
261 thisline = nextline;
262 }
263
264 free(loaded_list);
265
266 onerr_abort--;
267}