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