#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <tsol/label.h>
#include <zone.h>
#include <sys/stat.h>
#include "setupfiles.h"
#define dperror(s) if (flags & DIAG) perror(s)
#define dprintf(s, v) if (flags & DBUG) (void) printf(s, v)
#define dprintf2(s, v1, v2) if (flags & DBUG) (void) printf(s, v1, v2)
static int mkdirs(const char *dir, const char *target, int flags);
static int copyfile(const char *min_home, const char *home, const char *target,
int flags);
static int linkfile(const char *min_home, const char *home, const char *target,
int flags);
int
__setupfiles(const struct passwd *pwd, const m_label_t *min_sl, int flags)
{
m_label_t *plabel;
char home[MAXPATHLEN];
char min_home[MAXPATHLEN];
char cl_file[MAXPATHLEN];
char file[MAXPATHLEN];
FILE *clf;
char zoneroot[MAXPATHLEN];
zoneid_t zoneid;
zoneid_t min_zoneid;
zoneid = getzoneid();
if ((plabel = getzonelabelbyid(zoneid)) == NULL) {
dperror("setupfiles can't get process label");
return (errno);
}
if (blequal(plabel, min_sl)) {
return (0);
}
(void) strlcpy(home, pwd->pw_dir, MAXPATHLEN);
if ((min_zoneid = getzoneidbylabel(min_sl)) == -1) {
dperror("setupfiles can't get zoneid for min sl");
return (errno);
}
if (min_zoneid == GLOBAL_ZONEID)
return (0);
if (zone_getattr(min_zoneid, ZONE_ATTR_ROOT, zoneroot,
sizeof (zoneroot)) == -1) {
dperror("setupfiles can't get zone root path for min sl");
return (errno);
}
(void) snprintf(min_home, MAXPATHLEN, "%s%s",
zoneroot, pwd->pw_dir);
if ((strlen(min_home) + strlen(COPY)) > (MAXPATHLEN - 1)) {
dprintf("setupfiles copy path %s", min_home);
dprintf("%s ", COPY);
dprintf("greater than %d\n", MAXPATHLEN);
errno = ENAMETOOLONG;
dperror("setupfiles copy path");
return (errno);
}
(void) strcpy(cl_file, min_home);
(void) strcat(cl_file, COPY);
if ((clf = fopen(cl_file, "r")) != NULL) {
while (fgets(file, MAXPATHLEN, clf) != NULL) {
if (!feof(clf))
file[strlen(file) - 1] = '\0';
dprintf("copy file %s requested\n", file);
if (mkdirs(home, file, flags) != 0) {
if ((flags & IGNE) == 0)
return (errno);
else
continue;
}
if (copyfile(min_home, home, file, flags) != 0) {
if ((flags & IGNE) == 0)
return (errno);
else
continue;
}
}
} else {
if (errno != ENOENT)
dperror("setupfiles copy file open");
dprintf("setupfiles no copyfile %s\n", cl_file);
}
if ((strlen(min_home) + strlen(LINK)) > (MAXPATHLEN - 1)) {
dprintf("setupfiles link path %s", min_home);
dprintf("%s ", LINK);
dprintf("greater than %d\n", MAXPATHLEN);
errno = ENAMETOOLONG;
dperror("setupfiles link path");
return (errno);
}
(void) strcpy(cl_file, min_home);
(void) strcat(cl_file, LINK);
if ((clf = fopen(cl_file, "r")) != NULL) {
while (fgets(file, MAXPATHLEN, clf) != NULL) {
if (!feof(clf))
file[strlen(file) - 1] = '\0';
dprintf("link file %s requested\n", file);
if (mkdirs(home, file, flags) != 0) {
if ((flags & IGNE) == 0)
return (errno);
else
continue;
}
if (linkfile(min_home, home, file, flags) != 0) {
if ((flags & IGNE) == 0)
return (errno);
else
continue;
}
}
} else {
if (errno != ENOENT)
dperror("setupfiles link file open");
dprintf("setupfiles no linkfile %s\n", cl_file);
}
return (0);
}
static int
mkdirs(const char *home, const char *file, int flags)
{
char path[MAXPATHLEN];
char dir[MAXPATHLEN];
char *tok;
if ((strlen(home) + strlen(file)) > (MAXPATHLEN - 2)) {
dprintf("setupfiles mkdirs path %s", home);
dprintf("/%s ", file);
dprintf("greater than %d\n", MAXPATHLEN);
errno = ENAMETOOLONG;
dperror("setupfiles mkdirs");
return (errno);
}
(void) strcpy(dir, file);
if ((tok = strrchr(dir, '/')) == NULL) {
dprintf("setupfiles no dirs to make in %s\n", dir);
return (0);
}
*tok = '\000';
(void) strcpy(path, home);
for (tok = dir; tok = strtok(tok, "/"); tok = NULL) {
(void) strcat(path, "/");
(void) strcat(path, tok);
if ((mkdir(path, 0777) != 0) && (errno != EEXIST)) {
dperror("setupfiles mkdir");
dprintf("setupfiles mkdir path %s\n", path);
return (errno);
}
dprintf("setupfiles dir %s made or already exists\n", path);
}
return (0);
}
static int
copyfile(const char *min_home, const char *home, const char *target, int flags)
{
char src[MAXPATHLEN];
char dest[MAXPATHLEN];
struct stat buf;
pid_t child;
if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
sizeof (dest) - 1) {
dprintf("setupfiles copy dest %s", dest);
dprintf("greater than %d\n", sizeof (dest));
errno = ENAMETOOLONG;
dperror("setupfiles copy to home");
return (errno);
}
if (lstat(dest, &buf) == 0) {
if (flags & REPC) {
if (unlink(dest) != 0) {
dperror("setupfiles copy unlink");
dprintf("setupfiles copy unable to unlink %s\n",
dest);
return (errno);
}
} else {
return (0);
}
} else if (errno != ENOENT) {
dperror("setupfiles copy");
dprintf("setupfiles copy lstat %s\n", dest);
return (errno);
}
if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
sizeof (src) - 1) {
dprintf("setupfiles copy path %s", src);
dprintf("greater than %d\n", sizeof (src));
errno = ENAMETOOLONG;
dperror("setupfiles copy from home");
return (errno);
}
if (access(src, R_OK) != 0) {
dperror("setupfiles copy source access");
dprintf("setupfiles copy unable to access %s\n", src);
return (errno);
}
dprintf("setupfiles attempting to copy %s\n", src);
dprintf("\tto %s\n", dest);
if ((child = vfork()) != 0) {
int status;
(void) waitpid(child, &status, 0);
dprintf("setupfiles copy child returned %x\n", status);
} else {
if (execlp(CP, CP, "-p", src, dest, 0) != 0) {
dperror("setupfiles copy exec");
dprintf("setupfiles copy couldn't exec \"%s -p\"\n",
CP);
exit(2);
}
}
return (0);
}
static int
linkfile(const char *min_home, const char *home, const char *target, int flags)
{
char src[MAXPATHLEN];
char dest[MAXPATHLEN];
struct stat buf;
if (snprintf(dest, sizeof (dest), "%s/%s", home, target) >
sizeof (dest) - 1) {
dprintf("setupfiles link dest %s", dest);
dprintf("greater than %d\n", sizeof (dest));
errno = ENAMETOOLONG;
dperror("setupfiles link to home");
return (errno);
}
if (lstat(dest, &buf) == 0) {
if (flags & REPL) {
if (unlink(dest) != 0) {
dperror("setupfiles link unlink");
dprintf("setupfiles link unable to unlink %s\n",
dest);
return (errno);
}
} else {
return (0);
}
} else if (errno != ENOENT) {
dperror("setupfiles link");
dprintf("setupfiles link lstat %s\n", dest);
return (errno);
}
if (snprintf(src, sizeof (src), "%s/%s", min_home, target) >
sizeof (src) - 1) {
dprintf("setupfiles link path %s", src);
dprintf("greater than %d\n", sizeof (src));
errno = ENAMETOOLONG;
dperror("setupfiles link from home");
return (errno);
}
dprintf("setupfiles attempting to link %s\n", dest);
dprintf("\tto %s\n", src);
if (symlink(src, dest) != 0) {
dperror("setupfiles link symlink");
dprintf("setupfiles link unable to symlink%s\n", "");
return (errno);
}
return (0);
}