1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #include <stdio.h> 32 #include <signal.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <assert.h> 38 #include <pkgstrct.h> 39 #include <sys/stat.h> 40 #include <locale.h> 41 #include <libintl.h> 42 #include <pkginfo.h> 43 #include <instzones_api.h> 44 #include <pkglib.h> 45 #include <libinst.h> 46 #include <messages.h> 47 48 /* merg() return codes */ 49 #define MRG_SAME 0 50 #define MRG_DIFFERENT 1 51 #define MRG_REPLACE 2 52 53 /* typechg() return codes */ 54 #define TYPE_OK 0 55 #define TYPE_WARNING 1 56 #define TYPE_IGNORED 2 57 #define TYPE_REPLACE 3 58 #define TYPE_FATAL 4 59 60 /* message pool */ 61 #define ERR_OUTPUT "unable to update package database" 62 #define ERR_PINFO "missing pinfo structure for <%s>" 63 #define INFO_PROCESS " %2ld%% of information processed; continuing ..." 64 65 #define WRN_NOTFILE "WARNING: %s <no longer a regular file>" 66 #define WRN_NOTSYMLN "WARNING: %s <no longer a symbolic link>" 67 #define WRN_NOTLINK "WARNING: %s <no longer a linked file>" 68 #define WRN_NOTDIR "WARNING: %s <no longer a directory>" 69 #define WRN_NOTCHAR "WARNING: %s <no longer a character special device>" 70 #define WRN_NOTBLOCK "WARNING: %s <no longer a block special device>" 71 #define WRN_NOTPIPE "WARNING: %s <no longer a named pipe>" 72 #define WRN_TOEXCL "WARNING: cannot convert %s to an exclusive directory." 73 #define WRN_ODDVERIFY "WARNING: quick verify disabled for class %s." 74 75 #define MSG_TYPIGN "Object type change ignored." 76 #define MSG_TYPE_ERR "Package attempts fatal object type change." 77 78 extern char *pkginst; 79 extern int nosetuid, nocnflct, otherstoo; 80 81 /* pkgobjmap.c */ 82 extern int cp_cfent(struct cfent *cf_ent, struct cfextra *el_ent); 83 84 /* setlist.c */ 85 extern void cl_def_dverify(int idx); 86 87 char dbst = '\0'; /* usually set by installf() or removef() */ 88 89 int files_installed(void); /* return number of files installed. */ 90 91 static int errflg = 0; 92 static int eptnum; 93 static int installed; /* # of files, already properly installed. */ 94 static struct pinfo *pkgpinfo = (struct pinfo *)0; 95 96 static int is_setuid(struct cfent *ent); 97 static int is_setgid(struct cfent *ent); 98 static int merg(struct cfextra *el_ent, struct cfent *cf_ent); 99 static int do_like_ent(VFP_T *vfpo, struct cfextra *el_ent, 100 struct cfent *cf_ent, int ctrl); 101 static int do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl); 102 static int typechg(struct cfent *el_ent, char *curftype, 103 struct mergstat *mstat); 104 105 static void set_change(struct cfextra *el_ent); 106 static void chgclass(struct cfent *cf_ent, struct pinfo *pinfo); 107 static void output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo); 108 109 /* 110 * This scans the extlist (pkgmap) and matches them to the database, copying 111 * out the modified contents to the file at tmpfp. It updates the mergstat 112 * structures and deals with administrative defaults regarding setuid and 113 * conflict. 114 */ 115 116 int 117 pkgdbmerg(PKGserver server, VFP_T *tmpvfp, struct cfextra **extlist) 118 { 119 static struct cfent cf_ent; /* scratch area */ 120 struct cfextra *el_ent; /* extlist entry under review */ 121 int n; 122 int changed; 123 int assume_ok = 0; 124 125 cf_ent.pinfo = (NULL); 126 errflg = 0; 127 installed = changed = 0; 128 129 vfpRewind(tmpvfp); 130 131 for (eptnum = 0; (el_ent = extlist[eptnum]) != NULL; eptnum++) { 132 /* 133 * If there's an entry in the extlist at this position, 134 * process that entry. 135 */ 136 /* Metafiles don't get merged. */ 137 if ((el_ent->cf_ent.ftype == 'i') || 138 (el_ent->cf_ent.ftype == 'n')) { 139 continue; 140 } 141 142 /* 143 * Copy cfextra structure for duplicated paths. 144 * This is not just an optimization, it is 145 * necessary for correct operation of algorithm. 146 */ 147 if ((eptnum > 0) && (strncmp(el_ent->cf_ent.path, 148 extlist[eptnum-1]->cf_ent.path, PATH_MAX) == 0)) { 149 memcpy(extlist[eptnum], extlist[eptnum-1], 150 sizeof (struct cfextra)); 151 continue; 152 } 153 154 /* 155 * Normally dbst comes to us from installf() or 156 * removef() in order to specify their special 157 * database status codes. They cannot implement a 158 * quick verify (it just doesn't make sense). For 159 * that reason, we can test to see if we already have 160 * a special database status. If we don't (it's from 161 * pkgadd) then we can test to see if this is calling 162 * for a quick verify wherein we assume the install 163 * will work and fix it if it doesn't. In that case 164 * we set our own dbst to be ENTRY_OK. 165 */ 166 if (dbst == '\0') { 167 if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) == 168 QKVERIFY) { 169 assume_ok = 1; 170 } 171 } else { 172 /* 173 * If we DO end up with an installf/quick 174 * verify combination, we fix that by simply 175 * denying the quick verify for this class. 176 * This forces everything to come out alright 177 * by forcing the standard assumptions as 178 * regards package database for the rest of 179 * the load. 180 */ 181 if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) == 182 QKVERIFY) { 183 logerr(gettext(WRN_ODDVERIFY), 184 cl_nam(el_ent->cf_ent.pkg_class_idx)); 185 /* 186 * Set destination verification to 187 * default. 188 */ 189 cl_def_dverify(el_ent->cf_ent.pkg_class_idx); 190 } 191 } 192 193 /* 194 * Comply with administrative requirements regarding 195 * setuid/setgid processes. 196 */ 197 if (is_setuid(&(el_ent->cf_ent))) { 198 el_ent->mstat.setuid = 1; 199 } 200 if (is_setgid(&(el_ent->cf_ent))) { 201 el_ent->mstat.setgid = 1; 202 } 203 204 /* 205 * If setuid/setgid processes are not allowed, reset 206 * those bits. 207 */ 208 if (nosetuid && (el_ent->mstat.setgid || 209 el_ent->mstat.setuid)) { 210 el_ent->cf_ent.ainfo.mode &= ~(S_ISUID | S_ISGID); 211 } 212 213 /* Search package database for this entry. */ 214 n = srchcfile(&cf_ent, el_ent->cf_ent.path, server); 215 216 /* 217 * If there was an error, note it and return an error 218 * flag. 219 */ 220 if (n < 0) { 221 char *errstr = getErrstr(); 222 progerr(ERR_CFBAD); 223 logerr(gettext("pathname: %s"), 224 (cf_ent.path && *cf_ent.path) ? 225 cf_ent.path : "Unknown"); 226 logerr(gettext("problem: %s"), 227 (errstr && *errstr) ? errstr : "Unknown"); 228 return (-1); 229 /* 230 * If there was a match, then merge them into a 231 * single entry. 232 */ 233 } else if (n == 1) { 234 /* 235 * If this package is overwriting a setuid or 236 * setgid process, set the status bits so we 237 * can inform the administrator. 238 */ 239 if (is_setuid(&cf_ent)) { 240 el_ent->mstat.osetuid = 1; 241 } 242 243 if (is_setgid(&cf_ent)) { 244 el_ent->mstat.osetgid = 1; 245 } 246 /* 247 * Detect if a symlink has changed to directory 248 * If so mark all the files/dir supposed to be 249 * iniside this dir, so that they are not miss 250 * understood by do_new_ent later as already 251 * installed. 252 */ 253 if ((cf_ent.ftype == 's') && 254 (el_ent->cf_ent.ftype == 'd')) { 255 int i; 256 int plen = strlen(el_ent->cf_ent.path); 257 for (i = eptnum + 1; extlist[i]; i++) { 258 if (strncmp(el_ent->cf_ent.path, 259 extlist[i]->cf_ent.path, 260 plen) != 0) 261 break; 262 extlist[i]->mstat.parentsyml2dir 263 = 1; 264 } 265 } 266 267 if (do_like_ent(tmpvfp, el_ent, &cf_ent, assume_ok)) { 268 changed++; 269 } 270 271 } else { 272 /* 273 * The file doesn't exist in the database. 274 */ 275 if (do_new_ent(tmpvfp, el_ent, assume_ok)) { 276 changed++; 277 } 278 } 279 } 280 281 return (errflg ? -1 : changed); 282 } 283 284 /* 285 * Merge a new entry with an installed package object of the same name and 286 * insert that object into the package database. Obey administrative defaults 287 * as regards conflicting files. 288 */ 289 290 static int 291 do_like_ent(VFP_T *vfpo, struct cfextra *el_ent, struct cfent *cf_ent, int ctrl) 292 { 293 int stflag, ignore, changed, mrg_result; 294 295 ignore = changed = 0; 296 297 /* 298 * Construct the record defining the current package. If there are 299 * other packages involved, this will be appended to the existing 300 * list. If this is an update of the same package, it will get merged 301 * with the existing record. If this is a preloaded record (like from 302 * a dryrun file), it will keep it's current pinfo pointer and will 303 * pass it on to the record from the contents file - because on the 304 * final continuation, the contents file will be wrong. 305 */ 306 if (el_ent->mstat.preloaded) { 307 struct pinfo *pkginfo; 308 309 /* Contents file is not to be trusted for this list. */ 310 pkginfo = cf_ent->pinfo; 311 312 /* Free the potentially bogus list. */ 313 while (pkginfo) { 314 struct pinfo *next; 315 next = pkginfo->next; 316 free(pkginfo); 317 pkginfo = next; 318 } 319 320 cf_ent->pinfo = el_ent->cf_ent.pinfo; 321 } 322 323 pkgpinfo = eptstat(cf_ent, pkginst, DUP_ENTRY); 324 325 stflag = pkgpinfo->status; 326 327 if (otherstoo) 328 el_ent->mstat.shared = 1; 329 330 /* If it's marked for erasure, make it official */ 331 if (el_ent->cf_ent.ftype == RM_RDY) { 332 if (!errflg) { 333 pkgpinfo = eptstat(cf_ent, pkginst, RM_RDY); 334 335 /* 336 * Get copy of status character in case the object is 337 * "shared" by a server, in which case we need to 338 * maintain the shared status after the entry is 339 * written to the package database with RM_RDY 340 * status. This is needed to support the `removef' 341 * command. 342 */ 343 stflag = pkgpinfo->status; 344 pkgpinfo->status = RM_RDY; 345 346 if (putcvfpfile(cf_ent, vfpo)) { 347 progerr(gettext(ERR_OUTPUT)); 348 quit(99); 349 } 350 351 /* 352 * If object is provided by a server, allocate an 353 * info block and set the status to indicate this. 354 * This is needed to support the `removef' command. 355 */ 356 if (stflag == SERVED_FILE) { 357 el_ent->cf_ent.pinfo = 358 (struct pinfo *)calloc(1, 359 sizeof (struct pinfo)); 360 el_ent->cf_ent.pinfo->next = NULL; 361 el_ent->cf_ent.pinfo->status = SERVED_FILE; 362 } 363 } 364 return (1); 365 } 366 367 /* 368 * If there is no package associated with it, there's something 369 * very wrong. 370 */ 371 if (!pkgpinfo) { 372 progerr(gettext(ERR_PINFO), cf_ent->path); 373 quit(99); 374 } 375 376 /* 377 * Do not allow installation if nocnflct is set and other packages 378 * reference this pathname. The cp_cfent() function below writes the 379 * information from the installed file over the new entry, so the 380 * package database will be unchanged. 381 * 382 * By the way, ftype "e" is often shared and that's OK, so ftype 383 * "e" doesn't count here. 384 */ 385 if ((nocnflct && el_ent->mstat.shared && el_ent->cf_ent.ftype != 'e')) { 386 /* 387 * First set the attrchg and contchg entries for proper 388 * messaging in the install phase. 389 */ 390 set_change(el_ent); 391 392 /* 393 * Now overwrite the new entry with the entry for the 394 * currently installed object. 395 */ 396 if (cp_cfent(cf_ent, el_ent) == 0) 397 quit(99); 398 399 ignore++; 400 } else { 401 mrg_result = merg(el_ent, cf_ent); 402 403 switch (mrg_result) { 404 case MRG_SAME: 405 break; 406 407 case MRG_DIFFERENT: 408 changed++; 409 break; 410 411 case MRG_REPLACE: 412 /* 413 * We'll pick one or the other later. For now, cf_ent 414 * will have the fault value and el_ent will retain 415 * the other value. This is the only state that allows 416 * the database and the pkgmap to differ. 417 */ 418 419 el_ent->mstat.contchg = 1; /* subject to change */ 420 ignore++; 421 break; 422 423 default: 424 break; 425 } 426 } 427 428 /* el_ent structure now contains updated entry */ 429 if (!el_ent->mstat.contchg && !ignore) { 430 /* 431 * We know the DB entry matches the pkgmap, so now we need to 432 * see if the actual object matches the pkgmap. 433 */ 434 set_change(el_ent); 435 } 436 437 if (!errflg) { 438 if (ctrl == 1) { /* quick verify assumes OK */ 439 /* 440 * The pkgpinfo entry is already correctly 441 * constructed. Look into dropping this soon. 442 */ 443 pkgpinfo = eptstat(&(el_ent->cf_ent), pkginst, 444 ENTRY_OK); 445 446 if (stflag != DUP_ENTRY) { 447 changed++; 448 } 449 450 /* 451 * We could trust the prior pkginfo entry, but things 452 * could have changed and we need to update the 453 * fs_tab[] anyway. We check for a server object 454 * here. 455 */ 456 if (is_served(el_ent->server_path, 457 &(el_ent->fsys_value))) 458 pkgpinfo->status = SERVED_FILE; 459 } else { 460 if (!ignore && el_ent->mstat.contchg) { 461 pkgpinfo = 462 eptstat(&(el_ent->cf_ent), pkginst, 463 (dbst ? dbst : CONFIRM_CONT)); 464 } else if (!ignore && el_ent->mstat.attrchg) { 465 pkgpinfo = 466 eptstat(&(el_ent->cf_ent), pkginst, 467 (dbst ? dbst : CONFIRM_ATTR)); 468 } else if (!ignore && el_ent->mstat.shared) { 469 pkgpinfo = 470 eptstat(&(el_ent->cf_ent), pkginst, 471 dbst); 472 changed++; 473 } else if (stflag != DUP_ENTRY) { 474 pkgpinfo = eptstat(&(el_ent->cf_ent), 475 pkginst, '\0'); 476 if (stflag != ENTRY_OK) { 477 changed++; 478 } 479 } 480 } 481 482 if (mrg_result == MRG_REPLACE) { 483 /* 484 * Put the original package database entry back into 485 * the package database for now. 486 */ 487 output(vfpo, cf_ent, pkgpinfo); 488 } else { 489 /* Put the merged entry into the package database. */ 490 output(vfpo, &(el_ent->cf_ent), pkgpinfo); 491 } 492 } 493 494 if (pkgpinfo->aclass[0] != '\0') { 495 (void) strcpy(el_ent->cf_ent.pkg_class, pkgpinfo->aclass); 496 } 497 498 /* 499 * If a sym link entry exists in the contents file and 500 * and the destination of the link does not exist on the the system 501 * then the contents file needs to be updated appropriately so a 502 * subsequent invocation of "installf -f" will create the destination. 503 */ 504 if (el_ent->mstat.contchg && pkgpinfo->status == INST_RDY) { 505 changed++; 506 } 507 508 if (!(el_ent->mstat.preloaded)) 509 el_ent->cf_ent.pinfo = NULL; 510 511 /* 512 * If no change during the merg and we don't have a case where types 513 * were different in odd ways, count this as installed. 514 */ 515 if (!el_ent->mstat.attrchg && !el_ent->mstat.contchg && 516 !el_ent->mstat.replace) 517 installed++; 518 return (changed); 519 } 520 521 /* Insert an entirely new entry into the package database. */ 522 static int 523 do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl) 524 { 525 struct pinfo *pinfo; 526 char *tp; 527 int changed = 0; 528 529 if (el_ent->cf_ent.ftype == RM_RDY) { 530 return (0); 531 } 532 533 tp = el_ent->server_path; 534 /* 535 * Check the file/dir existence only if any of the parent directory 536 * of the file/dir has not changed from symbolic link to directory. 537 * At this time we are only doing a dry run, the symlink is not yet 538 * replaced, so if this is done directly then access will result in 539 * incorrect information in case a file with the same attr and cont 540 * exists in the link target. 541 */ 542 if ((!el_ent->mstat.parentsyml2dir) && (access(tp, F_OK) == 0)) { 543 /* 544 * Path exists, and although its not referenced by any 545 * package we make it look like it is so it appears as a 546 * conflicting file in case the user doesn't want it 547 * installed. We set the rogue flag to distinguish this from 548 * package object conflicts if the administrator is queried 549 * about this later. Note that noconflict means NO conflict 550 * at the file level. Even rogue files count. 551 */ 552 char myftype = '?'; 553 int n = 0; 554 555 /* Get the existing file type on disk */ 556 eval_ftype(el_ent->server_path, el_ent->cf_ent.ftype, &myftype); 557 558 /* Do the right thing if types are different */ 559 n = typechg(&(el_ent->cf_ent), &myftype, &(el_ent->mstat)); 560 switch (n) { 561 case TYPE_OK: 562 break; 563 564 /* This is an allowable change. */ 565 case TYPE_WARNING: 566 el_ent->mstat.contchg = 1; 567 break; 568 569 /* Not allowed, but leaving it as is is OK. */ 570 case TYPE_IGNORED: 571 break; 572 573 /* Future analysis will reveal if this is OK. */ 574 case TYPE_REPLACE: 575 el_ent->mstat.replace = 1; 576 break; 577 578 /* Kill it before it does any damage. */ 579 case TYPE_FATAL: 580 logerr(gettext(MSG_TYPE_ERR)); 581 quit(99); 582 583 default: 584 break; 585 } 586 el_ent->mstat.shared = 1; 587 el_ent->mstat.rogue = 1; 588 set_change(el_ent); 589 } else { 590 /* since path doesn't exist, we're changing everything */ 591 el_ent->mstat.rogue = 0; 592 el_ent->mstat.contchg = 1; 593 el_ent->mstat.attrchg = 1; 594 } 595 596 if (el_ent->cf_ent.ainfo.mode == WILDCARD) { 597 if (el_ent->cf_ent.ftype == 'd') { 598 el_ent->cf_ent.ainfo.mode = DEFAULT_MODE; 599 } else { 600 el_ent->cf_ent.ainfo.mode = DEFAULT_MODE_FILE; 601 } 602 logerr(WRN_SET_DEF_MODE, el_ent->cf_ent.path, 603 (int)el_ent->cf_ent.ainfo.mode); 604 } 605 606 if (strcmp(el_ent->cf_ent.ainfo.owner, DB_UNDEFINED_ENTRY) == 0) 607 (void) strcpy(el_ent->cf_ent.ainfo.owner, 608 DEFAULT_OWNER); 609 if (strcmp(el_ent->cf_ent.ainfo.group, DB_UNDEFINED_ENTRY) == 0) 610 (void) strcpy(el_ent->cf_ent.ainfo.group, 611 DEFAULT_GROUP); 612 613 /* 614 * Do not allow installation if nocnflct is set and this pathname is 615 * already in place. Since this entry is new (not associated with a 616 * package), we don't issue anything to the database we're building. 617 */ 618 if (nocnflct && el_ent->mstat.shared) { 619 return (0); 620 } 621 622 if (!errflg) { 623 if (el_ent->mstat.preloaded) { 624 /* Add this package to the already established list. */ 625 pinfo = eptstat(&(el_ent->cf_ent), pkginst, DUP_ENTRY); 626 } else { 627 el_ent->cf_ent.npkgs = 1; 628 pinfo = (struct pinfo *)calloc(1, 629 sizeof (struct pinfo)); 630 if (!pinfo) { 631 progerr(gettext(ERR_MEMORY), errno); 632 quit(99); 633 } 634 el_ent->cf_ent.pinfo = pinfo; 635 (void) strcpy(pinfo->pkg, pkginst); 636 } 637 638 if (ctrl == 1) { /* quick verify assumes OK */ 639 pinfo->status = dbst ? dbst : ENTRY_OK; 640 /* 641 * The entry won't be verified, but the entry in the 642 * database isn't necessarily ENTRY_OK. If this is 643 * coming from a server, we need to note that 644 * instead. 645 */ 646 if (is_served(el_ent->server_path, 647 &(el_ent->fsys_value))) 648 pinfo->status = SERVED_FILE; 649 } else { 650 pinfo->status = dbst ? dbst : CONFIRM_CONT; 651 } 652 653 output(vfpo, &(el_ent->cf_ent), pinfo); 654 changed++; 655 656 free(pinfo); 657 el_ent->cf_ent.pinfo = NULL; 658 } 659 if (!el_ent->mstat.attrchg && !el_ent->mstat.contchg) { 660 installed++; 661 } 662 663 return (changed); 664 } 665 666 int 667 files_installed(void) 668 { 669 return (installed); 670 } 671 672 /* 673 * This function determines if there is a difference between the file on 674 * the disk and the file to be laid down. It set's mstat flags attrchg 675 * and contchg accordingly. 676 */ 677 static void 678 set_change(struct cfextra *el_ent) 679 { 680 int n; 681 char *tp; 682 683 tp = el_ent->server_path; 684 if ((el_ent->cf_ent.ftype == 'f') || (el_ent->cf_ent.ftype == 'e') || 685 (el_ent->cf_ent.ftype == 'v')) { 686 if (cverify(0, &(el_ent->cf_ent.ftype), tp, 687 &(el_ent->cf_ent.cinfo), 1)) { 688 el_ent->mstat.contchg = 1; 689 } else if (!el_ent->mstat.contchg && !el_ent->mstat.attrchg) { 690 if (averify(0, &(el_ent->cf_ent.ftype), tp, 691 &(el_ent->cf_ent.ainfo))) 692 el_ent->mstat.attrchg = 1; 693 } 694 } else if (!el_ent->mstat.attrchg && 695 ((el_ent->cf_ent.ftype == 'd') || 696 (el_ent->cf_ent.ftype == 'x') || 697 (el_ent->cf_ent.ftype == 'c') || 698 (el_ent->cf_ent.ftype == 'b') || 699 (el_ent->cf_ent.ftype == 'p'))) { 700 n = averify(0, &(el_ent->cf_ent.ftype), tp, 701 &(el_ent->cf_ent.ainfo)); 702 if (n == VE_ATTR) 703 el_ent->mstat.attrchg = 1; 704 else if (n && (n != VE_EXIST)) { 705 el_ent->mstat.contchg = 1; 706 } 707 } else if (!el_ent->mstat.attrchg && 708 ((el_ent->cf_ent.ftype == 's') || 709 (el_ent->cf_ent.ftype == 'l'))) { 710 n = averify(0, &(el_ent->cf_ent.ftype), tp, 711 &(el_ent->cf_ent.ainfo)); 712 if (n == VE_ATTR) 713 el_ent->mstat.attrchg = 1; 714 else if (n && (n == VE_EXIST)) { 715 el_ent->mstat.contchg = 1; 716 } 717 } 718 } 719 720 static int 721 is_setuid(struct cfent *ent) 722 { 723 return (((ent->ftype == 'f') || (ent->ftype == 'v') || 724 (ent->ftype == 'e')) && 725 (ent->ainfo.mode != BADMODE) && 726 (ent->ainfo.mode != WILDCARD) && 727 (ent->ainfo.mode & S_ISUID)); 728 } 729 730 static int 731 is_setgid(struct cfent *ent) 732 { 733 return (((ent->ftype == 'f') || (ent->ftype == 'v') || 734 (ent->ftype == 'e')) && (ent->ainfo.mode != BADMODE) && 735 (ent->ainfo.mode != WILDCARD) && 736 (ent->ainfo.mode & S_ISGID) && 737 (ent->ainfo.mode & (S_IEXEC|S_IXUSR|S_IXOTH))); 738 } 739 740 char *types[] = { 741 "fev", /* type 1, regular files */ 742 "s", /* type 2, symbolic links */ 743 "l", /* type 3, linked files */ 744 "dx", /* type 4, directories */ 745 "c", /* type 5, character special devices */ 746 "b", /* type 6, block special devices */ 747 "p", /* type 7, named pipes */ 748 NULL 749 }; 750 751 /* 752 * This determines if the ftype of the file on the disk and the file to be 753 * laid down are close enough. If they aren't, this either returns an error 754 * or displays a warning. This returns : 755 * TYPE_OK they're identical or close enough 756 * TYPE_WARNING they're pretty close (probably no problem) 757 * TYPE_IGNORED the type change was not allowed 758 * TYPE_REPLACE to be reviewed later - in endofclass() maybe 759 * TYPE_FATAL something awful happened 760 */ 761 static int 762 typechg(struct cfent *el_ent, char *curftype, struct mergstat *mstat) 763 { 764 int i, etype, itype, retcode; 765 766 /* If they are identical, return OK */ 767 if (*curftype == el_ent->ftype) 768 return (TYPE_OK); 769 770 /* 771 * If package database entry is ambiguous, set it to the new entity's 772 * ftype 773 */ 774 if (*curftype == BADFTYPE) { 775 *curftype = el_ent->ftype; 776 return (TYPE_OK); /* do nothing; not really different */ 777 } 778 779 /* If the new entity is ambiguous, wait for the verify */ 780 if (el_ent->ftype == BADFTYPE) 781 return (TYPE_OK); 782 783 /* 784 * If we're trying to convert an existing regular directory to an 785 * exclusive directory, this is very dangerous. We will continue, but 786 * we will deny the conversion. 787 */ 788 if (el_ent->ftype == 'x' && *curftype == 'd') { 789 logerr(gettext(WRN_TOEXCL), el_ent->path); 790 return (TYPE_IGNORED); 791 } 792 793 etype = itype = 0; 794 795 /* Set etype to that of the new entity */ 796 for (i = 0; types[i]; ++i) { 797 if (strchr(types[i], el_ent->ftype)) { 798 etype = i+1; 799 break; 800 } 801 } 802 803 /* Set itype to that in the package database. */ 804 for (i = 0; types[i]; ++i) { 805 if (strchr(types[i], *curftype)) { 806 itype = i+1; 807 break; 808 } 809 } 810 811 if (itype == etype) { 812 /* same basic object type */ 813 return (TYPE_OK); 814 } 815 816 retcode = TYPE_WARNING; 817 818 /* 819 * If a simple object (like a file) is overwriting a directory, mark 820 * it for full inspection during installation. 821 */ 822 if (etype != 4 && itype == 4) { 823 mstat->dir2nondir = 1; 824 retcode = TYPE_REPLACE; 825 } 826 827 /* allow change, but warn user of possible problems */ 828 switch (itype) { 829 case 1: 830 logerr(gettext(WRN_NOTFILE), el_ent->path); 831 break; 832 833 case 2: 834 logerr(gettext(WRN_NOTSYMLN), el_ent->path); 835 break; 836 837 case 3: 838 logerr(gettext(WRN_NOTLINK), el_ent->path); 839 break; 840 841 case 4: 842 logerr(gettext(WRN_NOTDIR), el_ent->path); 843 break; 844 845 case 5: 846 logerr(gettext(WRN_NOTCHAR), el_ent->path); 847 break; 848 849 case 6: 850 logerr(gettext(WRN_NOTBLOCK), el_ent->path); 851 break; 852 853 case 7: 854 logerr(gettext(WRN_NOTPIPE), el_ent->path); 855 break; 856 857 default: 858 break; 859 } 860 return (retcode); 861 } 862 863 /* 864 * This function takes el_ent (the entry from the pkgmap) and cf_ent (the 865 * entry from the package database) and merge them into el_ent. The rules 866 * are still being figured out, but the comments should make the approach 867 * pretty clear. 868 * 869 * RETURN CODES: 870 * MRG_DIFFERENT The two entries are different and el_ent now contains 871 * the intended new entry to be installed. 872 * MRG_SAME The two entries were identical and the old database 873 * entry will be replaced unchanged. 874 * MRG_REPLACE One or the other entry will be used but the decision 875 * has to be made at install time. 876 */ 877 static int 878 merg(struct cfextra *el_ent, struct cfent *cf_ent) 879 { 880 int n, changed = 0; 881 882 /* 883 * We need to change the original entry to make it look like the new 884 * entry (the eptstat() routine has already added appropriate package 885 * information, but not about 'aclass' which may represent a change 886 * in class from the previous installation. 887 * 888 * NOTE: elent->cf_ent.pinfo (the list of associated packages) is NULL 889 * upon entry to this function. 890 */ 891 892 el_ent->cf_ent.pinfo = cf_ent->pinfo; 893 894 if (dbst == INST_RDY && el_ent->cf_ent.ftype == '?') { 895 el_ent->cf_ent.ftype = cf_ent->ftype; 896 } 897 898 /* 899 * Evaluate the ftype change. Usually the ftype won't change. If it 900 * does it may be easy (s -> f), not allowed (d -> x), so complex we 901 * can't figure it 'til later (d -> s) or fatal (a hook for later). 902 */ 903 if (cf_ent->ftype != el_ent->cf_ent.ftype) { 904 n = typechg(&(el_ent->cf_ent), &(cf_ent->ftype), 905 &(el_ent->mstat)); 906 907 switch (n) { 908 case TYPE_OK: 909 break; 910 911 /* This is an allowable change. */ 912 case TYPE_WARNING: 913 el_ent->mstat.contchg = 1; 914 break; 915 916 /* Not allowed, but leaving it as is is OK. */ 917 case TYPE_IGNORED: 918 logerr(gettext(MSG_TYPIGN)); 919 if (cp_cfent(cf_ent, el_ent) == 0) 920 quit(99); 921 return (MRG_SAME); 922 923 /* Future analysis will reveal if this is OK. */ 924 case TYPE_REPLACE: 925 el_ent->mstat.replace = 1; 926 return (MRG_REPLACE); 927 928 /* Kill it before it does any damage. */ 929 case TYPE_FATAL: 930 logerr(gettext(MSG_TYPE_ERR)); 931 quit(99); 932 933 default: 934 break; 935 } 936 937 changed++; 938 } 939 940 /* Evaluate and merge the class. */ 941 if (strcmp(cf_ent->pkg_class, el_ent->cf_ent.pkg_class)) { 942 /* 943 * we always allow a class change as long as we have 944 * consistent ftypes, which at this point we must 945 */ 946 changed++; 947 if (strcmp(cf_ent->pkg_class, "?")) { 948 (void) strcpy(pkgpinfo->aclass, 949 el_ent->cf_ent.pkg_class); 950 (void) strcpy(el_ent->cf_ent.pkg_class, 951 cf_ent->pkg_class); 952 chgclass(&(el_ent->cf_ent), pkgpinfo); 953 } 954 } 955 956 /* 957 * Evaluate and merge based upon the ftype of the intended package 958 * database entry. 959 */ 960 if (((el_ent->cf_ent.ftype == 's') || (el_ent->cf_ent.ftype == 'l'))) { 961 962 /* If both have link sources, then they need to be merged. */ 963 if (cf_ent->ainfo.local && el_ent->cf_ent.ainfo.local) { 964 /* 965 * If both sources are identical, the merge is 966 * already done. 967 */ 968 if (strcmp(cf_ent->ainfo.local, 969 el_ent->cf_ent.ainfo.local) != NULL) { 970 changed++; 971 972 /* 973 * Otherwise, if the pkgmap entry is 974 * ambiguous, it will inherit the database 975 * entry. 976 */ 977 if (strcmp(el_ent->cf_ent.ainfo.local, 978 "?") == NULL) { 979 (void) strlcpy( 980 el_ent->cf_ent.ainfo.local, 981 cf_ent->ainfo.local, 982 PATH_MAX); 983 } else { 984 el_ent->mstat.contchg = 1; 985 } 986 } 987 } 988 return (changed ? MRG_DIFFERENT : MRG_SAME); 989 990 } else if (el_ent->cf_ent.ftype == 'e') { 991 992 /* 993 * The contents of edittable files are assumed to be changing 994 * since some class action script will be doing the work and 995 * we have no way of evaluating what it will actually do. 996 */ 997 el_ent->mstat.contchg = 1; 998 changed++; 999 } else if (((el_ent->cf_ent.ftype == 'f') || 1000 (el_ent->cf_ent.ftype == 'v'))) { 1001 /* 1002 * For regular files, Look at content information; a BADCONT 1003 * in any el_ent field indicates the contents are unknown -- 1004 * since cf_ent is guaranteed to have a valid entry here (bad 1005 * assumption?) this function will recognize this as a 1006 * change. The ambiguous el_ent values will be evaluated and 1007 * set later. 1008 */ 1009 1010 /* 1011 * for type f/v files, if the file is in an area that is 1012 * inherited from the global zone, that area is read only 1013 * and the object cannot be changed - ignore any settings 1014 * in the current package database that may be present for 1015 * any existing object because they are irrelevant - since 1016 * the object is in a read-only area shared from the global 1017 * zone, accept that file's actual attributes as being correct. 1018 */ 1019 1020 if (z_path_is_inherited(el_ent->cf_ent.path, 1021 el_ent->cf_ent.ftype, get_inst_root()) == B_TRUE) { 1022 echoDebug(DBG_PKGDBMRG_INHERITED, el_ent->cf_ent.path); 1023 } else if (cf_ent->cinfo.size != el_ent->cf_ent.cinfo.size) { 1024 changed++; 1025 el_ent->mstat.contchg = 1; 1026 } else if (cf_ent->cinfo.modtime != 1027 el_ent->cf_ent.cinfo.modtime) { 1028 changed++; 1029 el_ent->mstat.contchg = 1; 1030 } else if (cf_ent->cinfo.cksum != el_ent->cf_ent.cinfo.cksum) { 1031 changed++; 1032 el_ent->mstat.contchg = 1; 1033 } 1034 } else if (((el_ent->cf_ent.ftype == 'c') || 1035 (el_ent->cf_ent.ftype == 'b'))) { 1036 /* 1037 * For devices, if major or minor numbers are identical the 1038 * merge is trivial. If the el_ent value is ambiguous (BAD), 1039 * the cf_ent value is inherited. Otherwise, the el_ent value 1040 * is preserved. 1041 */ 1042 if (cf_ent->ainfo.major != el_ent->cf_ent.ainfo.major) { 1043 changed++; 1044 if (el_ent->cf_ent.ainfo.major == BADMAJOR) { 1045 el_ent->cf_ent.ainfo.major = 1046 cf_ent->ainfo.major; 1047 } else { 1048 el_ent->mstat.contchg = 1; 1049 } 1050 } 1051 if (cf_ent->ainfo.minor != el_ent->cf_ent.ainfo.minor) { 1052 changed++; 1053 if (el_ent->cf_ent.ainfo.minor == BADMINOR) 1054 el_ent->cf_ent.ainfo.minor = 1055 cf_ent->ainfo.minor; 1056 else 1057 el_ent->mstat.contchg = 1; 1058 } 1059 } 1060 1061 /* 1062 * For mode, owner and group follow the same rules as above - if 1063 * ambiguous, inherit, otherwise keep the new one. 1064 */ 1065 if (cf_ent->ainfo.mode != el_ent->cf_ent.ainfo.mode) { 1066 changed++; /* attribute info is changing */ 1067 if (el_ent->cf_ent.ainfo.mode == BADMODE) { 1068 el_ent->cf_ent.ainfo.mode = cf_ent->ainfo.mode; 1069 } else if (el_ent->cf_ent.ainfo.mode == WILDCARD) { 1070 /* 1071 * If pkgmap has a '?' set for mode, use the mode from 1072 * the pkg DB (contents file). 1073 */ 1074 el_ent->cf_ent.ainfo.mode = cf_ent->ainfo.mode; 1075 el_ent->mstat.attrchg = 0; 1076 } else { 1077 el_ent->mstat.attrchg = 1; 1078 } 1079 } 1080 if (strcmp(cf_ent->ainfo.owner, el_ent->cf_ent.ainfo.owner) != 0) { 1081 changed++; /* attribute info is changing */ 1082 if (strcmp(el_ent->cf_ent.ainfo.owner, BADOWNER) == 0) 1083 (void) strcpy(el_ent->cf_ent.ainfo.owner, 1084 cf_ent->ainfo.owner); 1085 else 1086 el_ent->mstat.attrchg = 1; 1087 } 1088 if (strcmp(cf_ent->ainfo.group, el_ent->cf_ent.ainfo.group) != 0) { 1089 changed++; /* attribute info is changing */ 1090 if (strcmp(el_ent->cf_ent.ainfo.group, BADGROUP) == 0) 1091 (void) strcpy(el_ent->cf_ent.ainfo.group, 1092 cf_ent->ainfo.group); 1093 else 1094 el_ent->mstat.attrchg = 1; 1095 } 1096 return (changed ? MRG_DIFFERENT : MRG_SAME); 1097 } 1098 1099 /* 1100 * This puts the current entry into the package database in the appropriate 1101 * intermediate format for this stage of the installation. This also assures 1102 * the correct format for the various package object ftypes, stripping the 1103 * link name before storing a regular file and stuff like that. 1104 */ 1105 1106 static void 1107 output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo) 1108 { 1109 short svvolno; 1110 char *svpt; 1111 1112 /* output without volume information */ 1113 svvolno = ent->volno; 1114 ent->volno = 0; 1115 1116 pinfo->editflag = 0; 1117 if (((ent->ftype == 's') || (ent->ftype == 'l'))) { 1118 if (putcvfpfile(ent, vfpo)) { 1119 progerr(gettext(ERR_OUTPUT)); 1120 quit(99); 1121 } 1122 } else { 1123 1124 /* output without local pathname */ 1125 svpt = ent->ainfo.local; 1126 ent->ainfo.local = NULL; 1127 if (putcvfpfile(ent, vfpo)) { 1128 progerr(gettext(ERR_OUTPUT)); 1129 quit(99); 1130 } 1131 1132 ent->ainfo.local = svpt; 1133 /* 1134 * If this entry represents a file which is being edited, we 1135 * need to store in memory the fact that it is an edittable 1136 * file so that when we audit it after installation we do not 1137 * worry about its contents; we do this by resetting the ftype 1138 * to 'e' in the memory array which is later used to control 1139 * the audit 1140 */ 1141 if (pinfo->editflag) 1142 ent->ftype = 'e'; 1143 } 1144 /* restore volume information */ 1145 ent->volno = svvolno; 1146 } 1147 1148 static void 1149 chgclass(struct cfent *cf_ent, struct pinfo *pinfo) 1150 { 1151 struct pinfo *pp; 1152 char *oldclass, newclass[CLSSIZ+1]; 1153 int newcnt, oldcnt; 1154 1155 /* 1156 * we use this routine to minimize the use of the aclass element by 1157 * optimizing the use of the cf_ent->pkg_class element 1158 */ 1159 1160 (void) strlcpy(newclass, pinfo->aclass, sizeof (newclass)); 1161 newcnt = 1; 1162 1163 oldclass = cf_ent->pkg_class; 1164 oldcnt = 0; 1165 1166 /* 1167 * count the number of times the newclass will be used and see if it 1168 * exceeds the number of times the oldclass is referenced 1169 */ 1170 pp = cf_ent->pinfo; 1171 while (pp) { 1172 if (pp->aclass[0] != '\0') { 1173 if (strcmp(pp->aclass, newclass) == 0) 1174 newcnt++; 1175 else if (strcmp(pp->aclass, oldclass) == 0) 1176 oldcnt++; 1177 } 1178 pp = pp->next; 1179 } 1180 if (newcnt > oldcnt) { 1181 pp = cf_ent->pinfo; 1182 while (pp) { 1183 if (pp->aclass[0] == '\0') { 1184 (void) strcpy(pp->aclass, oldclass); 1185 } else if (strcmp(pp->aclass, newclass) == 0) { 1186 pp->aclass[0] = '\0'; 1187 } 1188 pp = pp->next; 1189 } 1190 (void) strcpy(cf_ent->pkg_class, newclass); 1191 } 1192 } 1193