rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

verify.c
Go to the documentation of this file.
1
6 #include "system.h"
7
8 #include <rpmio.h>
9 #include <rpmiotypes.h>
10 #include <rpmcb.h>
11 #include "ugid.h"
12
13 #include <rpmtypes.h>
14 #include <rpmtag.h>
15
16 #include <rpmfi.h>
17
18 #define _RPMSQ_INTERNAL
19 #include "psm.h"
20
21 #include "legacy.h" /* XXX dodigest(), uidToUname(), gnameToGid */
22
23 #define _RPMPS_INTERNAL /* XXX rpmps needs iterator. */
24 #define _RPMTS_INTERNAL /* XXX expose rpmtsSetScriptFd */
25 #include <rpmcli.h>
26
27 #include "debug.h"
28
29 /*@access rpmts @*/ /* XXX cast */
30 /*@access rpmpsm @*/ /* XXX for %verifyscript through rpmpsmStage() */
31
32 #define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
33
34 /*@unchecked@*/
35 extern int _rpmds_unspecified_epoch_noise;
36
46 static int rpmVerifyFile(const rpmts ts, const rpmfi fi,
47 /*@out@*/ rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
48 /*@globals h_errno, fileSystem, internalState @*/
49 /*@modifies fi, *res, fileSystem, internalState @*/
50 /*@requires maxSet(res) >= 0 @*/
51 {
52 unsigned short fmode = rpmfiFMode(fi);
53 rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
54 rpmVerifyAttrs flags = rpmfiVFlags(fi);
55 const char * fn = rpmfiFN(fi);
56 const char * rootDir = rpmtsRootDir(ts);
57 struct stat sb;
58 int rc;
59
60 /* Prepend the path to root (if specified). */
61 if (rootDir && *rootDir != '\0'
62 && !(rootDir[0] == '/' && rootDir[1] == '\0'))
63 {
64 int nb = strlen(fn) + strlen(rootDir) + 1;
65 char * tb = alloca(nb);
66 char * t;
67
68 t = tb;
69 *t = '\0';
70 t = stpcpy(t, rootDir);
71 while (t > tb && t[-1] == '/') {
72 --t;
73 *t = '\0';
74 }
75 t = stpcpy(t, fn);
76 fn = tb;
77 }
78
79 *res = RPMVERIFY_NONE;
80
81 /*
82 * Check to see if the file was installed - if not pretend all is OK.
83 */
84 switch (rpmfiFState(fi)) {
85 case RPMFILE_STATE_NETSHARED:
86 case RPMFILE_STATE_REPLACED:
87 case RPMFILE_STATE_NOTINSTALLED:
88 case RPMFILE_STATE_WRONGCOLOR:
89 return 0;
90 /*@notreached@*/ break;
91 case RPMFILE_STATE_NORMAL:
92 break;
93 }
94
95 if (fn == NULL || Lstat(fn, &sb) != 0) {
96 *res |= RPMVERIFY_LSTATFAIL;
97 return 1;
98 }
99
100 /*
101 * Not all attributes of non-regular files can be verified.
102 */
103 if (S_ISDIR(sb.st_mode))
104 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
105 RPMVERIFY_LINKTO);
106 else if (S_ISLNK(sb.st_mode)) {
107 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
108 RPMVERIFY_MODE);
109 #if CHOWN_FOLLOWS_SYMLINK
110 flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
111 #endif
112 }
113 else if (S_ISFIFO(sb.st_mode))
114 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
115 RPMVERIFY_LINKTO);
116 else if (S_ISCHR(sb.st_mode))
117 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
118 RPMVERIFY_LINKTO);
119 else if (S_ISBLK(sb.st_mode))
120 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
121 RPMVERIFY_LINKTO);
122 else
123 flags &= ~(RPMVERIFY_LINKTO);
124
125 /*
126 * Content checks of %ghost files are meaningless.
127 */
128 if (fileAttrs & RPMFILE_GHOST)
129 flags &= ~(RPMVERIFY_FDIGEST | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
130 RPMVERIFY_LINKTO);
131
132 /*
133 * Don't verify any features in omitMask.
134 */
135 flags &= ~(omitMask | RPMVERIFY_FAILURES);
136
137
138 if (flags & RPMVERIFY_FDIGEST) {
139 int dalgo = 0;
140 size_t dlen = 0;
141 const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
142
143 if (digest == NULL)
144 *res |= RPMVERIFY_FDIGEST;
145 else {
146 /* XXX If --nofdigest, then prelinked library sizes fail to verify. */
147 unsigned char * fdigest = memset(alloca(dlen), 0, dlen);
148 size_t fsize;
149 rc = dodigest(dalgo, fn, fdigest, 0, &fsize);
150 sb.st_size = fsize;
151 if (rc)
152 *res |= (RPMVERIFY_READFAIL|RPMVERIFY_FDIGEST);
153 else
154 if (memcmp(fdigest, digest, dlen))
155 *res |= RPMVERIFY_FDIGEST;
156 }
157 }
158
159 if (flags & RPMVERIFY_LINKTO) {
160 char linkto[1024+1];
161 int size = 0;
162
163 if ((size = Readlink(fn, linkto, sizeof(linkto)-1)) == -1)
164 *res |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
165 else {
166 const char * flink = rpmfiFLink(fi);
167 linkto[size] = '\0';
168 if (flink == NULL || strcmp(linkto, flink))
169 *res |= RPMVERIFY_LINKTO;
170 }
171 }
172
173 if (flags & RPMVERIFY_FILESIZE) {
174 if (sb.st_size != rpmfiFSize(fi))
175 *res |= RPMVERIFY_FILESIZE;
176 }
177
178 if (flags & RPMVERIFY_MODE) {
179 unsigned short metamode = fmode;
180 unsigned short filemode;
181
182 /*
183 * Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
184 * need the (unsigned short) cast here.
185 */
186 filemode = (unsigned short)sb.st_mode;
187
188 /*
189 * Comparing the type of %ghost files is meaningless, but perms are OK.
190 */
191 if (fileAttrs & RPMFILE_GHOST) {
192 metamode &= ~0xf000;
193 filemode &= ~0xf000;
194 }
195
196 if (metamode != filemode)
197 *res |= RPMVERIFY_MODE;
198 }
199
200 if (flags & RPMVERIFY_RDEV) {
201 if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
202 || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
203 {
204 *res |= RPMVERIFY_RDEV;
205 } else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
206 rpmuint16_t st_rdev = (rpmuint16_t)(sb.st_rdev & 0xffff);
207 rpmuint16_t frdev = (rpmuint16_t)(rpmfiFRdev(fi) & 0xffff);
208 if (st_rdev != frdev)
209 *res |= RPMVERIFY_RDEV;
210 }
211 }
212
213 if (flags & RPMVERIFY_MTIME) {
214 if ((rpmuint32_t)sb.st_mtime != rpmfiFMtime(fi))
215 *res |= RPMVERIFY_MTIME;
216 }
217
218 if (flags & RPMVERIFY_USER) {
219 const char * name = uidToUname(sb.st_uid);
220 const char * fuser = rpmfiFUser(fi);
221 if (name == NULL || fuser == NULL || strcmp(name, fuser))
222 *res |= RPMVERIFY_USER;
223 }
224
225 if (flags & RPMVERIFY_GROUP) {
226 const char * name = gidToGname(sb.st_gid);
227 const char * fgroup = rpmfiFGroup(fi);
228 if (name == NULL || fgroup == NULL || strcmp(name, fgroup))
229 *res |= RPMVERIFY_GROUP;
230 }
231
232 return 0;
233 }
234
244 static int rpmVerifyScript(/*@unused@*/ QVA_t qva, rpmts ts,
245 rpmfi fi, /*@null@*/ FD_t scriptFd)
246 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
247 /*@modifies ts, fi, scriptFd, rpmGlobalMacroContext,
248 fileSystem, internalState @*/
249 {
250 rpmpsm psm = rpmpsmNew(ts, NULL, fi);
251 int rc = 0;
252
253 if (psm == NULL) /* XXX can't happen */
254 return rc;
255
256 if (scriptFd != NULL)
257 rpmtsSetScriptFd(psm->ts, scriptFd);
258
259 psm->stepName = "verify";
260 psm->scriptTag = RPMTAG_VERIFYSCRIPT;
261 psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
262 rc = rpmpsmStage(psm, PSM_SCRIPT);
263
264 psm->stepName = "sanitycheck";
265 psm->scriptTag = RPMTAG_SANITYCHECK;
266 psm->progTag = RPMTAG_SANITYCHECKPROG;
267 rc = rpmpsmStage(psm, PSM_SCRIPT);
268
269 if (scriptFd != NULL)
270 rpmtsSetScriptFd(psm->ts, NULL);
271
272 psm = rpmpsmFree(psm, "rpmVerifyScript");
273
274 return rc;
275 }
276
284 static int verifyHeader(QVA_t qva, const rpmts ts, rpmfi fi)
285 /*@globals h_errno, fileSystem, internalState @*/
286 /*@modifies fi, fileSystem, internalState @*/
287 {
288 rpmVerifyAttrs verifyResult = 0;
289 /*@-type@*/ /* FIX: union? */
290 rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
291 /*@=type@*/
292 int ec = 0; /* assume no problems */
293 char * t, * te;
294 char buf[BUFSIZ];
295 int i;
296
297 te = t = buf;
298 *te = '\0';
299
300 /*@-castexpose@*/
301 fi = rpmfiLink(fi, "verifyHeader");
302 /*@=castexpose@*/
303 fi = rpmfiInit(fi, 0);
304 if (fi != NULL) /* XXX lclint */
305 while ((i = rpmfiNext(fi)) >= 0) {
306 rpmfileAttrs fflags;
307 int rc;
308
309 fflags = rpmfiFFlags(fi);
310
311 /* If not querying %config, skip config files. */
312 if ((qva->qva_fflags & RPMFILE_CONFIG) && (fflags & RPMFILE_CONFIG))
313 continue;
314
315 /* If not querying %doc, skip doc files. */
316 if ((qva->qva_fflags & RPMFILE_DOC) && (fflags & RPMFILE_DOC))
317 continue;
318
319 /* If not verifying %ghost, skip ghost files. */
320 /* XXX the broken!!! logic disables %ghost queries always. */
321 if (!(qva->qva_fflags & RPMFILE_GHOST) && (fflags & RPMFILE_GHOST))
322 continue;
323
324 rc = rpmVerifyFile(ts, fi, &verifyResult, omitMask);
325 if (rc) {
326 if (qva->qva_mode != 'v') /* XXX no output w verify(...) probe. */
327 if (!(fflags & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
328 sprintf(te, _("missing %c %s"),
329 ((fflags & RPMFILE_CONFIG) ? 'c' :
330 (fflags & RPMFILE_DOC) ? 'd' :
331 (fflags & RPMFILE_GHOST) ? 'g' :
332 (fflags & RPMFILE_LICENSE) ? 'l' :
333 (fflags & RPMFILE_PUBKEY) ? 'P' :
334 (fflags & RPMFILE_README) ? 'r' : ' '),
335 rpmfiFN(fi));
336 te += strlen(te);
337 if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 && errno != ENOENT) {
338 sprintf(te, " (%s)", strerror(errno));
339 te += strlen(te);
340 }
341 ec = rc;
342 }
343 } else if (verifyResult || rpmIsVerbose()) {
344 const char * size, * digest, * link, * mtime, * mode;
345 const char * group, * user, * rdev;
346 /*@observer@*/ static const char *const aok = ".";
347 /*@observer@*/ static const char *const unknown = "?";
348
349 if (!ec)
350 ec = (verifyResult != 0);
351
352 if (qva->qva_mode != 'v') { /* XXX no output w verify(...) probe. */
353 #define _verify(_RPMVERIFY_F, _C) \
354 ((verifyResult & _RPMVERIFY_F) ? _C : aok)
355 #define _verifylink(_RPMVERIFY_F, _C) \
356 ((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
357 (verifyResult & _RPMVERIFY_F) ? _C : aok)
358 #define _verifyfile(_RPMVERIFY_F, _C) \
359 ((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
360 (verifyResult & _RPMVERIFY_F) ? _C : aok)
361
362 digest = _verifyfile(RPMVERIFY_FDIGEST, "5");
363 size = _verify(RPMVERIFY_FILESIZE, "S");
364 link = _verifylink(RPMVERIFY_LINKTO, "L");
365 mtime = _verify(RPMVERIFY_MTIME, "T");
366 rdev = _verify(RPMVERIFY_RDEV, "D");
367 user = _verify(RPMVERIFY_USER, "U");
368 group = _verify(RPMVERIFY_GROUP, "G");
369 mode = _verify(RPMVERIFY_MODE, "M");
370
371 #undef _verifyfile
372 #undef _verifylink
373 #undef _verify
374
375 sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
376 size, mode, digest, rdev, link, user, group, mtime,
377 ((fflags & RPMFILE_CONFIG) ? 'c' :
378 (fflags & RPMFILE_DOC) ? 'd' :
379 (fflags & RPMFILE_GHOST) ? 'g' :
380 (fflags & RPMFILE_LICENSE) ? 'l' :
381 (fflags & RPMFILE_PUBKEY) ? 'P' :
382 (fflags & RPMFILE_README) ? 'r' : ' '),
383 rpmfiFN(fi));
384 te += strlen(te);
385 }
386 }
387
388 if (qva->qva_mode != 'v') /* XXX no output w verify(...) probe. */
389 if (te > t) {
390 *te++ = '\n';
391 *te = '\0';
392 rpmlog(RPMLOG_NOTICE, "%s", t);
393 te = t = buf;
394 *t = '\0';
395 }
396 }
397 fi = rpmfiUnlink(fi, "verifyHeader");
398
399 return ec;
400 }
401
409 static int verifyDependencies(/*@unused@*/ QVA_t qva, rpmts ts,
410 Header h)
411 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
412 /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/
413 {
414 #ifdef NOTYET
415 int instance = headerGetInstance(h);
416 #endif
417 rpmps ps;
418 int rc = 0; /* assume no problems */
419 int xx;
420
421 rpmtsEmpty(ts);
422 #ifdef NOTYET
423 if (instance > 0)
424 (void) rpmtsAddEraseElement(ts, h, instance);
425 else
426 #endif
427 (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
428
429 xx = rpmtsCheck(ts);
430 ps = rpmtsProblems(ts);
431
432 if (rpmpsNumProblems(ps) > 0) {
433 const char * altNEVR;
434 const char * pkgNEVR = NULL;
435 rpmpsi psi;
436 rpmProblem prob;
437 char * t, * te;
438 int nb = 512;
439
440 psi = rpmpsInitIterator(ps);
441 while (rpmpsNextIterator(psi) >= 0) {
442 prob = rpmpsProblem(psi);
443 if (pkgNEVR == NULL)
444 pkgNEVR = rpmProblemGetPkgNEVR(prob);
445
446 altNEVR = rpmProblemGetAltNEVR(prob);
447 assert(altNEVR != NULL);
448 if (altNEVR[0] == 'R' && altNEVR[1] == ' ')
449 nb += sizeof("\tRequires: ")-1;
450 if (altNEVR[0] == 'C' && altNEVR[1] == ' ')
451 nb += sizeof("\tConflicts: ")-1;
452 nb += strlen(altNEVR+2) + sizeof("\n") - 1;
453
454 }
455 psi = rpmpsFreeIterator(psi);
456
457 te = t = alloca(nb);
458 *te = '\0';
459 sprintf(te, _("Unsatisfied dependencies for %s:\n"), pkgNEVR);
460 te += strlen(te);
461
462 psi = rpmpsInitIterator(ps);
463 while (rpmpsNextIterator(psi) >= 0) {
464 prob = rpmpsProblem(psi);
465
466 if ((altNEVR = rpmProblemGetAltNEVR(prob)) == NULL)
467 altNEVR = "? ?altNEVR?";
468 if (altNEVR[0] == 'R' && altNEVR[1] == ' ')
469 te = stpcpy(te, "\tRequires: ");
470 if (altNEVR[0] == 'C' && altNEVR[1] == ' ')
471 te = stpcpy(te, "\tConflicts: ");
472 te = stpcpy( stpcpy(te, altNEVR+2), "\n");
473
474 rc++;
475 }
476 psi = rpmpsFreeIterator(psi);
477
478 if (te > t) {
479 *te++ = '\n';
480 *te = '\0';
481 rpmlog(RPMLOG_NOTICE, "%s", t);
482 te = t;
483 *t = '\0';
484 }
485 }
486
487 ps = rpmpsFree(ps);
488
489 rpmtsEmpty(ts);
490
491 return rc;
492 }
493
494 int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
495 {
496 int scareMem = 0;
497 rpmfi fi = NULL;
498 int ec = 0;
499 int rc;
500
501 fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
502 if (fi != NULL) {
503 if (qva->qva_flags & VERIFY_DEPS) {
504 int save_noise = _rpmds_unspecified_epoch_noise;
505 /*@-mods@*/
506 if (rpmIsVerbose())
507 _rpmds_unspecified_epoch_noise = 1;
508 if ((rc = verifyDependencies(qva, ts, h)) != 0)
509 ec = rc;
510 _rpmds_unspecified_epoch_noise = save_noise;
511 /*@=mods@*/
512 }
513 if (qva->qva_flags & VERIFY_FILES) {
514 if ((rc = verifyHeader(qva, ts, fi)) != 0)
515 ec = rc;
516 }
517 if ((qva->qva_flags & VERIFY_SCRIPT)
518 && (headerIsEntry(h, RPMTAG_VERIFYSCRIPT) ||
519 headerIsEntry(h, RPMTAG_SANITYCHECK)))
520 {
521 FD_t fdo = fdDup(STDOUT_FILENO);
522
523 rc = rpmfiSetHeader(fi, h);
524 if ((rc = rpmVerifyScript(qva, ts, fi, fdo)) != 0)
525 ec = rc;
526 if (fdo != NULL)
527 rc = Fclose(fdo);
528 rc = rpmfiSetHeader(fi, NULL);
529 }
530
531 fi = rpmfiFree(fi);
532 }
533
534 return ec;
535 }
536
537 int rpmcliVerify(rpmts ts, QVA_t qva, const char ** argv)
538 {
539 rpmdepFlags depFlags = qva->depFlags, odepFlags;
540 rpmtransFlags transFlags = qva->transFlags, otransFlags;
541 rpmVSFlags vsflags, ovsflags;
542 int ec = 0;
543
544 if (qva->qva_showPackage == NULL)
545 qva->qva_showPackage = showVerifyPackage;
546
547 /* XXX verify flags are inverted from query. */
548 vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
549 if (!(qva->qva_flags & VERIFY_DIGEST))
550 vsflags |= _RPMVSF_NODIGESTS;
551 if (!(qva->qva_flags & VERIFY_SIGNATURE))
552 vsflags |= _RPMVSF_NOSIGNATURES;
553 if (!(qva->qva_flags & VERIFY_HDRCHK))
554 vsflags |= RPMVSF_NOHDRCHK;
555 vsflags &= ~RPMVSF_NEEDPAYLOAD;
556
557 odepFlags = rpmtsSetDFlags(ts, depFlags);
558 otransFlags = rpmtsSetFlags(ts, transFlags);
559 ovsflags = rpmtsSetVSFlags(ts, vsflags);
560 ec = rpmcliArgIter(ts, qva, argv);
561 vsflags = rpmtsSetVSFlags(ts, ovsflags);
562 transFlags = rpmtsSetFlags(ts, otransFlags);
563 depFlags = rpmtsSetDFlags(ts, odepFlags);
564
565 if (qva->qva_showPackage == showVerifyPackage)
566 qva->qva_showPackage = NULL;
567
568 rpmtsEmpty(ts);
569
570 return ec;
571 }