xref: /onnv-gate/usr/src/cmd/tsol/updatehome/setupfiles.c (revision 11561:e0d5740d4722)
14746Srica /*
24746Srica  * CDDL HEADER START
34746Srica  *
44746Srica  * The contents of this file are subject to the terms of the
54746Srica  * Common Development and Distribution License (the "License").
64746Srica  * You may not use this file except in compliance with the License.
74746Srica  *
84746Srica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94746Srica  * or http://www.opensolaris.org/os/licensing.
104746Srica  * See the License for the specific language governing permissions
114746Srica  * and limitations under the License.
124746Srica  *
134746Srica  * When distributing Covered Code, include this CDDL HEADER in each
144746Srica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154746Srica  * If applicable, add the following below this CDDL HEADER, with the
164746Srica  * fields enclosed by brackets "[]" replaced with your own identifying
174746Srica  * information: Portions Copyright [yyyy] [name of copyright owner]
184746Srica  *
194746Srica  * CDDL HEADER END
204746Srica  */
214746Srica 
224746Srica /*
23*11561SRic.Aleshire@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
244746Srica  * Use is subject to license terms.
254746Srica  */
264746Srica 
274746Srica #include <errno.h>
284746Srica #include <pwd.h>
294746Srica #include <stdio.h>
304746Srica #include <stdlib.h>
314746Srica #include <string.h>
324746Srica #include <unistd.h>
334746Srica 
344746Srica #include <sys/param.h>
354746Srica #include <sys/types.h>
364746Srica #include <sys/wait.h>
374746Srica 
384746Srica #include <tsol/label.h>
394746Srica #include <zone.h>
404746Srica #include <sys/stat.h>
414746Srica 
424746Srica #include "setupfiles.h"
434746Srica 
444746Srica #define	dperror(s) if (flags & DIAG) perror(s)
454746Srica #define	dprintf(s, v) if (flags & DBUG) (void) printf(s, v)
464746Srica #define	dprintf2(s, v1, v2) if (flags & DBUG) (void) printf(s, v1, v2)
474746Srica 
484746Srica static int mkdirs(const char *dir, const char *target, int flags);
494746Srica static int copyfile(const char *min_home, const char *home, const char *target,
504746Srica     int flags);
514746Srica static int linkfile(const char *min_home, const char *home, const char *target,
524746Srica     int flags);
534746Srica 
544746Srica 
554746Srica /*
564746Srica  *	__setupfiles - Process copy and link files directions in min $HOME.
574746Srica  *
584746Srica  *	Entry	pwd = user's password file entry.
594746Srica  *		min_sl = user's minimum SL.
604746Srica  *		flags = DBUG, if print debug messages.
614746Srica  *			DIAG, if print diagnostics (perrors).
624746Srica  *			IGNE, continue rather than abort on failures.
634746Srica  *			REPC, if replace existing file.
644746Srica  *			REPL, if replace existing symbolic link.
654746Srica  *		process is running as user at correct label.
664746Srica  *
674746Srica  *	Exit	None.
684746Srica  *
694746Srica  *	Returns	0, if success.
704746Srica  *		errno, if failure.
714746Srica  *
724746Srica  *	Uses	COPY, CP, LINK, MAXPATHLEN.
734746Srica  *
74*11561SRic.Aleshire@Sun.COM  *	Calls	blequal, copyfile, feof, fgets, fopen,
754746Srica  *		mkdirs, getzoneid, getzonelabelbyid, linkfile, strcat, strcpy,
764746Srica  *		strlen.
774746Srica  *
784746Srica  *	This program assumes the /zone is the autofs mountpoint for
794746Srica  *	cross-zone mounts.
804746Srica  *
814746Srica  *	It also assumes that the user's home directory path is the
824746Srica  *	the same in each zone, relative to the zone's root.
834746Srica  *
844746Srica  *	At this point, the cross-zone automounter only supports home
854746Srica  * 	directories starting with /home
864746Srica  */
874746Srica 
884746Srica int
__setupfiles(const struct passwd * pwd,const m_label_t * min_sl,int flags)89*11561SRic.Aleshire@Sun.COM __setupfiles(const struct passwd *pwd, const m_label_t *min_sl, int flags)
904746Srica {
91*11561SRic.Aleshire@Sun.COM 	m_label_t *plabel;		/* process label */
924746Srica 	char	home[MAXPATHLEN];	/* real path to current $HOME */
934746Srica 	char	min_home[MAXPATHLEN];	/* real path to min $HOME */
944746Srica 	char	cl_file[MAXPATHLEN];	/* real path to .copy/.link_files */
954746Srica 	char	file[MAXPATHLEN];	/* file to copy/link */
964746Srica 	FILE	*clf;			/* .copy/.link_file stream */
974746Srica 	char	zoneroot[MAXPATHLEN];
984746Srica 	zoneid_t zoneid;
994746Srica 	zoneid_t min_zoneid;
1004746Srica 
1014746Srica 	zoneid = getzoneid();
1024746Srica 	if ((plabel = getzonelabelbyid(zoneid)) == NULL) {
1034746Srica 
1044746Srica 		dperror("setupfiles can't get process label");
1054746Srica 		return (errno);
1064746Srica 	}
1074746Srica 
1084746Srica 	if (blequal(plabel, min_sl)) {
1094746Srica 		/* at min SL no files to setup */
1104746Srica 
1114746Srica 		return (0);
1124746Srica 	}
1134746Srica 
1144746Srica 	/* get current home real path */
1154746Srica 
1164746Srica 	(void) strlcpy(home, pwd->pw_dir, MAXPATHLEN);
1174746Srica 
1184746Srica 	/* Get zone id from min_sl */
1194746Srica 
1204746Srica 	if ((min_zoneid = getzoneidbylabel(min_sl)) == -1) {
1214746Srica 
1224746Srica 		dperror("setupfiles can't get zoneid for min sl");
1234746Srica 		return (errno);
1244746Srica 	}
1254746Srica 
1264746Srica 	/*
1274746Srica 	 * Since the global zone home directories aren't public
1284746Srica 	 * information, we don't support copy and link files there.
1294746Srica 	 */
1304746Srica 	if (min_zoneid == GLOBAL_ZONEID)
1314746Srica 		return (0);
1324746Srica 
1334746Srica 	/*
1344746Srica 	 * Get zone root path from zone id
1354746Srica 	 *
1364746Srica 	 * Could have used getzonenamebyid() but this assumes that /etc/zones
1374746Srica 	 * directory is available, which is not true in labeled zones
1384746Srica 	 */
1394746Srica 
1404746Srica 	if (zone_getattr(min_zoneid, ZONE_ATTR_ROOT, zoneroot,
1414746Srica 	    sizeof (zoneroot)) == -1) {
1424746Srica 		dperror("setupfiles can't get zone root path for min sl");
1434746Srica 		return (errno);
1444746Srica 	}
1454746Srica 
1464746Srica 	(void) snprintf(min_home, MAXPATHLEN, "%s%s",
1474746Srica 	    zoneroot, pwd->pw_dir);
1484746Srica 
1494746Srica 	/* process copy files */
1504746Srica 
1514746Srica 	if ((strlen(min_home) + strlen(COPY)) > (MAXPATHLEN - 1)) {
1524746Srica 
1534746Srica 		dprintf("setupfiles copy path %s", min_home);
1544746Srica 		dprintf("%s ", COPY);
1554746Srica 		dprintf("greater than %d\n", MAXPATHLEN);
1564746Srica 		errno = ENAMETOOLONG;
1574746Srica 		dperror("setupfiles copy path");
1584746Srica 		return (errno);
1594746Srica 	}
1604746Srica 
1614746Srica 	(void) strcpy(cl_file, min_home);
1624746Srica 	(void) strcat(cl_file, COPY);
1634746Srica 
1644746Srica 	if ((clf = fopen(cl_file, "r")) != NULL) {
1654746Srica 
1664746Srica 		while (fgets(file, MAXPATHLEN, clf) != NULL) {
1674746Srica 
1684746Srica 			if (!feof(clf))		/* remove trailing \n */
1694746Srica 				file[strlen(file) - 1] = '\0';
1704746Srica 
1714746Srica 			dprintf("copy file %s requested\n", file);
1724746Srica 
1734746Srica 			/* make any needed subdirectories */
1744746Srica 
1754746Srica 			if (mkdirs(home, file, flags) != 0) {
1764746Srica 
1774746Srica 				if ((flags & IGNE) == 0)
1784746Srica 					return (errno);
1794746Srica 				else
1804746Srica 					continue;
1814746Srica 			}
1824746Srica 
1834746Srica 			/* copy the file */
1844746Srica 
1854746Srica 			if (copyfile(min_home, home, file, flags) != 0) {
1864746Srica 
1874746Srica 				if ((flags & IGNE) == 0)
1884746Srica 					return (errno);
1894746Srica 				else
1904746Srica 					continue;
1914746Srica 
1924746Srica 			}
1934746Srica 
1944746Srica 		}  /* while (fgets( ... ) != NULL) */
1954746Srica 	} else {
1964746Srica 		if (errno != ENOENT)
1974746Srica 			dperror("setupfiles copy file open");
1984746Srica 		dprintf("setupfiles no copyfile %s\n", cl_file);
1994746Srica 	}  /* process copy files */
2004746Srica 
2014746Srica 
2024746Srica 	/* process link files */
2034746Srica 
2044746Srica 	if ((strlen(min_home) + strlen(LINK)) > (MAXPATHLEN - 1)) {
2054746Srica 
2064746Srica 		dprintf("setupfiles link path %s", min_home);
2074746Srica 		dprintf("%s ", LINK);
2084746Srica 		dprintf("greater than %d\n", MAXPATHLEN);
2094746Srica 		errno = ENAMETOOLONG;
2104746Srica 		dperror("setupfiles link path");
2114746Srica 		return (errno);
2124746Srica 	}
2134746Srica 
2144746Srica 	(void) strcpy(cl_file, min_home);
2154746Srica 	(void) strcat(cl_file, LINK);
2164746Srica 
2174746Srica 	if ((clf = fopen(cl_file, "r")) != NULL) {
2184746Srica 
2194746Srica 		while (fgets(file, MAXPATHLEN, clf) != NULL) {
2204746Srica 
2214746Srica 			if (!feof(clf))		/* remove trailing \n */
2224746Srica 				file[strlen(file) - 1] = '\0';
2234746Srica 
2244746Srica 			dprintf("link file %s requested\n", file);
2254746Srica 
2264746Srica 			/* make any needed subdirectories */
2274746Srica 
2284746Srica 			if (mkdirs(home, file, flags) != 0) {
2294746Srica 
2304746Srica 				if ((flags & IGNE) == 0)
2314746Srica 					return (errno);
2324746Srica 				else
2334746Srica 					continue;
2344746Srica 			}
2354746Srica 
2364746Srica 			/* link the file */
2374746Srica 
2384746Srica 			if (linkfile(min_home, home, file, flags) != 0) {
2394746Srica 
2404746Srica 				if ((flags & IGNE) == 0)
2414746Srica 					return (errno);
2424746Srica 				else
2434746Srica 					continue;
2444746Srica 			}
2454746Srica 
2464746Srica 		}  /* while (fgets ... ) != NULL) */
2474746Srica 	} else {
2484746Srica 		if (errno != ENOENT)
2494746Srica 			dperror("setupfiles link file open");
2504746Srica 		dprintf("setupfiles no linkfile %s\n", cl_file);
2514746Srica 	}  /* process link files */
2524746Srica 
2534746Srica 	return (0);
2544746Srica }  /* setupfiles() */
2554746Srica 
2564746Srica 
2574746Srica /*
2584746Srica  *	mkdirs - Make any needed subdirectories in target's path.
2594746Srica  *
2604746Srica  *	Entry	home = base directory.
2614746Srica  *		file = file to create with intermediate subdirectories.
2624746Srica  *		flags = from __setupfiles -- for dprintf and dperror.
2634746Srica  *
2644746Srica  *	Exit	Needed subdirectories made.
2654746Srica  *
2664746Srica  *	Returns	0, if success.
2674746Srica  *		errno, if failure.
2684746Srica  *
2694746Srica  *	Uses	MAXPATHLEN.
2704746Srica  *
2714746Srica  *	Calls	mkdir, strcat, strcpy, strlen, strtok.
2724746Srica  */
2734746Srica 
2744746Srica static int
mkdirs(const char * home,const char * file,int flags)2754746Srica mkdirs(const char *home, const char *file, int flags)
2764746Srica {
2774746Srica 	char	path[MAXPATHLEN];
2784746Srica 	char	dir[MAXPATHLEN];
2794746Srica 	char	*tok;
2804746Srica 
2814746Srica 	if ((strlen(home) + strlen(file)) > (MAXPATHLEN - 2)) {
2824746Srica 
2834746Srica 		dprintf("setupfiles mkdirs path %s", home);
2844746Srica 		dprintf("/%s ", file);
2854746Srica 		dprintf("greater than %d\n", MAXPATHLEN);
2864746Srica 		errno = ENAMETOOLONG;
2874746Srica 		dperror("setupfiles mkdirs");
2884746Srica 		return (errno);
2894746Srica 	}
2904746Srica 
2914746Srica 	(void) strcpy(dir, file);
2924746Srica 
2934746Srica 	if ((tok = strrchr(dir, '/')) == NULL) {
2944746Srica 
2954746Srica 		dprintf("setupfiles no dirs to make in %s\n", dir);
2964746Srica 		return (0);
2974746Srica 	}
2984746Srica 
2994746Srica 	*tok = '\000';		/* drop last component, it's the target */
3004746Srica 
3014746Srica 	(void) strcpy(path, home);
3024746Srica 
3034746Srica 	for (tok = dir; tok = strtok(tok, "/"); tok = NULL) {
3044746Srica 
3054746Srica 		(void) strcat(path, "/");
3064746Srica 		(void) strcat(path, tok);
3074746Srica 
3084746Srica 		if ((mkdir(path, 0777) != 0) && (errno != EEXIST)) {
3094746Srica 
3104746Srica 			dperror("setupfiles mkdir");
3114746Srica 			dprintf("setupfiles mkdir path %s\n", path);
3124746Srica 			return (errno);
3134746Srica 		}
3144746Srica 
3154746Srica 		dprintf("setupfiles dir %s made or already exists\n", path);
3164746Srica 	}
3174746Srica 
3184746Srica 	return (0);
3194746Srica }  /* mkdirs() */
3204746Srica 
3214746Srica 
3224746Srica /*
3234746Srica  *	copyfile - Copy a file from the base home directory to the current.
3244746Srica  *
3254746Srica  *	Entry	min_home = from home directory.
3264746Srica  *		home = current (to) home directory.
3274746Srica  *		target = file to copy.
3284746Srica  *		flags = from __setupfiles.
3294746Srica  *			REPC, if replace existing file.
3304746Srica  *
3314746Srica  *	Exit	File copied.
3324746Srica  *
3334746Srica  *	Returns	0, if success.
3344746Srica  *		errno, if failure.
3354746Srica  *
3364746Srica  *	Uses	CP, MAXPATHLEN.
3374746Srica  *
3384746Srica  *	Calls	access, execlp, exit, lstat, strcat, strcpy, strlen, unlink,
3394746Srica  *		vfork, waitpid.
3404746Srica  */
3414746Srica 
3424746Srica static int
copyfile(const char * min_home,const char * home,const char * target,int flags)3434746Srica copyfile(const char *min_home, const char *home, const char *target, int flags)
3444746Srica {
3454746Srica 	char	src[MAXPATHLEN];
3464746Srica 	char	dest[MAXPATHLEN];
3474746Srica 	struct stat	buf;
3484746Srica 	pid_t	child;
3494746Srica 
3504746Srica 	/* prepare target */
3514746Srica 
3524746Srica 	if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
3534746Srica 	    sizeof (dest) - 1) {
3544746Srica 		dprintf("setupfiles copy dest %s", dest);
3554746Srica 		dprintf("greater than %d\n", sizeof (dest));
3564746Srica 		errno = ENAMETOOLONG;
3574746Srica 		dperror("setupfiles copy to home");
3584746Srica 		return (errno);
3594746Srica 	}
3604746Srica 
3614746Srica 	if (lstat(dest, &buf) == 0) {
3624746Srica 		/* target exists */
3634746Srica 
3644746Srica 		if (flags & REPC) {
3654746Srica 			/* unlink and replace */
3664746Srica 
3674746Srica 			if (unlink(dest) != 0) {
3684746Srica 
3694746Srica 				dperror("setupfiles copy unlink");
3704746Srica 				dprintf("setupfiles copy unable to unlink %s\n",
3714746Srica 				    dest);
3724746Srica 				return (errno);
3734746Srica 			}
3744746Srica 		} else {
3754746Srica 			/* target exists and is not to be replaced */
3764746Srica 
3774746Srica 			return (0);
3784746Srica 		}
3794746Srica 	} else if (errno != ENOENT) {
3804746Srica 		/* error on target */
3814746Srica 
3824746Srica 		dperror("setupfiles copy");
3834746Srica 		dprintf("setupfiles copy lstat %s\n", dest);
3844746Srica 		return (errno);
3854746Srica 	}
3864746Srica 
3874746Srica 	/* prepare source */
3884746Srica 
3894746Srica 	if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
3904746Srica 	    sizeof (src) - 1) {
3914746Srica 		dprintf("setupfiles copy path %s", src);
3924746Srica 		dprintf("greater than %d\n", sizeof (src));
3934746Srica 		errno = ENAMETOOLONG;
3944746Srica 		dperror("setupfiles copy from home");
3954746Srica 		return (errno);
3964746Srica 	}
3974746Srica 
3984746Srica 	if (access(src, R_OK) != 0) {
3994746Srica 		/* can't access source */
4004746Srica 
4014746Srica 		dperror("setupfiles copy source access");
4024746Srica 		dprintf("setupfiles copy unable to access %s\n", src);
4034746Srica 		return (errno);
4044746Srica 	}
4054746Srica 
4064746Srica 	/* attempt the copy */
4074746Srica 
4084746Srica 	dprintf("setupfiles attempting to copy %s\n", src);
4094746Srica 	dprintf("\tto %s\n", dest);
4104746Srica 
4114746Srica 	if ((child = vfork()) != 0) {	/* parent, wait for child status */
4124746Srica 		int	status;	/* child status */
4134746Srica 
4144746Srica 		(void) waitpid(child, &status, 0);  /* wait for child */
4154746Srica 		dprintf("setupfiles copy child returned %x\n", status);
4164746Srica 	} else {
4174746Srica 		/* execute "cp -p min_home home" */
4184746Srica 
4194746Srica 		if (execlp(CP, CP, "-p", src, dest, 0) != 0) {
4204746Srica 			/* can't execute cp */
4214746Srica 
4224746Srica 			dperror("setupfiles copy exec");
4234746Srica 			dprintf("setupfiles copy couldn't exec \"%s  -p\"\n",
4244746Srica 			    CP);
4254746Srica 			exit(2);
4264746Srica 		}
4274746Srica 	}
4284746Srica 
4294746Srica 	return (0);
4304746Srica }  /* copyfile() */
4314746Srica 
4324746Srica 
4334746Srica /*
4344746Srica  *	linkfile - Make a symlink from the the current directory to the base
4354746Srica  *			home directory.
4364746Srica  *
4374746Srica  *	Entry	min_home = from home directory.
4384746Srica  *		home = current (to) home directory.
4394746Srica  *		target = file to copy.
4404746Srica  *		flags = from __setupfiles.
4414746Srica  *			REPL, if replace existing symlink.
4424746Srica  *
4434746Srica  *	Exit	File symlinked.
4444746Srica  *
4454746Srica  *	Returns	0, if success.
4464746Srica  *		errno, if failure.
4474746Srica  *
4484746Srica  *	Uses	MAXPATHLEN.
4494746Srica  *
4504746Srica  *	Calls	lstat, symlink, strcat, strcpy, strlen, unlink.
4514746Srica  */
4524746Srica 
4534746Srica static int
linkfile(const char * min_home,const char * home,const char * target,int flags)4544746Srica linkfile(const char *min_home, const char *home, const char *target, int flags)
4554746Srica {
4564746Srica 	char	src[MAXPATHLEN];
4574746Srica 	char	dest[MAXPATHLEN];
4584746Srica 	struct stat	buf;
4594746Srica 
4604746Srica 	/* prepare target */
4614746Srica 
4624746Srica 	if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
4634746Srica 	    sizeof (dest) - 1) {
4644746Srica 		dprintf("setupfiles link dest %s", dest);
4654746Srica 		dprintf("greater than %d\n", sizeof (dest));
4664746Srica 		errno = ENAMETOOLONG;
4674746Srica 		dperror("setupfiles link to home");
4684746Srica 		return (errno);
4694746Srica 	}
4704746Srica 
4714746Srica 	if (lstat(dest, &buf) == 0) {
4724746Srica 		/* target exists */
4734746Srica 
4744746Srica 		if (flags & REPL) {
4754746Srica 			/* unlink and replace */
4764746Srica 			if (unlink(dest) != 0) {
4774746Srica 				dperror("setupfiles link unlink");
4784746Srica 				dprintf("setupfiles link unable to unlink %s\n",
4794746Srica 				    dest);
4804746Srica 				return (errno);
4814746Srica 			}
4824746Srica 		} else {
4834746Srica 			/* target exists and is not to be replaced */
4844746Srica 			return (0);
4854746Srica 		}
4864746Srica 	} else if (errno != ENOENT) {
4874746Srica 		/* error on target */
4884746Srica 		dperror("setupfiles link");
4894746Srica 		dprintf("setupfiles link lstat %s\n", dest);
4904746Srica 		return (errno);
4914746Srica 	}
4924746Srica 
4934746Srica 	if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
4944746Srica 	    sizeof (src) - 1) {
4954746Srica 		dprintf("setupfiles link path %s", src);
4964746Srica 		dprintf("greater than %d\n", sizeof (src));
4974746Srica 		errno = ENAMETOOLONG;
4984746Srica 		dperror("setupfiles link from home");
4994746Srica 		return (errno);
5004746Srica 	}
5014746Srica 
5024746Srica 	/* attempt the copy */
5034746Srica 
5044746Srica 	dprintf("setupfiles attempting to link %s\n", dest);
5054746Srica 	dprintf("\tto %s\n", src);
5064746Srica 
5074746Srica 	if (symlink(src, dest) != 0) {
5084746Srica 		dperror("setupfiles link symlink");
5094746Srica 		dprintf("setupfiles link unable to symlink%s\n", "");
5104746Srica 		return (errno);
5114746Srica 	}
5124746Srica 
5134746Srica 	return (0);
5144746Srica }  /* linkfile */
515