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