2 * dpkg - main program for package management
3 * verify.c - verify package integrity
5 * Copyright © 2012-2015 Guillem Jover <guillem@debian.org>
7 * This is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
32 #include <dpkg/i18n.h>
33 #include <dpkg/dpkg.h>
34 #include <dpkg/dpkg-db.h>
35 #include <dpkg/options.h>
36 #include <dpkg/db-ctrl.h>
37 #include <dpkg/db-fsys.h>
38 #include <dpkg/buffer.h>
49 struct verify_checks
{
51 enum verify_result exists
;
52 enum verify_result mode
;
53 enum verify_result md5sum
;
56 typedef void verify_output_func(struct fsys_namenode
*, struct verify_checks
*);
59 verify_result_rpm(enum verify_result result
, int check
)
73 verify_output_rpm(struct fsys_namenode
*namenode
, struct verify_checks
*checks
)
79 memset(result
, '?', sizeof(result
));
81 if (checks
->exists
== VERIFY_FAIL
) {
82 memcpy(result
, "missing ", sizeof(result
));
83 if (checks
->exists_errno
!= ENOENT
)
84 m_asprintf(&error
, " (%s)", strerror(checks
->exists_errno
));
86 result
[1] = verify_result_rpm(checks
->mode
, 'M');
87 result
[2] = verify_result_rpm(checks
->md5sum
, '5');
90 if (namenode
->flags
& FNNF_OLD_CONFF
)
95 printf("%.9s %c %s%s\n", result
, attr
, namenode
->name
, error
? error
: "");
100 static verify_output_func
*verify_output
= verify_output_rpm
;
103 verify_set_output(const char *name
)
105 if (strcmp(name
, "rpm") == 0)
106 verify_output
= verify_output_rpm
;
114 verify_digest(const char *filename
, struct fsys_namenode
*fnn
,
115 struct verify_checks
*checks
)
119 fd
= open(filename
, O_RDONLY
);
122 struct dpkg_error err
;
123 char hash
[MD5HASHLEN
+ 1];
125 push_cleanup(cu_closefd
, ehflag_bombout
, 1, &fd
);
126 if (fd_md5(fd
, hash
, -1, &err
) < 0)
127 ohshit(_("cannot compute MD5 digest for file '%s': %s"),
129 pop_cleanup(ehflag_normaltidy
); /* fd = open(cdr.buf) */
132 if (strcmp(hash
, fnn
->newhash
) == 0) {
133 checks
->md5sum
= VERIFY_PASS
;
136 checks
->md5sum
= VERIFY_FAIL
;
139 checks
->md5sum
= VERIFY_NONE
;
146 verify_file(const char *filename
, struct fsys_namenode
*fnn
,
147 struct pkginfo
*pkg
, struct verify_checks
*checks
)
152 if (lstat(filename
, &st
) < 0) {
153 checks
->exists_errno
= errno
;
154 checks
->exists
= VERIFY_FAIL
;
157 checks
->exists
= VERIFY_PASS
;
159 if (fnn
->newhash
== NULL
&& fnn
->oldhash
!= NULL
)
160 fnn
->newhash
= fnn
->oldhash
;
162 if (fnn
->newhash
!= NULL
) {
163 /* Mode check heuristic: If we know its digest, the pathname
164 * must be a regular file. */
165 if (!S_ISREG(st
.st_mode
)) {
166 checks
->mode
= VERIFY_FAIL
;
170 if (verify_digest(filename
, fnn
, checks
) < 0)
178 verify_package(struct pkginfo
*pkg
)
180 struct fsys_namenode_list
*file
;
181 struct varbuf filename
= VARBUF_INIT
;
183 ensure_packagefiles_available(pkg
);
184 parse_filehash(pkg
, &pkg
->installed
);
185 pkg_conffiles_mark_old(pkg
);
187 for (file
= pkg
->files
; file
; file
= file
->next
) {
188 struct verify_checks checks
;
189 struct fsys_namenode
*fnn
;
191 fnn
= namenodetouse(file
->namenode
, pkg
, &pkg
->installed
);
193 varbuf_reset(&filename
);
194 varbuf_add_str(&filename
, dpkg_fsys_get_dir());
195 varbuf_add_str(&filename
, fnn
->name
);
196 varbuf_end_str(&filename
);
198 memset(&checks
, 0, sizeof(checks
));
200 if (verify_file(filename
.buf
, fnn
, pkg
, &checks
) > 0)
201 verify_output(fnn
, &checks
);
204 varbuf_destroy(&filename
);
208 verify(const char *const *argv
)
213 modstatdb_open(msdbrw_readonly
);
217 struct pkg_hash_iter
*iter
;
219 iter
= pkg_hash_iter_new();
220 while ((pkg
= pkg_hash_iter_next_pkg(iter
)))
222 pkg_hash_iter_free(iter
);
226 while ((thisarg
= *argv
++)) {
227 pkg
= dpkg_options_parse_pkgname(cipaction
, thisarg
);
228 if (pkg
->status
== PKG_STAT_NOTINSTALLED
) {
229 notice(_("package '%s' is not installed"),
230 pkg_name(pkg
, pnaw_nonambig
));
239 modstatdb_shutdown();
241 m_output(stdout
, _("<standard output>"));