rpm  5.2.1
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@*/
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)) {
89  return 0;
90  /*@notreached@*/ break;
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))
106  else if (S_ISLNK(sb.st_mode)) {
109 #if CHOWN_FOLLOWS_SYMLINK
110  flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
111 #endif
112  }
113  else if (S_ISFIFO(sb.st_mode))
116  else if (S_ISCHR(sb.st_mode))
119  else if (S_ISBLK(sb.st_mode))
122  else
123  flags &= ~(RPMVERIFY_LINKTO);
124 
125  /*
126  * Content checks of %ghost files are meaningless.
127  */
128  if (fileAttrs & RPMFILE_GHOST)
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)
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";
262  rc = rpmpsmStage(psm, PSM_SCRIPT);
263 
264  psm->stepName = "sanitycheck";
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 
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())
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)
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)
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 
566  qva->qva_showPackage = NULL;
567 
568  rpmtsEmpty(ts);
569 
570  return ec;
571 }