xref: /illumos-gate/usr/src/cmd/svr4pkg/pkginstall/check.c (revision 635216b673cf196ac523ff2a7ab715717e553292)
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 2006 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 <limits.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/stat.h>	/* mkdir declaration is here? */
36 #include <unistd.h>
37 #include <errno.h>
38 #include <utmpx.h>
39 #include <dirent.h>
40 #include <sys/types.h>
41 #include <locale.h>
42 #include <libintl.h>
43 #include <pkgstrct.h>
44 #include <pkglocs.h>
45 #include "install.h"
46 #include <pkglib.h>
47 #include "libadm.h"
48 #include "libinst.h"
49 #include "pkginstall.h"
50 
51 extern struct admin adm;
52 extern struct cfextra **extlist;
53 extern int	ckquit, nocnflct, nosetuid, rprcflag;
54 extern char	ilockfile[], rlockfile[], instdir[], savlog[],
55 		tmpdir[], pkgloc[], pkgloc_sav[], pkgbin[], pkgsav[],
56 		*pkginst, *msgtext;
57 extern char	saveSpoolInstallDir[];
58 
59 static boolean_t	preinstallCheck = B_FALSE;
60 static char		*zoneName = (char *)NULL;
61 
62 static char	ask_cont[100];
63 
64 #define	DISPSIZ	20	/* number of items to display on one page */
65 
66 #define	MSG_RUNLEVEL	"\\nThe current run-level of this machine is <%s>, " \
67 			"which is not a run-level suggested for installation " \
68 			"of this package.  Suggested run-levels (in order of " \
69 			"preference) include:"
70 #define	HLP_RUNLEVEL	"If this package is not installed in a run-level " \
71 			"which has been suggested, it is possible that the " \
72 			"package may not install or operate properly.  If " \
73 			"you wish to follow the run-level suggestions, " \
74 			"answer 'n' to stop installation of the package."
75 #define	MSG_STATECHG	"\\nTo change states, execute\\n\\tshutdown -y " \
76 			"-i%s -g0\\nafter exiting the installation process. " \
77 			"Please note that after changing states you " \
78 			"may have to mount appropriate filesystem(s) " \
79 			"in order to install this package."
80 
81 #define	ASK_CONFLICT	"Do you want to install these conflicting files"
82 #define	MSG_CONFLICT	"\\nThe following files are already installed on the " \
83 			"system and are being used by another package:"
84 #define	MSG_ROGUE	"\\n* - conflict with a file which does not " \
85 			"belong to any package."
86 #define	HLP_CONFLICT	"If you choose to install conflicting files, the " \
87 			"files listed above will be overwritten and/or have " \
88 			"their access permissions changed.  If you choose " \
89 			"not to install these files, installation will " \
90 			"proceed but these specific files will not be " \
91 			"installed.  Note that sane operation of the " \
92 			"software being installed may require these files " \
93 			"be installed; thus choosing to not to do so may " \
94 			"cause inapropriate operation.  If you wish to stop " \
95 			"installation of this package, enter 'q' to quit."
96 
97 #define	ASK_SETUID	"Do you want to install these as setuid/setgid files"
98 #define	MSG_SETUID	"\\nThe following files are being installed with " \
99 			"setuid and/or setgid permissions:"
100 #define	MSG_OVERWR	"\\n* - overwriting a file which is also " \
101 			"setuid/setgid."
102 #define	HLP_SETUID	"The package being installed appears to contain " \
103 			"processes which will have their effective user or " \
104 			"group ids set upon execution.  History has shown " \
105 			"that these types of processes can be a source of " \
106 			"security problems on your system.  If you choose " \
107 			"not to install these as setuid files, installation " \
108 			"will proceed but these specific files will be " \
109 			"installed as regular files with setuid and/or " \
110 			"setgid permissions reset.  Note that sane " \
111 			"operation of the software being installed may " \
112 			"require that these files be installed with setuid " \
113 			"or setgid permissions as delivered; thus choosing " \
114 			"to install them as regular files may cause " \
115 			"inapropriate operation.  If you wish to stop " \
116 			"installation of this package, enter 'q' to quit."
117 #define	MSG_PARTINST	"\\nThe installation of this package was previously " \
118 			"terminated and installation was never successfully " \
119 			"completed."
120 #define	MSG_PARTREM	"\\nThe removal of this package was terminated at " \
121 			"some point in time, and package removal was only " \
122 			"partially completed."
123 #define	HLP_PARTIAL	"Installation of partially installed packages is " \
124 			"normally allowable, but some packages providers " \
125 			"may suggest that a partially installed package be " \
126 			"completely removed before re-attempting " \
127 			"installation.  Check the documentation provided " \
128 			"with this package, and then answer 'y' if you feel " \
129 			"it is advisable to continue the installation process."
130 
131 #define	HLP_SPACE	"It appears that there is not enough free space on " \
132 			"your system in which to install this package.  It " \
133 			"is possible that one or more filesystems are not " \
134 			"properly mounted.  Neither installation of the " \
135 			"package nor its operation can be guaranteed under " \
136 			"these conditions.  If you choose to disregard this " \
137 			"warning, enter 'y' to continue the installation " \
138 			"process."
139 #define	HLP_DEPEND	"The package being installed has indicated a " \
140 			"dependency on the existence (or non-existence) " \
141 			"of another software package.  If this dependency is " \
142 			"not met before continuing, the package may not " \
143 			"install or operate properly.  If you wish to " \
144 			"disregard this dependency, answer 'y' to continue " \
145 			"the installation process."
146 
147 #define	MSG_PRIV	"\\nThis package contains scripts which will be " \
148 			"executed with super-user permission during the " \
149 			"process of installing this package."
150 #define	HLP_PRIV	"During the installation of this package, certain " \
151 			"scripts provided with the package will execute with " \
152 			"super-user permission.  These scripts may modify or " \
153 			"otherwise change your system without your " \
154 			"knowledge.  If you are certain of the origin and " \
155 			"trustworthiness of the package being installed, " \
156 			"answer 'y' to continue the installation process."
157 
158 #define	ASK_CONT	"Do you want to continue with the installation of <%s>"
159 #define	HLP_CONT	"If you choose 'y', installation of this package " \
160 			"will continue.  If you want to stop installation " \
161 			"of this package, choose 'n'."
162 
163 #define	MSG_MKPKGDIR	"unable to make packaging directory <%s>"
164 
165 #define	MSG_CKCONFL_GZ	"## Checking for conflicts with packages already " \
166 			"installed."
167 #define	MSG_CKCONFL_LZ	"## Checking for conflicts with packages already " \
168 			"installed in zone <%s>."
169 #define	MSG_CKDEPEND_GZ	"## Verifying package dependencies."
170 #define	MSG_CKDEPEND_LZ	"## Verifying package dependencies in zone <%s>."
171 #define	MSG_CKSPACE_GZ	"## Verifying disk space requirements."
172 #define	MSG_CKSPACE_LZ	"## Verifying disk space requirements in zone <%s>."
173 #define	MSG_CKUID_GZ	"## Checking for setuid/setgid programs."
174 #define	MSG_CKUID_LZ	"## Checking for setuid/setgid programs in zone <%s>."
175 
176 #define	MSG_SCRFND	"Package scripts were found."
177 #define	MSG_UIDFND	"Setuid/setgid processes detected."
178 #define	MSG_ATTRONLY	"!%s %s <attribute change only>"
179 
180 #define	MSG_CONTDISP	"[Hit <RETURN> to continue display]"
181 
182 #define	ERR_NO_RUNST	"unable to determine current run-state"
183 #define	ERR_DEPFAILED	"Dependency checking failed."
184 #define	ERR_SPCFAILED	"Space checking failed."
185 #define	ERR_CNFFAILED	"Conflict checking failed."
186 #define	ERR_BADFILE	"packaging file <%s> is corrupt"
187 
188 /*
189  * Return value:	int
190  *			0 - success
191  *			1 - end of file
192  *			2 - undefined error
193  *			3 - answer was not "y"/was "q"
194  *			4 - quit action taken
195  *			5 - interactive mode required
196  * If "preinstallcheck" is set to B_TRUE:
197  *			8 - partial install detected
198  *			9 - partial removal detected
199  */
200 
201 int
202 ckpartial(void)
203 {
204 	char	ans[MAX_INPUT];
205 	int	n;
206 
207 	if (ADM(partial, "nocheck")) {
208 		return (0);
209 	}
210 
211 	if (access(ilockfile, F_OK) == 0) {
212 		if (preinstallCheck == B_TRUE) {
213 			return (8);	/* partial install detected */
214 		}
215 
216 		(void) snprintf(ask_cont, sizeof (ask_cont),
217 			gettext(ASK_CONT), pkginst);
218 
219 		msgtext = gettext(MSG_PARTINST);
220 		ptext(stderr, msgtext);
221 
222 		if (ADM(partial, "quit")) {
223 			return (4);
224 		}
225 
226 		if (echoGetFlag() == B_FALSE) {
227 			return (5);
228 		}
229 
230 		msgtext = NULL;
231 
232 		ckquit = 0;
233 		if (n = ckyorn(ans, NULL, NULL, gettext(HLP_PARTIAL),
234 				ask_cont)) {
235 			return (n);
236 		}
237 
238 		if (strchr("yY", *ans) == NULL) {
239 			return (3);
240 		}
241 		ckquit = 1;
242 	}
243 
244 	if (access(rlockfile, F_OK) == 0) {
245 		if (preinstallCheck == B_TRUE) {
246 			return (9);	/* partial removal detected */
247 		}
248 
249 		(void) snprintf(ask_cont, sizeof (ask_cont),
250 			gettext(ASK_CONT), pkginst);
251 
252 
253 		msgtext = gettext(MSG_PARTREM);
254 		ptext(stderr, msgtext);
255 
256 		if (ADM(partial, "quit")) {
257 			return (4);
258 		}
259 
260 		if (echoGetFlag() == B_FALSE) {
261 			return (5);
262 		}
263 
264 		msgtext = NULL;
265 
266 		ckquit = 0;
267 		if (n = ckyorn(ans, NULL, NULL, gettext(HLP_PARTIAL),
268 			ask_cont)) {
269 			return (n);
270 		}
271 
272 		if (strchr("yY", *ans) == NULL) {
273 			return (3);
274 		}
275 		ckquit = 1;
276 	}
277 
278 	return (0);
279 }
280 
281 /*
282  * Return value:	int
283  *			0 - success
284  *			1 - end of file
285  *			2 - undefined error
286  *			3 - answer was not "y"/was "q"
287  *			4 - quit action taken
288  *			5 - interactive mode required
289  *			99 - fatal error
290  */
291 
292 int
293 ckrunlevel(void)
294 {
295 	struct utmpx utmpx;
296 	struct utmpx *putmpx;
297 	char	ans[MAX_INPUT], *pt, *istates, *pstate;
298 	int	n;
299 	char	*uxstate;
300 
301 	if (ADM(runlevel, "nocheck")) {
302 		return (0);
303 	}
304 
305 	pt = getenv("ISTATES");
306 	if (pt == NULL) {
307 		return (0);
308 	}
309 
310 	utmpx.ut_type = RUN_LVL;
311 	putmpx = getutxid(&utmpx);
312 	if (putmpx == NULL) {
313 		progerr(gettext(ERR_NO_RUNST));
314 		return (99);
315 	}
316 
317 	(void) snprintf(ask_cont, sizeof (ask_cont),
318 			gettext(ASK_CONT), pkginst);
319 
320 	/*
321 	 * this cryptic code is trying to pull the run level
322 	 * out of the utmpx entry...the level starts in column
323 	 * 11 - looks like "run-level %c"
324 	 */
325 	uxstate = strtok(&putmpx->ut_line[10], " \t\n");
326 
327 	istates = qstrdup(pt);
328 	if ((pt = strtok(pt, " \t\n, ")) == NULL) {
329 		return (0); /* no list is no list */
330 	}
331 
332 	pstate = pt;
333 	do {
334 		if (strcmp(pt, uxstate) == 0) {
335 			free(istates);
336 			return (0);
337 		}
338 	} while (pt = strtok(NULL, " \t\n, "));
339 
340 	if (preinstallCheck == B_FALSE) {
341 		msgtext = gettext(MSG_RUNLEVEL);
342 		ptext(stderr, msgtext, uxstate);
343 	} else {
344 		(void) fprintf(stdout, "runlevel=%s", uxstate);
345 	}
346 
347 	pt = strtok(istates, " \t\n, ");
348 	do {
349 		if (preinstallCheck == B_FALSE) {
350 			ptext(stderr, "\\t%s", pt);
351 		} else {
352 			(void) fprintf(stdout, ":%s", pt);
353 		}
354 	} while (pt = strtok(NULL, " \t\n, "));
355 
356 	if (preinstallCheck == B_TRUE) {
357 		(void) fprintf(stdout, "\n");
358 	}
359 
360 	free(istates);
361 
362 	if (preinstallCheck == B_TRUE) {
363 		return (4);
364 	}
365 
366 	if (ADM(runlevel, "quit")) {
367 		return (4);
368 	}
369 
370 	if (echoGetFlag() == B_FALSE) {
371 		return (5);
372 	}
373 
374 	msgtext = NULL;
375 
376 	ckquit = 0;
377 	if (n = ckyorn(ans, NULL, NULL, gettext(HLP_RUNLEVEL),
378 		ask_cont)) {
379 		return (n);
380 	}
381 
382 	ckquit = 1;
383 
384 	if (strchr("yY", *ans) != NULL) {
385 		return (0);
386 	} else {
387 		if (preinstallCheck == B_FALSE) {
388 			ptext(stderr, gettext(MSG_STATECHG), pstate);
389 		}
390 		return (3);
391 	}
392 }
393 
394 /*
395  * Return value:	int
396  *			0 - success
397  *			1 - end of file
398  *			2 - undefined error
399  *			3 - answer was not "y"/was "q"
400  *			4 - quit action taken
401  *			5 - interactive mode required
402  */
403 
404 int
405 ckdepend(void)
406 {
407 	int	n;
408 	char	ans[MAX_INPUT];
409 	char	path[PATH_MAX];
410 
411 	if (ADM(idepend, "nocheck")) {
412 		return (0);
413 	}
414 
415 	(void) snprintf(path, sizeof (path), "%s/%s", instdir, DEPEND_FILE);
416 	if (access(path, F_OK) != 0) {
417 		return (0); /* no dependency file provided by package */
418 	}
419 
420 	if (zoneName == (char *)NULL) {
421 		echo(gettext(MSG_CKDEPEND_GZ));
422 	} else {
423 		echo(gettext(MSG_CKDEPEND_LZ), zoneName);
424 	}
425 
426 	if (dockdeps(path, 0, preinstallCheck)) {
427 		(void) snprintf(ask_cont, sizeof (ask_cont),
428 			gettext(ASK_CONT), pkginst);
429 		msgtext = gettext(ERR_DEPFAILED);
430 
431 		if (preinstallCheck == B_TRUE) {
432 			return (4);
433 		}
434 
435 		if (ADM(idepend, "quit")) {
436 			return (4);
437 		}
438 
439 		if (echoGetFlag() == B_FALSE) {
440 			return (5);
441 		}
442 
443 		msgtext = NULL;
444 
445 		ckquit = 0;
446 		if (n = ckyorn(ans, NULL, NULL, gettext(HLP_DEPEND),
447 			ask_cont)) {
448 			return (n);
449 		}
450 
451 		if (strchr("yY", *ans) == NULL) {
452 			return (3);
453 		}
454 
455 		ckquit = 1;
456 	}
457 
458 	return (0);
459 }
460 
461 void
462 cksetZoneName(char *a_zoneName)
463 {
464 	zoneName = a_zoneName;
465 }
466 
467 void
468 cksetPreinstallCheck(boolean_t a_preinstallCheck)
469 {
470 	preinstallCheck = a_preinstallCheck;
471 }
472 
473 /*
474  * Return value:	int
475  *			0 - success
476  *			1 - end of file
477  *			2 - undefined error
478  *			3 - answer was not "y"/was "q"
479  *			4 - quit action taken
480  *			5 - interactive mode required
481  */
482 int
483 ckspace(void)
484 {
485 	int	n;
486 	char	ans[MAX_INPUT];
487 	char	path[PATH_MAX];
488 
489 	if (ADM(space, "nocheck")) {
490 		return (0);
491 	}
492 
493 	if (zoneName == (char *)NULL) {
494 		echo(gettext(MSG_CKSPACE_GZ));
495 	} else {
496 		echo(gettext(MSG_CKSPACE_LZ), zoneName);
497 	}
498 
499 	(void) snprintf(path, sizeof (path), "%s/install/space", instdir);
500 	if (access(path, F_OK) == 0) {
501 		n = dockspace(path);
502 	} else {
503 		n = dockspace(NULL);
504 	}
505 
506 	if (n) {
507 		msgtext = gettext(ERR_SPCFAILED);
508 		(void) snprintf(ask_cont, sizeof (ask_cont),
509 			gettext(ASK_CONT), pkginst);
510 
511 		if (preinstallCheck == B_TRUE) {
512 			return (4);
513 		}
514 
515 		if (ADM(space, "quit")) {
516 			return (4);
517 		}
518 
519 		if (echoGetFlag() == B_FALSE) {
520 			return (5);
521 		}
522 
523 		msgtext = NULL;
524 
525 		ckquit = 0;
526 		n = ckyorn(ans, NULL, NULL, gettext(HLP_SPACE), ask_cont);
527 		if (n != 0) {
528 			return (n);
529 		}
530 
531 		if (strchr("yY", *ans) == NULL) {
532 			return (3);
533 		}
534 
535 		ckquit = 1;
536 	}
537 	return (0);
538 }
539 
540 void
541 ckdirs(void)
542 {
543 	char	path[PATH_MAX];
544 
545 	if (mkpath(get_PKGADM())) {
546 		if (preinstallCheck == B_TRUE) {
547 			(void) fprintf(stdout, "ckdirs=%s\n", get_PKGADM());
548 		} else {
549 			progerr(gettext(MSG_MKPKGDIR), get_PKGADM());
550 		}
551 		quit(99);
552 	}
553 
554 	(void) snprintf(path, sizeof (path), "%s/admin", get_PKGADM());
555 
556 	if (mkpath(path)) {
557 		if (preinstallCheck == B_TRUE) {
558 			(void) fprintf(stdout, "ckdirs=%s\n", path);
559 		} else {
560 			progerr(gettext(MSG_MKPKGDIR), path);
561 		}
562 		quit(99);
563 	}
564 
565 	(void) snprintf(path, sizeof (path), "%s/logs", get_PKGADM());
566 
567 	if (mkpath(path)) {
568 		if (preinstallCheck == B_TRUE) {
569 			(void) fprintf(stdout, "ckdirs=%s\n", path);
570 		} else {
571 			progerr(gettext(MSG_MKPKGDIR), path);
572 		}
573 		quit(99);
574 	}
575 
576 	if (mkpath(PKGSCR)) {
577 		if (preinstallCheck == B_TRUE) {
578 			(void) fprintf(stdout, "ckdirs=%s\n", PKGSCR);
579 		} else {
580 			progerr(gettext(MSG_MKPKGDIR), PKGSCR);
581 		}
582 		quit(99);
583 	}
584 
585 	if (mkpath(get_PKGLOC())) {
586 		if (preinstallCheck == B_TRUE) {
587 			(void) fprintf(stdout, "ckdirs=%s\n", get_PKGLOC());
588 		} else {
589 			progerr(gettext(MSG_MKPKGDIR), get_PKGLOC());
590 		}
591 		quit(99);
592 	}
593 }
594 
595 /*
596  * Return value:	int
597  *			0 - success
598  *			99 - failure
599  */
600 
601 int
602 ckpkgdirs(void)
603 {
604 	boolean_t nonExistentPkgloc = B_FALSE;
605 
606 	/*
607 	 * If pkgloc doesn't exist make sure it gets removed after creating
608 	 * it if this is a preinstall check. All dryrun and preinstallation
609 	 * checks must not modify the file system.
610 	 */
611 
612 	if (access(pkgloc, F_OK) != 0) {
613 		nonExistentPkgloc = B_TRUE;
614 	}
615 
616 	if (mkpath(pkgloc)) {
617 		if (preinstallCheck == B_TRUE) {
618 			(void) fprintf(stdout, "ckdirs=%s\n", pkgloc);
619 		} else {
620 			progerr(gettext(MSG_MKPKGDIR), pkgloc);
621 		}
622 		return (99);
623 	}
624 
625 	if (mkpath(pkgbin)) {
626 		if (preinstallCheck == B_TRUE) {
627 			(void) fprintf(stdout, "ckdirs=%s\n", pkgbin);
628 		} else {
629 			progerr(gettext(MSG_MKPKGDIR), pkgbin);
630 		}
631 		return (99);
632 	}
633 
634 	if (mkpath(pkgsav)) {
635 		if (preinstallCheck == B_TRUE) {
636 			(void) fprintf(stdout, "ckdirs=%s\n", pkgsav);
637 		} else {
638 			progerr(gettext(MSG_MKPKGDIR), pkgsav);
639 		}
640 		return (99);
641 	}
642 
643 	if (!is_spool_create() && mkpath(saveSpoolInstallDir)) {
644 		if (preinstallCheck == B_TRUE) {
645 			(void) fprintf(stdout, "ckdirs=%s\n", pkgsav);
646 		} else {
647 			progerr(gettext(MSG_MKPKGDIR), pkgsav);
648 		}
649 		return (99);
650 	}
651 
652 	if (preinstallCheck && nonExistentPkgloc) {
653 		rrmdir(pkgloc);
654 	}
655 
656 	return (0);
657 }
658 
659 /*
660  * Return value:	int
661  *			0 - success
662  *			1 - end of file
663  *			2 - undefined error
664  *			3 - answer was not "y"/was "q"
665  *			4 - quit action taken
666  *			5 - interactive mode required
667  */
668 
669 int
670 ckconflct(void)
671 {
672 	int	i, n, count, has_a_rogue = 0;
673 	char	ans[MAX_INPUT];
674 
675 	if (ADM(conflict, "nochange")) {
676 		nocnflct++;
677 		return (0);
678 	}
679 
680 	if (ADM(conflict, "nocheck")) {
681 		return (0);
682 	}
683 
684 	if (zoneName == (char *)NULL) {
685 		echo(gettext(MSG_CKCONFL_GZ));
686 	} else {
687 		echo(gettext(MSG_CKCONFL_LZ), zoneName);
688 	}
689 
690 	count = 0;
691 	for (i = 0; extlist[i]; i++) {
692 		struct cfent *ept;
693 		struct mergstat *mstat;
694 
695 		if (extlist[i]->cf_ent.ftype == 'i') {
696 			continue;
697 		}
698 
699 		ept = &(extlist[i]->cf_ent);
700 		mstat = &(extlist[i]->mstat);
701 
702 		if (is_remote_fs(ept->path, &(extlist[i]->fsys_value)) &&
703 			!is_fs_writeable(ept->path,
704 				&(extlist[i]->fsys_value))) {
705 			continue;
706 		}
707 
708 		/*
709 		 * If no other package claims it or it's from a continuation
710 		 * file, skip it.
711 		 */
712 		if (!mstat->shared || mstat->preloaded) {
713 			continue;
714 		}
715 
716 		if (ept->ftype == 'e') {
717 			continue;
718 		}
719 
720 		if (mstat->rogue) {
721 			has_a_rogue = 1;
722 		}
723 
724 		if (mstat->contchg) {
725 			if (!count++) {
726 				if (preinstallCheck == B_FALSE) {
727 					ptext(stderr, gettext(MSG_CONFLICT));
728 				}
729 			} else if ((echoGetFlag() == B_TRUE) &&
730 					((count % DISPSIZ) == 0)) {
731 				echo(gettext(MSG_CONTDISP));
732 				(void) getc(stdin);
733 			}
734 			/*
735 			 * NOTE : The leading "!" in this string forces
736 			 * puttext() to print leading white space.
737 			 */
738 
739 			if (preinstallCheck == B_FALSE) {
740 				ptext(stderr, "!%s %s",
741 					(mstat->rogue) ? "*" : " ", ept->path);
742 			} else {
743 				(void) fprintf(stdout,
744 					"conflict-contents=%s\n", ept->path);
745 			}
746 		} else if (mstat->attrchg) {
747 			if (!count++) {
748 				if (preinstallCheck == B_FALSE) {
749 					ptext(stderr, gettext(MSG_CONFLICT));
750 				}
751 			} else if ((echoGetFlag() == B_TRUE) &&
752 					((count % DISPSIZ) == 0)) {
753 				echo(gettext(MSG_CONTDISP));
754 				(void) getc(stdin);
755 			}
756 			if (preinstallCheck == B_FALSE) {
757 				ptext(stderr, gettext(MSG_ATTRONLY),
758 					(mstat->rogue) ? "*" : " ", ept->path);
759 			} else {
760 				(void) fprintf(stdout,
761 					"conflict-attributes=%s\n", ept->path);
762 			}
763 		}
764 	}
765 
766 	if (count) {
767 		if (has_a_rogue) {
768 			if (preinstallCheck == B_FALSE) {
769 				ptext(stderr, gettext(MSG_ROGUE));
770 			}
771 		}
772 
773 		msgtext = gettext(ERR_CNFFAILED);
774 
775 		if (preinstallCheck == B_TRUE) {
776 			return (4);
777 		}
778 
779 		if (ADM(conflict, "quit")) {
780 			return (4);
781 		}
782 
783 		if (echoGetFlag() == B_FALSE) {
784 			return (5);
785 		}
786 
787 		msgtext = NULL;
788 
789 		if (n = ckyorn(ans, NULL, NULL, gettext(HLP_CONFLICT),
790 			gettext(ASK_CONFLICT))) {
791 			return (n);
792 		}
793 
794 		if (strchr("yY", *ans) == NULL) {
795 			ckquit = 0;
796 			(void) snprintf(ask_cont, sizeof (ask_cont),
797 				gettext(ASK_CONT), pkginst);
798 
799 			if (n = ckyorn(ans, NULL, NULL, gettext(HLP_CONT),
800 				ask_cont)) {
801 				return (n);
802 			}
803 
804 			if (strchr("yY", *ans) == NULL) {
805 				return (3);
806 			}
807 			ckquit = 1;
808 			nocnflct++;
809 			rprcflag++;
810 		}
811 	}
812 	return (0);
813 }
814 
815 /*
816  * Return value:	int
817  *			0 - success
818  *			1 - end of file
819  *			2 - undefined error
820  *			3 - answer was not "y"/was "q"
821  *			4 - quit action taken
822  *			5 - interactive mode required
823  */
824 
825 int
826 cksetuid(void)
827 {
828 	int	i, n, count, overwriting = 0;
829 	char	ans[MAX_INPUT];
830 
831 	/* See if the administrative defaults already resolve this check. */
832 	if (ADM(setuid, "nocheck")) {
833 		return (0);
834 	}
835 
836 	if (ADM(setuid, "nochange")) {
837 		nosetuid++;	/* Do not install processes as setuid/gid. */
838 		return (0);
839 	}
840 
841 	/* The administrative defaults require review of the package. */
842 
843 	if (zoneName == (char *)NULL) {
844 		echo(gettext(MSG_CKUID_GZ));
845 	} else {
846 		echo(gettext(MSG_CKUID_LZ), zoneName);
847 	}
848 
849 	count = 0;
850 	for (i = 0; extlist[i]; i++) {
851 		int overwr;
852 		struct mergstat *mstat = &(extlist[i]->mstat);
853 
854 		/*
855 		 * Provide the administrator with info as to whether there is
856 		 * already a setuid process in place. This is only necessary
857 		 * to help the administrator decide whether or not to lay
858 		 * down the process, it doesn't have anything to do with the
859 		 * administrative defaults.
860 		 */
861 		if (mstat->osetuid || mstat->osetgid) {
862 			overwr = 1;
863 			overwriting = 1;
864 		} else
865 			overwr = 0;
866 
867 		if (mstat->setuid || mstat->setgid) {
868 			if (!count++) {
869 				if (preinstallCheck == B_FALSE) {
870 					ptext(stderr, gettext(MSG_SETUID));
871 				}
872 			} else if ((echoGetFlag() == B_TRUE) &&
873 					((count % DISPSIZ) == 0)) {
874 				echo(gettext(MSG_CONTDISP));
875 				(void) getc(stdin);
876 			}
877 			/*
878 			 * NOTE : The leading "!" in these strings forces
879 			 * puttext() to print leading white space.
880 			 */
881 
882 			if (mstat->setuid && mstat->setgid) {
883 				if (preinstallCheck == B_FALSE) {
884 					ptext(stderr, gettext(
885 						"!%s %s <setuid %s setgid %s>"),
886 						(overwr) ? "*" : " ",
887 						extlist[i]->cf_ent.path,
888 						extlist[i]->cf_ent.ainfo.owner,
889 						extlist[i]->cf_ent.ainfo.group);
890 				} else {
891 					(void) fprintf(stdout, "setuid=%s:%s\n",
892 						extlist[i]->cf_ent.path,
893 						extlist[i]->cf_ent.ainfo.owner);
894 					(void) fprintf(stdout, "setgid=%s:%s\n",
895 						extlist[i]->cf_ent.path,
896 						extlist[i]->cf_ent.ainfo.group);
897 				}
898 			} else if (mstat->setuid) {
899 				if (preinstallCheck == B_FALSE) {
900 					ptext(stderr, gettext(
901 						"!%s %s <setuid %s>"),
902 						(overwr) ? "*" : " ",
903 						extlist[i]->cf_ent.path,
904 						extlist[i]->cf_ent.ainfo.owner);
905 				} else {
906 					(void) fprintf(stdout, "setuid=%s:%s\n",
907 						extlist[i]->cf_ent.path,
908 						extlist[i]->cf_ent.ainfo.owner);
909 				}
910 			} else if (mstat->setgid) {
911 				if (preinstallCheck == B_FALSE) {
912 					ptext(stderr, gettext(
913 						"!%s%s <setgid %s>"),
914 						(overwr) ? "*" : " ",
915 						extlist[i]->cf_ent.path,
916 						extlist[i]->cf_ent.ainfo.group);
917 				} else {
918 					(void) fprintf(stdout, "setgid=%s:%s\n",
919 						extlist[i]->cf_ent.path,
920 						extlist[i]->cf_ent.ainfo.group);
921 				}
922 			}
923 		}
924 	}
925 
926 	if (count) {
927 		if (overwriting) {
928 			if (preinstallCheck == B_FALSE) {
929 				ptext(stderr, gettext(MSG_OVERWR));
930 			} else {
931 				(void) fprintf(stdout,
932 					"setuid-overwrite=true\n");
933 			}
934 		}
935 
936 		msgtext = gettext(MSG_UIDFND);
937 
938 		if (preinstallCheck == B_TRUE) {
939 			return (4);
940 		}
941 
942 		if (ADM(setuid, "quit")) {
943 			return (4);
944 		}
945 		if (echoGetFlag() == B_FALSE) {
946 			return (5);
947 		}
948 		msgtext = NULL;
949 
950 		if (n = ckyorn(ans, NULL, NULL, gettext(HLP_SETUID),
951 			gettext(ASK_SETUID))) {
952 			return (n);
953 		}
954 		if (strchr("yY", *ans) == NULL) {
955 			ckquit = 0;
956 			(void) snprintf(ask_cont, sizeof (ask_cont),
957 				gettext(ASK_CONT), pkginst);
958 			if (n = ckyorn(ans, NULL, NULL, gettext(HLP_CONT),
959 				ask_cont)) {
960 				return (n);
961 			}
962 			if (strchr("yY", *ans) == NULL) {
963 				return (3);
964 			}
965 			ckquit = 1;
966 			nosetuid++;
967 			rprcflag++;
968 		}
969 	}
970 
971 	return (0);
972 }
973 
974 /*
975  * Return value:	int
976  *			0 - success
977  *			1 - end of file
978  *			2 - undefined error
979  *			3 - answer was not "y"/was "q"
980  *			4 - quit action taken
981  *			5 - interactive mode required
982  */
983 
984 int
985 ckpriv(void)
986 {
987 	struct dirent *dp;
988 	DIR	*dirfp;
989 	int	n, found;
990 	char	ans[MAX_INPUT], path[PATH_MAX];
991 
992 	if (ADM(action, "nocheck")) {
993 		return (0);
994 	}
995 
996 	(void) snprintf(path, sizeof (path), "%s/install", instdir);
997 	if ((dirfp = opendir(path)) == NULL) {
998 		return (0);
999 	}
1000 
1001 	found = 0;
1002 	while ((dp = readdir(dirfp)) != NULL) {
1003 		if (strcmp(dp->d_name, "preinstall") == 0 ||
1004 			strcmp(dp->d_name, "postinstall") == 0 ||
1005 			strncmp(dp->d_name, "i.", 2) == 0) {
1006 			found++;
1007 			break;
1008 		}
1009 	}
1010 	(void) closedir(dirfp);
1011 
1012 	if (found) {
1013 		if (preinstallCheck == B_FALSE) {
1014 			ptext(stderr, gettext(MSG_PRIV));
1015 			msgtext = gettext(MSG_SCRFND);
1016 		}
1017 		(void) snprintf(ask_cont, sizeof (ask_cont),
1018 				gettext(ASK_CONT), pkginst);
1019 
1020 		if (preinstallCheck == B_TRUE) {
1021 			return (4);
1022 		}
1023 
1024 		if (ADM(action, "quit")) {
1025 			return (4);
1026 		}
1027 
1028 		if (echoGetFlag() == B_FALSE) {
1029 			return (5);
1030 		}
1031 
1032 		msgtext = NULL;
1033 
1034 		ckquit = 0;
1035 		if (n = ckyorn(ans, NULL, NULL, gettext(HLP_PRIV),
1036 			ask_cont)) {
1037 			return (n);
1038 		}
1039 
1040 		if (strchr("yY", *ans) == NULL) {
1041 			return (3);
1042 		}
1043 		ckquit = 1;
1044 	}
1045 
1046 	return (0);
1047 }
1048 
1049 /*
1050  * Return value:	int
1051  *			0 - success
1052  *			99 - failure
1053  */
1054 
1055 int
1056 ckpkgfiles(void)
1057 {
1058 	register int i;
1059 	struct cfent	*ept;
1060 	int	errflg;
1061 	char	source[PATH_MAX];
1062 
1063 	errflg = 0;
1064 	for (i = 0; extlist[i]; i++) {
1065 		ept = &(extlist[i]->cf_ent);
1066 		if (ept->ftype != 'i') {
1067 			continue;
1068 		}
1069 
1070 		if (ept->ainfo.local) {
1071 			(void) snprintf(source, sizeof (source),
1072 				"%s/%s", instdir, ept->ainfo.local);
1073 		} else if (strcmp(ept->path, PKGINFO) == 0) {
1074 			(void) snprintf(source, sizeof (source),
1075 				"%s/%s", instdir, ept->path);
1076 		} else {
1077 			(void) snprintf(source, sizeof (source),
1078 				"%s/install/%s", instdir, ept->path);
1079 		}
1080 		if (cverify(0, &ept->ftype, source, &ept->cinfo, 1)) {
1081 			errflg++;
1082 			if (preinstallCheck == B_FALSE) {
1083 				progerr(gettext(ERR_BADFILE), source);
1084 				logerr(getErrbufAddr());
1085 			} else {
1086 				(void) fprintf(stdout, "ckpkgfilebad=%s",
1087 					source);
1088 			}
1089 		}
1090 	}
1091 
1092 	if (errflg) {
1093 		return (99);
1094 	} else {
1095 		return (0);
1096 	}
1097 }
1098