diff options
author | tonnerre <tonnerre@pkgsrc.org> | 2009-02-15 20:16:08 +0000 |
---|---|---|
committer | tonnerre <tonnerre@pkgsrc.org> | 2009-02-15 20:16:08 +0000 |
commit | 659fa42813aa02523db112c7a903af8624c3bd3c (patch) | |
tree | 74e88cf5c7d45dc73de0a67e3d77f9fe598d8574 /security | |
parent | e55ecfc8e346257c29efab8bbb076037b8c71896 (diff) | |
download | pkgsrc-659fa42813aa02523db112c7a903af8624c3bd3c.tar.gz |
Initial import of the mkhomedir PAM module.
The pam_mkhomedir module provides the means for automatic creation of
home directories upon login, if necessary. Key Benefits are:
* Uses the Pluggable Authentication Module API defined in OSF DCE RFC 86.0.
* Removes the need to pre-create user home directories.
The software is distributed under the terms of the 2.5-clause BSD license.
Diffstat (limited to 'security')
-rw-r--r-- | security/pam-mkhomedir/files/pam_mkhomedir.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/security/pam-mkhomedir/files/pam_mkhomedir.c b/security/pam-mkhomedir/files/pam_mkhomedir.c new file mode 100644 index 00000000000..441fe7c588e --- /dev/null +++ b/security/pam-mkhomedir/files/pam_mkhomedir.c @@ -0,0 +1,297 @@ +/** + * (c) 2009, Tonnerre Lombard <tonnerre@NetBSD.org>, + * The NetBSD Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the The NetBSD Foundation nor the name of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $NetBSD: pam_mkhomedir.c,v 1.1.1.1 2009/02/15 20:16:08 tonnerre Exp $ + */ + +#include <sys/types.h> +#include <security/pam_appl.h> +#include <security/pam_modules.h> + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <pwd.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <dirent.h> +#include <syslog.h> + +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> + +static int +pam_mkhd_copy(pam_handle_t *pamh, const struct passwd *pwent, + const char *from, const char *to) +{ + char *newfrom, *newto; + struct dirent *dentry; + struct stat di; + ssize_t len; + DIR *dirp; + int ffd, tfd, ret; + + if (lstat(from, &di)) + { + pam_error(pamh, "Unable to stat %s: %s", from, strerror(errno)); + return PAM_PERM_DENIED; + } + + if (S_ISDIR(di.st_mode)) + { + if (mkdir(to, di.st_mode & 07777)) + { + pam_error(pamh, "Creating directory %s failed: %s", + to, strerror(errno)); + return PAM_PERM_DENIED; + } + + if (chown(to, pwent->pw_uid, pwent->pw_gid)) + { + pam_error(pamh, "Setting ownership of %s failed: %s", + to, strerror(errno)); + return PAM_PERM_DENIED; + } + + dirp = opendir(from); + if (!dirp) + { + pam_error(pamh, "Unable to open %s: %s", from, + strerror(errno)); + return PAM_PERM_DENIED; + } + + while ((dentry = readdir(dirp))) + { + if (dentry->d_name[0] == '.' && + (dentry->d_name[1] == '\0' || + (dentry->d_name[1] == '.' && + dentry->d_name[2] == '\0'))) + continue; + + newfrom = malloc(strlen(from) + strlen(dentry->d_name) + + 2); + if (!newfrom) + { + closedir(dirp); + return PAM_PERM_DENIED; + } + + memset(newfrom, 0, strlen(from) + strlen(dentry->d_name) + 2); + strlcpy(newfrom, from, strlen(from) + 1); + newfrom[strlen(from)] = '/'; + strlcpy(newfrom + strlen(from) + 1, dentry->d_name, strlen(dentry->d_name) + 1); + newfrom[strlen(from) + strlen(dentry->d_name) + 2] = + '\0'; + + newto = malloc(strlen(to) + strlen(dentry->d_name) + 2); + if (!newto) + { + free(newfrom); + closedir(dirp); + return PAM_PERM_DENIED; + } + + strlcpy(newto, to, strlen(to) + 1); + newto[strlen(to)] = '/'; + strlcpy(newto + strlen(to) + 1, dentry->d_name, strlen(dentry->d_name) + 1); + newto[strlen(to) + strlen(dentry->d_name) + 2] = '\0'; + + ret = pam_mkhd_copy(pamh, pwent, newfrom, newto); + + free(newto); + free(newfrom); + + if (ret != PAM_SUCCESS) + { + closedir(dirp); + return ret; + } + } + + closedir(dirp); + } + else if (S_ISLNK(di.st_mode)) + { + newto = malloc(di.st_size) + 1; + memset(newto, 0, di.st_size + 1); + + if (readlink(from, newto, di.st_size + 1) < 0) + { + pam_error(pamh, "Readlink on %s failed: %s", from, + strerror(errno)); + free(newto); + return PAM_PERM_DENIED; + } + + if (symlink(newto, to)) + { + pam_error(pamh, "Creating symlink %s failed: %s", to, + strerror(errno)); + free(newto); + return PAM_PERM_DENIED; + } + + free(newto); + + if (lchmod(to, di.st_mode & 07777)) + { + pam_error(pamh, "Changing permissions of symlink %s failed: %s", + to, strerror(errno)); + return PAM_PERM_DENIED; + } + + if (lchown(to, pwent->pw_uid, pwent->pw_gid)) + { + pam_error(pamh, "Changing ownership of symlink %s failed: %s", + to, strerror(errno)); + return PAM_PERM_DENIED; + } + } + else if (S_ISREG(di.st_mode)) + { + ffd = open(from, O_RDONLY, 0); + if (ffd == -1) + { + pam_error(pamh, "Opening %s for reading failed: %s", + from, strerror(errno)); + return PAM_PERM_DENIED; + } + + tfd = open(to, O_WRONLY | O_CREAT | O_TRUNC, di.st_mode & 07777); + if (ffd == -1) + { + pam_error(pamh, "Opening %s for writing failed: %s", + to, strerror(errno)); + close(ffd); + return PAM_PERM_DENIED; + } + + newto = malloc(65536); + if (!newto) + { + pam_error(pamh, "Unable to allocate buffer: %s", + strerror(errno)); + close(tfd); + close(ffd); + return PAM_PERM_DENIED; + } + + while ((len = read(ffd, newto, 65546)) > 0) + { + if (write(tfd, newto, len) == -1) + { + pam_error(pamh, "Unable to write to %s: %s", + to, strerror(errno)); + free(newto); + close(tfd); + close(ffd); + return PAM_PERM_DENIED; + } + } + + free(newto); + if (len == -1) + { + pam_error(pamh, "Unable to read from %s: %s", from, + strerror(errno)); + close(tfd); + close(ffd); + return PAM_PERM_DENIED; + } + + if (close(tfd)) + { + pam_error(pamh, "Unable to close %s: %s", to, + strerror(errno)); + close(ffd); + return PAM_PERM_DENIED; + } + + if (close(ffd)) + { + pam_error(pamh, "Unable to close %s: %s", from, + strerror(errno)); + return PAM_PERM_DENIED; + } + + if (chown(to, pwent->pw_uid, pwent->pw_gid)) + { + pam_error(pamh, "Changing ownership of symlink %s failed: %s", + to, strerror(errno)); + return PAM_PERM_DENIED; + } + } + + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_open_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + const struct passwd *pwent; + const char *user; + struct stat di; + void (*sh)(int); + pid_t child; + int res; + + /* Who are we talking about anyway? */ + res = pam_get_user(pamh, &user, NULL); + if (res != PAM_SUCCESS) + return res; + + /* Fetch passwd entry */ + pwent = getpwnam(user); + if (!pwent) + { + pam_error(pamh, "User not found in passwd?"); + return PAM_CRED_INSUFFICIENT; + } + + openlog("pam_mkhomedir", LOG_PID, LOG_AUTH); + if (stat(pwent->pw_dir, &di)) + return pam_mkhd_copy(pamh, pwent, "/etc/skel", pwent->pw_dir); + + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_close_session(pam_handle_t *pamh, int flags, + int argc, const char **argv) +{ + (void) pamh; (void) flags; (void) argc; (void) argv; + return PAM_SUCCESS; +} |