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