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