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