int create_homedir(TALLOC_CTX *mem_ctx, const char *skeldir, const char *homedir, const char *username, uid_t uid, gid_t gid, mode_t default_umask) { int ret; selinux_file_context(homedir); ret = mkdir(homedir, 0); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot create user's home directory: [%d][%s].\n", ret, strerror(ret))); goto done; } ret = chown(homedir, uid, gid); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot chown user's home directory: [%d][%s].\n", ret, strerror(ret))); goto done; } ret = chmod(homedir, 0777 & ~default_umask); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot chmod user's home directory: [%d][%s].\n", ret, strerror(ret))); goto done; } reset_selinux_file_context(); ret = copy_tree(skeldir, homedir, uid, gid); if (ret != EOK) { DEBUG(1, ("Cannot populate user's home directory: [%d][%s].\n", ret, strerror(ret))); goto done; } done: reset_selinux_file_context(); return ret; }
int create_homedir(const char *skeldir, const char *homedir, uid_t uid, gid_t gid, mode_t default_umask) { int ret; selinux_file_context(homedir); ret = copy_tree(skeldir, homedir, 0777 & ~default_umask, uid, gid); if (ret != EOK) { DEBUG(1, ("Cannot populate user's home directory: [%d][%s].\n", ret, strerror(ret))); goto done; } done: reset_selinux_file_context(); return ret; }
/* * copy_tree - copy files in a directory tree * * copy_tree() walks a directory tree and copies ordinary files * as it goes. * * When reset_selinux is enabled, extended attributes (and thus * SELinux attributes) are not copied. * * old_uid and new_uid are used to set the ownership of the copied * files. Unless old_uid is set to -1, only the files owned by * old_uid have their ownership changed to new_uid. In addition, if * new_uid is set to -1, no ownership will be changed. * * The same logic applies for the group-ownership and * old_gid/new_gid. */ int copy_tree (const char *src_root, const char *dst_root, bool copy_root, bool reset_selinux, uid_t old_uid, uid_t new_uid, gid_t old_gid, gid_t new_gid) { int err = 0; bool set_orig = false; struct DIRECT *ent; DIR *dir; if (copy_root) { struct stat sb; if (access (dst_root, F_OK) == 0) { return -1; } if (LSTAT (src_root, &sb) == -1) { return -1; } if (!S_ISDIR (sb.st_mode)) { fprintf (stderr, "%s: %s is not a directory", Prog, src_root); return -1; } return copy_entry (src_root, dst_root, reset_selinux, old_uid, new_uid, old_gid, new_gid); } /* * Make certain both directories exist. This routine is called * after the home directory is created, or recursively after the * target is created. It assumes the target directory exists. */ if ( (access (src_root, F_OK) != 0) || (access (dst_root, F_OK) != 0)) { return -1; } /* * Open the source directory and read each entry. Every file * entry in the directory is copied with the UID and GID set * to the provided values. As an added security feature only * regular files (and directories ...) are copied, and no file * is made set-ID. */ dir = opendir (src_root); if (NULL == dir) { return -1; } if (src_orig == NULL) { src_orig = src_root; dst_orig = dst_root; set_orig = true; } while ((0 == err) && (ent = readdir (dir)) != NULL) { /* * Skip the "." and ".." entries */ if ((strcmp (ent->d_name, ".") != 0) && (strcmp (ent->d_name, "..") != 0)) { char *src_name; char *dst_name; size_t src_len = strlen (ent->d_name) + 2; size_t dst_len = strlen (ent->d_name) + 2; src_len += strlen (src_root); dst_len += strlen (dst_root); src_name = (char *) malloc (src_len); dst_name = (char *) malloc (dst_len); if ((NULL == src_name) || (NULL == dst_name)) { err = -1; } else { /* * Build the filename for both the source and * the destination files. */ (void) snprintf (src_name, src_len, "%s/%s", src_root, ent->d_name); (void) snprintf (dst_name, dst_len, "%s/%s", dst_root, ent->d_name); err = copy_entry (src_name, dst_name, reset_selinux, old_uid, new_uid, old_gid, new_gid); } if (NULL != src_name) { free (src_name); } if (NULL != dst_name) { free (dst_name); } } } (void) closedir (dir); if (set_orig) { src_orig = NULL; dst_orig = NULL; /* FIXME: clean links * Since there can be hardlinks elsewhere on the device, * we cannot check that all the hardlinks were found: assert (NULL == links); */ } #ifdef WITH_SELINUX /* Reset SELinux to create files with default contexts. * Note that the context is only reset on exit of copy_tree (it is * assumed that the program would quit without needing a restored * context if copy_tree failed previously), and that copy_tree can * be called recursively (hence the context is set on the * sub-functions of copy_entry). */ if (reset_selinux_file_context () != 0) { err = -1; } #endif /* WITH_SELINUX */ return err; }
/* The reason for not putting this into create_homedir * is better granularity when it comes to reporting error * messages and tracebacks in pysss */ int create_mail_spool(TALLOC_CTX *mem_ctx, const char *username, const char *maildir, uid_t uid, gid_t gid) { char *spool_file = NULL; int fd = -1; int ret; spool_file = talloc_asprintf(mem_ctx, "%s/%s", maildir, username); if (spool_file == NULL) { ret = ENOMEM; goto fail; } selinux_file_context(spool_file); fd = open(spool_file, O_CREAT | O_WRONLY | O_EXCL, 0); if (fd < 0) { ret = errno; DEBUG(1, ("Cannot open() the spool file: [%d][%s]\n", ret, strerror(ret))); goto fail; } ret = fchmod(fd, 0600); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot fchmod() the spool file: [%d][%s]\n", ret, strerror(ret))); goto fail; } ret = fchown(fd, uid, gid); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot fchown() the spool file: [%d][%s]\n", ret, strerror(ret))); goto fail; } ret = fsync(fd); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot fsync() the spool file: [%d][%s]\n", ret, strerror(ret))); } fail: if (fd >= 0) { ret = close(fd); if (ret != 0) { ret = errno; DEBUG(1, ("Cannot close() the spool file: [%d][%s]\n", ret, strerror(ret))); } } reset_selinux_file_context(); talloc_free(spool_file); return ret; }