xref: /onnv-gate/usr/src/cmd/tsol/updatehome/setupfiles.c (revision 4746:0bc0c48f4304)
1*4746Srica /*
2*4746Srica  * CDDL HEADER START
3*4746Srica  *
4*4746Srica  * The contents of this file are subject to the terms of the
5*4746Srica  * Common Development and Distribution License (the "License").
6*4746Srica  * You may not use this file except in compliance with the License.
7*4746Srica  *
8*4746Srica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4746Srica  * or http://www.opensolaris.org/os/licensing.
10*4746Srica  * See the License for the specific language governing permissions
11*4746Srica  * and limitations under the License.
12*4746Srica  *
13*4746Srica  * When distributing Covered Code, include this CDDL HEADER in each
14*4746Srica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4746Srica  * If applicable, add the following below this CDDL HEADER, with the
16*4746Srica  * fields enclosed by brackets "[]" replaced with your own identifying
17*4746Srica  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4746Srica  *
19*4746Srica  * CDDL HEADER END
20*4746Srica  */
21*4746Srica 
22*4746Srica /*
23*4746Srica  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*4746Srica  * Use is subject to license terms.
25*4746Srica  */
26*4746Srica 
27*4746Srica #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*4746Srica 
29*4746Srica 
30*4746Srica #include <errno.h>
31*4746Srica #include <pwd.h>
32*4746Srica #include <stdio.h>
33*4746Srica #include <stdlib.h>
34*4746Srica #include <string.h>
35*4746Srica #include <unistd.h>
36*4746Srica 
37*4746Srica #include <sys/param.h>
38*4746Srica #include <sys/types.h>
39*4746Srica #include <sys/wait.h>
40*4746Srica 
41*4746Srica #include <tsol/label.h>
42*4746Srica #include <zone.h>
43*4746Srica #include <sys/stat.h>
44*4746Srica 
45*4746Srica #include "setupfiles.h"
46*4746Srica 
47*4746Srica #define	dperror(s) if (flags & DIAG) perror(s)
48*4746Srica #define	dprintf(s, v) if (flags & DBUG) (void) printf(s, v)
49*4746Srica #define	dprintf2(s, v1, v2) if (flags & DBUG) (void) printf(s, v1, v2)
50*4746Srica 
51*4746Srica static int mkdirs(const char *dir, const char *target, int flags);
52*4746Srica static int copyfile(const char *min_home, const char *home, const char *target,
53*4746Srica     int flags);
54*4746Srica static int linkfile(const char *min_home, const char *home, const char *target,
55*4746Srica     int flags);
56*4746Srica 
57*4746Srica 
58*4746Srica /*
59*4746Srica  *	__setupfiles - Process copy and link files directions in min $HOME.
60*4746Srica  *
61*4746Srica  *	Entry	pwd = user's password file entry.
62*4746Srica  *		min_sl = user's minimum SL.
63*4746Srica  *		flags = DBUG, if print debug messages.
64*4746Srica  *			DIAG, if print diagnostics (perrors).
65*4746Srica  *			IGNE, continue rather than abort on failures.
66*4746Srica  *			REPC, if replace existing file.
67*4746Srica  *			REPL, if replace existing symbolic link.
68*4746Srica  *		process is running as user at correct label.
69*4746Srica  *
70*4746Srica  *	Exit	None.
71*4746Srica  *
72*4746Srica  *	Returns	0, if success.
73*4746Srica  *		errno, if failure.
74*4746Srica  *
75*4746Srica  *	Uses	COPY, CP, LINK, MAXPATHLEN.
76*4746Srica  *
77*4746Srica  *	Calls	blequal, copyfile, feof, fgets, fopen, getcmwplabel, stobsl,
78*4746Srica  *		mkdirs, getzoneid, getzonelabelbyid, linkfile, strcat, strcpy,
79*4746Srica  *		strlen.
80*4746Srica  *
81*4746Srica  *	This program assumes the /zone is the autofs mountpoint for
82*4746Srica  *	cross-zone mounts.
83*4746Srica  *
84*4746Srica  *	It also assumes that the user's home directory path is the
85*4746Srica  *	the same in each zone, relative to the zone's root.
86*4746Srica  *
87*4746Srica  *	At this point, the cross-zone automounter only supports home
88*4746Srica  * 	directories starting with /home
89*4746Srica  */
90*4746Srica 
91*4746Srica int
92*4746Srica __setupfiles(const struct passwd *pwd, const bslabel_t *min_sl, int flags)
93*4746Srica {
94*4746Srica 	bslabel_t *plabel;		/* process label */
95*4746Srica 	char	home[MAXPATHLEN];	/* real path to current $HOME */
96*4746Srica 	char	min_home[MAXPATHLEN];	/* real path to min $HOME */
97*4746Srica 	char	cl_file[MAXPATHLEN];	/* real path to .copy/.link_files */
98*4746Srica 	char	file[MAXPATHLEN];	/* file to copy/link */
99*4746Srica 	FILE	*clf;			/* .copy/.link_file stream */
100*4746Srica 	char	zoneroot[MAXPATHLEN];
101*4746Srica 	zoneid_t zoneid;
102*4746Srica 	zoneid_t min_zoneid;
103*4746Srica 
104*4746Srica 	zoneid = getzoneid();
105*4746Srica 	if ((plabel = getzonelabelbyid(zoneid)) == NULL) {
106*4746Srica 
107*4746Srica 		dperror("setupfiles can't get process label");
108*4746Srica 		return (errno);
109*4746Srica 	}
110*4746Srica 
111*4746Srica 	if (blequal(plabel, min_sl)) {
112*4746Srica 		/* at min SL no files to setup */
113*4746Srica 
114*4746Srica 		return (0);
115*4746Srica 	}
116*4746Srica 
117*4746Srica 	/* get current home real path */
118*4746Srica 
119*4746Srica 	(void) strlcpy(home, pwd->pw_dir, MAXPATHLEN);
120*4746Srica 
121*4746Srica 	/* Get zone id from min_sl */
122*4746Srica 
123*4746Srica 	if ((min_zoneid = getzoneidbylabel(min_sl)) == -1) {
124*4746Srica 
125*4746Srica 		dperror("setupfiles can't get zoneid for min sl");
126*4746Srica 		return (errno);
127*4746Srica 	}
128*4746Srica 
129*4746Srica 	/*
130*4746Srica 	 * Since the global zone home directories aren't public
131*4746Srica 	 * information, we don't support copy and link files there.
132*4746Srica 	 */
133*4746Srica 	if (min_zoneid == GLOBAL_ZONEID)
134*4746Srica 		return (0);
135*4746Srica 
136*4746Srica 	/*
137*4746Srica 	 * Get zone root path from zone id
138*4746Srica 	 *
139*4746Srica 	 * Could have used getzonenamebyid() but this assumes that /etc/zones
140*4746Srica 	 * directory is available, which is not true in labeled zones
141*4746Srica 	 */
142*4746Srica 
143*4746Srica 	if (zone_getattr(min_zoneid, ZONE_ATTR_ROOT, zoneroot,
144*4746Srica 	    sizeof (zoneroot)) == -1) {
145*4746Srica 		dperror("setupfiles can't get zone root path for min sl");
146*4746Srica 		return (errno);
147*4746Srica 	}
148*4746Srica 
149*4746Srica 	(void) snprintf(min_home, MAXPATHLEN, "%s%s",
150*4746Srica 	    zoneroot, pwd->pw_dir);
151*4746Srica 
152*4746Srica 	/* process copy files */
153*4746Srica 
154*4746Srica 	if ((strlen(min_home) + strlen(COPY)) > (MAXPATHLEN - 1)) {
155*4746Srica 
156*4746Srica 		dprintf("setupfiles copy path %s", min_home);
157*4746Srica 		dprintf("%s ", COPY);
158*4746Srica 		dprintf("greater than %d\n", MAXPATHLEN);
159*4746Srica 		errno = ENAMETOOLONG;
160*4746Srica 		dperror("setupfiles copy path");
161*4746Srica 		return (errno);
162*4746Srica 	}
163*4746Srica 
164*4746Srica 	(void) strcpy(cl_file, min_home);
165*4746Srica 	(void) strcat(cl_file, COPY);
166*4746Srica 
167*4746Srica 	if ((clf = fopen(cl_file, "r")) != NULL) {
168*4746Srica 
169*4746Srica 		while (fgets(file, MAXPATHLEN, clf) != NULL) {
170*4746Srica 
171*4746Srica 			if (!feof(clf))		/* remove trailing \n */
172*4746Srica 				file[strlen(file) - 1] = '\0';
173*4746Srica 
174*4746Srica 			dprintf("copy file %s requested\n", file);
175*4746Srica 
176*4746Srica 			/* make any needed subdirectories */
177*4746Srica 
178*4746Srica 			if (mkdirs(home, file, flags) != 0) {
179*4746Srica 
180*4746Srica 				if ((flags & IGNE) == 0)
181*4746Srica 					return (errno);
182*4746Srica 				else
183*4746Srica 					continue;
184*4746Srica 			}
185*4746Srica 
186*4746Srica 			/* copy the file */
187*4746Srica 
188*4746Srica 			if (copyfile(min_home, home, file, flags) != 0) {
189*4746Srica 
190*4746Srica 				if ((flags & IGNE) == 0)
191*4746Srica 					return (errno);
192*4746Srica 				else
193*4746Srica 					continue;
194*4746Srica 
195*4746Srica 			}
196*4746Srica 
197*4746Srica 		}  /* while (fgets( ... ) != NULL) */
198*4746Srica 	} else {
199*4746Srica 		if (errno != ENOENT)
200*4746Srica 			dperror("setupfiles copy file open");
201*4746Srica 		dprintf("setupfiles no copyfile %s\n", cl_file);
202*4746Srica 	}  /* process copy files */
203*4746Srica 
204*4746Srica 
205*4746Srica 	/* process link files */
206*4746Srica 
207*4746Srica 	if ((strlen(min_home) + strlen(LINK)) > (MAXPATHLEN - 1)) {
208*4746Srica 
209*4746Srica 		dprintf("setupfiles link path %s", min_home);
210*4746Srica 		dprintf("%s ", LINK);
211*4746Srica 		dprintf("greater than %d\n", MAXPATHLEN);
212*4746Srica 		errno = ENAMETOOLONG;
213*4746Srica 		dperror("setupfiles link path");
214*4746Srica 		return (errno);
215*4746Srica 	}
216*4746Srica 
217*4746Srica 	(void) strcpy(cl_file, min_home);
218*4746Srica 	(void) strcat(cl_file, LINK);
219*4746Srica 
220*4746Srica 	if ((clf = fopen(cl_file, "r")) != NULL) {
221*4746Srica 
222*4746Srica 		while (fgets(file, MAXPATHLEN, clf) != NULL) {
223*4746Srica 
224*4746Srica 			if (!feof(clf))		/* remove trailing \n */
225*4746Srica 				file[strlen(file) - 1] = '\0';
226*4746Srica 
227*4746Srica 			dprintf("link file %s requested\n", file);
228*4746Srica 
229*4746Srica 			/* make any needed subdirectories */
230*4746Srica 
231*4746Srica 			if (mkdirs(home, file, flags) != 0) {
232*4746Srica 
233*4746Srica 				if ((flags & IGNE) == 0)
234*4746Srica 					return (errno);
235*4746Srica 				else
236*4746Srica 					continue;
237*4746Srica 			}
238*4746Srica 
239*4746Srica 			/* link the file */
240*4746Srica 
241*4746Srica 			if (linkfile(min_home, home, file, flags) != 0) {
242*4746Srica 
243*4746Srica 				if ((flags & IGNE) == 0)
244*4746Srica 					return (errno);
245*4746Srica 				else
246*4746Srica 					continue;
247*4746Srica 			}
248*4746Srica 
249*4746Srica 		}  /* while (fgets ... ) != NULL) */
250*4746Srica 	} else {
251*4746Srica 		if (errno != ENOENT)
252*4746Srica 			dperror("setupfiles link file open");
253*4746Srica 		dprintf("setupfiles no linkfile %s\n", cl_file);
254*4746Srica 	}  /* process link files */
255*4746Srica 
256*4746Srica 	return (0);
257*4746Srica }  /* setupfiles() */
258*4746Srica 
259*4746Srica 
260*4746Srica /*
261*4746Srica  *	mkdirs - Make any needed subdirectories in target's path.
262*4746Srica  *
263*4746Srica  *	Entry	home = base directory.
264*4746Srica  *		file = file to create with intermediate subdirectories.
265*4746Srica  *		flags = from __setupfiles -- for dprintf and dperror.
266*4746Srica  *
267*4746Srica  *	Exit	Needed subdirectories made.
268*4746Srica  *
269*4746Srica  *	Returns	0, if success.
270*4746Srica  *		errno, if failure.
271*4746Srica  *
272*4746Srica  *	Uses	MAXPATHLEN.
273*4746Srica  *
274*4746Srica  *	Calls	mkdir, strcat, strcpy, strlen, strtok.
275*4746Srica  */
276*4746Srica 
277*4746Srica static int
278*4746Srica mkdirs(const char *home, const char *file, int flags)
279*4746Srica {
280*4746Srica 	char	path[MAXPATHLEN];
281*4746Srica 	char	dir[MAXPATHLEN];
282*4746Srica 	char	*tok;
283*4746Srica 
284*4746Srica 	if ((strlen(home) + strlen(file)) > (MAXPATHLEN - 2)) {
285*4746Srica 
286*4746Srica 		dprintf("setupfiles mkdirs path %s", home);
287*4746Srica 		dprintf("/%s ", file);
288*4746Srica 		dprintf("greater than %d\n", MAXPATHLEN);
289*4746Srica 		errno = ENAMETOOLONG;
290*4746Srica 		dperror("setupfiles mkdirs");
291*4746Srica 		return (errno);
292*4746Srica 	}
293*4746Srica 
294*4746Srica 	(void) strcpy(dir, file);
295*4746Srica 
296*4746Srica 	if ((tok = strrchr(dir, '/')) == NULL) {
297*4746Srica 
298*4746Srica 		dprintf("setupfiles no dirs to make in %s\n", dir);
299*4746Srica 		return (0);
300*4746Srica 	}
301*4746Srica 
302*4746Srica 	*tok = '\000';		/* drop last component, it's the target */
303*4746Srica 
304*4746Srica 	(void) strcpy(path, home);
305*4746Srica 
306*4746Srica 	for (tok = dir; tok = strtok(tok, "/"); tok = NULL) {
307*4746Srica 
308*4746Srica 		(void) strcat(path, "/");
309*4746Srica 		(void) strcat(path, tok);
310*4746Srica 
311*4746Srica 		if ((mkdir(path, 0777) != 0) && (errno != EEXIST)) {
312*4746Srica 
313*4746Srica 			dperror("setupfiles mkdir");
314*4746Srica 			dprintf("setupfiles mkdir path %s\n", path);
315*4746Srica 			return (errno);
316*4746Srica 		}
317*4746Srica 
318*4746Srica 		dprintf("setupfiles dir %s made or already exists\n", path);
319*4746Srica 	}
320*4746Srica 
321*4746Srica 	return (0);
322*4746Srica }  /* mkdirs() */
323*4746Srica 
324*4746Srica 
325*4746Srica /*
326*4746Srica  *	copyfile - Copy a file from the base home directory to the current.
327*4746Srica  *
328*4746Srica  *	Entry	min_home = from home directory.
329*4746Srica  *		home = current (to) home directory.
330*4746Srica  *		target = file to copy.
331*4746Srica  *		flags = from __setupfiles.
332*4746Srica  *			REPC, if replace existing file.
333*4746Srica  *
334*4746Srica  *	Exit	File copied.
335*4746Srica  *
336*4746Srica  *	Returns	0, if success.
337*4746Srica  *		errno, if failure.
338*4746Srica  *
339*4746Srica  *	Uses	CP, MAXPATHLEN.
340*4746Srica  *
341*4746Srica  *	Calls	access, execlp, exit, lstat, strcat, strcpy, strlen, unlink,
342*4746Srica  *		vfork, waitpid.
343*4746Srica  */
344*4746Srica 
345*4746Srica static int
346*4746Srica copyfile(const char *min_home, const char *home, const char *target, int flags)
347*4746Srica {
348*4746Srica 	char	src[MAXPATHLEN];
349*4746Srica 	char	dest[MAXPATHLEN];
350*4746Srica 	struct stat	buf;
351*4746Srica 	pid_t	child;
352*4746Srica 
353*4746Srica 	/* prepare target */
354*4746Srica 
355*4746Srica 	if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
356*4746Srica 	    sizeof (dest) - 1) {
357*4746Srica 		dprintf("setupfiles copy dest %s", dest);
358*4746Srica 		dprintf("greater than %d\n", sizeof (dest));
359*4746Srica 		errno = ENAMETOOLONG;
360*4746Srica 		dperror("setupfiles copy to home");
361*4746Srica 		return (errno);
362*4746Srica 	}
363*4746Srica 
364*4746Srica 	if (lstat(dest, &buf) == 0) {
365*4746Srica 		/* target exists */
366*4746Srica 
367*4746Srica 		if (flags & REPC) {
368*4746Srica 			/* unlink and replace */
369*4746Srica 
370*4746Srica 			if (unlink(dest) != 0) {
371*4746Srica 
372*4746Srica 				dperror("setupfiles copy unlink");
373*4746Srica 				dprintf("setupfiles copy unable to unlink %s\n",
374*4746Srica 				    dest);
375*4746Srica 				return (errno);
376*4746Srica 			}
377*4746Srica 		} else {
378*4746Srica 			/* target exists and is not to be replaced */
379*4746Srica 
380*4746Srica 			return (0);
381*4746Srica 		}
382*4746Srica 	} else if (errno != ENOENT) {
383*4746Srica 		/* error on target */
384*4746Srica 
385*4746Srica 		dperror("setupfiles copy");
386*4746Srica 		dprintf("setupfiles copy lstat %s\n", dest);
387*4746Srica 		return (errno);
388*4746Srica 	}
389*4746Srica 
390*4746Srica 	/* prepare source */
391*4746Srica 
392*4746Srica 	if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
393*4746Srica 	    sizeof (src) - 1) {
394*4746Srica 		dprintf("setupfiles copy path %s", src);
395*4746Srica 		dprintf("greater than %d\n", sizeof (src));
396*4746Srica 		errno = ENAMETOOLONG;
397*4746Srica 		dperror("setupfiles copy from home");
398*4746Srica 		return (errno);
399*4746Srica 	}
400*4746Srica 
401*4746Srica 	if (access(src, R_OK) != 0) {
402*4746Srica 		/* can't access source */
403*4746Srica 
404*4746Srica 		dperror("setupfiles copy source access");
405*4746Srica 		dprintf("setupfiles copy unable to access %s\n", src);
406*4746Srica 		return (errno);
407*4746Srica 	}
408*4746Srica 
409*4746Srica 	/* attempt the copy */
410*4746Srica 
411*4746Srica 	dprintf("setupfiles attempting to copy %s\n", src);
412*4746Srica 	dprintf("\tto %s\n", dest);
413*4746Srica 
414*4746Srica 	if ((child = vfork()) != 0) {	/* parent, wait for child status */
415*4746Srica 		int	status;	/* child status */
416*4746Srica 
417*4746Srica 		(void) waitpid(child, &status, 0);  /* wait for child */
418*4746Srica 		dprintf("setupfiles copy child returned %x\n", status);
419*4746Srica 	} else {
420*4746Srica 		/* execute "cp -p min_home home" */
421*4746Srica 
422*4746Srica 		if (execlp(CP, CP, "-p", src, dest, 0) != 0) {
423*4746Srica 			/* can't execute cp */
424*4746Srica 
425*4746Srica 			dperror("setupfiles copy exec");
426*4746Srica 			dprintf("setupfiles copy couldn't exec \"%s  -p\"\n",
427*4746Srica 			    CP);
428*4746Srica 			exit(2);
429*4746Srica 		}
430*4746Srica 	}
431*4746Srica 
432*4746Srica 	return (0);
433*4746Srica }  /* copyfile() */
434*4746Srica 
435*4746Srica 
436*4746Srica /*
437*4746Srica  *	linkfile - Make a symlink from the the current directory to the base
438*4746Srica  *			home directory.
439*4746Srica  *
440*4746Srica  *	Entry	min_home = from home directory.
441*4746Srica  *		home = current (to) home directory.
442*4746Srica  *		target = file to copy.
443*4746Srica  *		flags = from __setupfiles.
444*4746Srica  *			REPL, if replace existing symlink.
445*4746Srica  *
446*4746Srica  *	Exit	File symlinked.
447*4746Srica  *
448*4746Srica  *	Returns	0, if success.
449*4746Srica  *		errno, if failure.
450*4746Srica  *
451*4746Srica  *	Uses	MAXPATHLEN.
452*4746Srica  *
453*4746Srica  *	Calls	lstat, symlink, strcat, strcpy, strlen, unlink.
454*4746Srica  */
455*4746Srica 
456*4746Srica static int
457*4746Srica linkfile(const char *min_home, const char *home, const char *target, int flags)
458*4746Srica {
459*4746Srica 	char	src[MAXPATHLEN];
460*4746Srica 	char	dest[MAXPATHLEN];
461*4746Srica 	struct stat	buf;
462*4746Srica 
463*4746Srica 	/* prepare target */
464*4746Srica 
465*4746Srica 	if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
466*4746Srica 	    sizeof (dest) - 1) {
467*4746Srica 		dprintf("setupfiles link dest %s", dest);
468*4746Srica 		dprintf("greater than %d\n", sizeof (dest));
469*4746Srica 		errno = ENAMETOOLONG;
470*4746Srica 		dperror("setupfiles link to home");
471*4746Srica 		return (errno);
472*4746Srica 	}
473*4746Srica 
474*4746Srica 	if (lstat(dest, &buf) == 0) {
475*4746Srica 		/* target exists */
476*4746Srica 
477*4746Srica 		if (flags & REPL) {
478*4746Srica 			/* unlink and replace */
479*4746Srica 			if (unlink(dest) != 0) {
480*4746Srica 				dperror("setupfiles link unlink");
481*4746Srica 				dprintf("setupfiles link unable to unlink %s\n",
482*4746Srica 				    dest);
483*4746Srica 				return (errno);
484*4746Srica 			}
485*4746Srica 		} else {
486*4746Srica 			/* target exists and is not to be replaced */
487*4746Srica 			return (0);
488*4746Srica 		}
489*4746Srica 	} else if (errno != ENOENT) {
490*4746Srica 		/* error on target */
491*4746Srica 		dperror("setupfiles link");
492*4746Srica 		dprintf("setupfiles link lstat %s\n", dest);
493*4746Srica 		return (errno);
494*4746Srica 	}
495*4746Srica 
496*4746Srica 	if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
497*4746Srica 	    sizeof (src) - 1) {
498*4746Srica 		dprintf("setupfiles link path %s", src);
499*4746Srica 		dprintf("greater than %d\n", sizeof (src));
500*4746Srica 		errno = ENAMETOOLONG;
501*4746Srica 		dperror("setupfiles link from home");
502*4746Srica 		return (errno);
503*4746Srica 	}
504*4746Srica 
505*4746Srica 	/* attempt the copy */
506*4746Srica 
507*4746Srica 	dprintf("setupfiles attempting to link %s\n", dest);
508*4746Srica 	dprintf("\tto %s\n", src);
509*4746Srica 
510*4746Srica 	if (symlink(src, dest) != 0) {
511*4746Srica 		dperror("setupfiles link symlink");
512*4746Srica 		dprintf("setupfiles link unable to symlink%s\n", "");
513*4746Srica 		return (errno);
514*4746Srica 	}
515*4746Srica 
516*4746Srica 	return (0);
517*4746Srica }  /* linkfile */
518