From a834ffda8f39316e41581f74b41a8c9e1e76b025 Mon Sep 17 00:00:00 2001 From: David Bartley Date: Sat, 15 Mar 2008 02:22:08 -0400 Subject: [PATCH] Add zfsaddhomedir --- src/.gitignore | 1 + src/Makefile | 5 +- src/addclub.c | 32 ++-------- src/addhomedir.c | 138 ++++--------------------------------------- src/addhomedir.h | 3 +- src/addmember.c | 30 +++------- src/config.c | 17 +++--- src/config.h | 3 +- src/zfsaddhomedir.c | 140 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 178 insertions(+), 191 deletions(-) create mode 100644 src/zfsaddhomedir.c diff --git a/src/.gitignore b/src/.gitignore index d02cf7920..b07d4ffbd 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +1,5 @@ *.o /addmember /addclub +/zfsaddhomedir /config-test diff --git a/src/Makefile b/src/Makefile index 3fdcd19b6..fa5caf6b5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,7 +10,7 @@ PREFIX := /usr/local all: addmember addclub clean: - rm -f addmember addclub config-test *.o + rm -f addmember addclub zfsaddhomedir config-test *.o addmember: $(LIBCEO_OBJECTS) addmember.o $(CC) $(LDFLAGS) $(LIBCEO_LDFLAGS) $^ -o $@ @@ -18,6 +18,9 @@ addmember: $(LIBCEO_OBJECTS) addmember.o addclub: $(LIBCEO_OBJECTS) addclub.o $(CC) $(LDFLAGS) $(LIBCEO_LDFLAGS) $^ -o $@ +zfsaddhomedir: util.o zfsaddhomedir.o + $(CC) $(LDFLAGS) $^ -o $@ + config-test: config-test.o parser.o util.o $(CC) $(LDFLAGS) $^ -o $@ diff --git a/src/addclub.c b/src/addclub.c index 87abcae73..430ae627a 100644 --- a/src/addclub.c +++ b/src/addclub.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -42,11 +41,10 @@ static void usage() { } int addclub() { - int krb_ok, user_ok, group_ok, sudo_ok, home_ok, quota_ok; + int krb_ok, user_ok, group_ok, sudo_ok, home_ok; int id; char homedir[1024]; - char acl_s[1024], dacl_s[1024]; - acl_t acl = NULL, dacl = NULL; + char acl_s[1024] = {0}; logmsg("adding uid=%s cn=%s by %s", userid, name, user); @@ -67,19 +65,7 @@ int addclub() { if ((id = ceo_new_uid(club_min_id, club_max_id)) <= 0) fatal("no available uids in range [%d, %d]", club_min_id, club_max_id); - snprintf(acl_s, sizeof(acl_s), club_home_acl, id); - - acl = acl_from_text(acl_s); - if (acl == NULL) - fatalpe("Unable to parse club_home_acl"); - - if (*club_home_dacl) { - snprintf(dacl_s, sizeof(dacl_s), club_home_dacl, id); - dacl = acl_from_text(dacl_s); - if (dacl == NULL) - fatalpe("Unable to parse club_home_dacl"); - } - + snprintf(acl_s, sizeof(acl_s), club_home_acl, userid); krb_ok = ceo_del_princ(userid); if (!krb_ok) @@ -98,14 +84,10 @@ int addclub() { if (!sudo_ok) logmsg("successfully added group sudo entry for %s", userid); - home_ok = user_ok || ceo_create_home(homedir, id, id, acl, dacl); + home_ok = user_ok || ceo_create_home(homedir, id, id, homedir_mode, acl_s); if (!home_ok) logmsg("successfully created home directory for %s", userid); - quota_ok = user_ok || ceo_set_quota(quota_prototype, id); - if (!quota_ok) - logmsg("successfully set quota for %s", userid); - logmsg("done uid=%s", userid); if (!no_notify && !user_ok) { @@ -136,9 +118,7 @@ int addclub() { fprintf(hkf, "failed to create group\n"); if (home_ok) fprintf(hkf, "failed to create home directory\n"); - if (quota_ok) - fprintf(hkf, "failed to set quota\n"); - if (!group_ok && !home_ok && !quota_ok) + if (!group_ok && !home_ok) fprintf(hkf, "all failures went undetected\n"); fclose(hkf); @@ -155,7 +135,7 @@ int addclub() { ceo_ldap_cleanup(); ceo_krb5_cleanup(); - return krb_ok || user_ok || group_ok || home_ok || quota_ok; + return krb_ok || user_ok || group_ok || home_ok; } int main(int argc, char *argv[]) { diff --git a/src/addhomedir.c b/src/addhomedir.c index 6cd27dbb3..5c396ea65 100644 --- a/src/addhomedir.c +++ b/src/addhomedir.c @@ -6,139 +6,23 @@ #include #include #include +#include #include "addhomedir.h" #include "util.h" #include "config.h" -int ceo_create_home(char *homedir, uid_t uid, gid_t gid, acl_t acl, acl_t dacl) { - int mask; - DIR *skel; - struct dirent *skelent; +int ceo_create_home(char *homedir, uid_t uid, gid_t gid, char *mode, char *acl) { + char uid_str[16], gid_str[16]; + char *zfs_argv[] = { "ssh", "ceo@ginseng", "/usr/sbin/zfsaddhomedir", \ + homedir, skeleton_dir, uid_str, gid_str, mode, acl, NULL }; - mask = umask(0); - - if (mkdir(homedir, 0755)) { - errorpe("failed to create %s", homedir); - return -1; - } - - skel = opendir(skeleton_dir); - if (!skel) { - errorpe("failed to open %s", skeleton_dir); - return -1; - } - - while ((skelent = readdir(skel))) { - struct stat sb; - char src[PATH_MAX], dest[PATH_MAX]; - - if (!strcmp(skelent->d_name, ".") || !strcmp(skelent->d_name, "..")) - continue; - - snprintf(src, sizeof(src), "%s/%s", skeleton_dir, skelent->d_name); - snprintf(dest, sizeof(dest), "%s/%s", homedir, skelent->d_name); - lstat(src, &sb); - - if (sb.st_uid || sb.st_gid) { - warn("not creating %s due to ownership", dest); - continue; - } - - if (S_ISREG(sb.st_mode)) { - int bytes; - char buf[4096]; - - int srcfd = open(src, O_RDONLY); - if (srcfd == -1) { - warnpe("open: %s", src); - continue; - } - - int destfd = open(dest, O_WRONLY|O_CREAT|O_EXCL, sb.st_mode & 0777); - if (destfd == -1) { - warnpe("open: %s", dest); - close(srcfd); - continue; - } - - for (;;) { - bytes = read(srcfd, buf, sizeof(buf)); - if (!bytes) - break; - if (bytes < 0) { - warnpe("read"); - break; - } - if (write(destfd, buf, bytes) < 0) { - warnpe("write"); - break; - } - } - - if (fchown(destfd, uid, gid)) - errorpe("chown: %s", dest); - - close(srcfd); - close(destfd); - } else if (S_ISDIR(sb.st_mode)) { - if (mkdir(dest, sb.st_mode & 0777)) { - warnpe("mkdir: %s", dest); - continue; - } - if (chown(dest, uid, gid)) - errorpe("chown: %s", dest); - } else if (S_ISLNK(sb.st_mode)) { - char lnkdest[PATH_MAX]; - int bytes; - bytes = readlink(src, lnkdest, sizeof(lnkdest)); - lnkdest[bytes] = '\0'; - if (bytes == -1) { - warnpe("readlink: %s", src); - continue; - } - if (symlink(lnkdest, dest)) { - warnpe("symlink: %s", dest); - continue; - } - if (lchown(dest, uid, gid)) - errorpe("lchown: %s", dest); - } else { - warn("not creating %s", dest); - } - } - - closedir(skel); - - if (chown(homedir, uid, gid)) { - errorpe("failed to chown %s", homedir); - return -1; - } - - if (acl && acl_set_file(homedir, ACL_TYPE_ACCESS, acl)) { - errorpe("failed to set acl for %s", homedir); - return -1; - } - - if (dacl && acl_set_file(homedir, ACL_TYPE_DEFAULT, dacl)) { - errorpe("failed to set default acl for %s", homedir); - return -1; - } - - umask(mask); - - return 0; -} - -int ceo_set_quota(char *proto, int id) { - char user[128]; - char *sqargs[] = { "setquota", "-a", "-p", proto, NULL, NULL }; - - snprintf(user, sizeof(user), "%d", id); - sqargs[4] = user; - - if (spawnv("/usr/sbin/setquota", sqargs)) { - error("failed to set quota for %s", user); + assert(homedir[0]); + snprintf(uid_str, sizeof(uid_str), "%ld", (long)uid); + snprintf(gid_str, sizeof(gid_str), "%ld", (long)uid); + if(!acl[0]) acl = NULL; + if(spawnv("/usr/bin/ssh", zfs_argv)) { + errorpe("failed calling zfsaddhomedir for %s", homedir); return -1; } diff --git a/src/addhomedir.h b/src/addhomedir.h index 560dbc8d9..9d3493d0a 100644 --- a/src/addhomedir.h +++ b/src/addhomedir.h @@ -1,4 +1,3 @@ #include -int ceo_create_home(char *, uid_t, gid_t, acl_t, acl_t); -int ceo_set_quota(char *, int); +int ceo_create_home(char *, uid_t, gid_t, char *, char *); diff --git a/src/addmember.c b/src/addmember.c index f43507ad6..62ee40875 100644 --- a/src/addmember.c +++ b/src/addmember.c @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -47,11 +46,10 @@ static void usage() { } int addmember() { - int krb_ok, user_ok, group_ok, home_ok, quota_ok; + int krb_ok, user_ok, group_ok, home_ok; int id; char homedir[1024]; - char acl_s[1024], dacl_s[1024]; - acl_t acl = NULL, dacl = NULL; + char acl_s[1024] = {0}; logmsg("adding uid=%s cn=%s program=%s by %s", userid, name, program, user); @@ -76,18 +74,10 @@ int addmember() { if ((id = ceo_new_uid(member_min_id, member_max_id)) <= 0) fatal("no available uids in range [%d, %d]", member_min_id, member_max_id); - snprintf(acl_s, sizeof(acl_s), member_home_acl, id); - - acl = acl_from_text(acl_s); - if (acl == NULL) - fatalpe("Unable to parse member_home_acl"); - if (*member_home_acl) { - snprintf(dacl_s, sizeof(dacl_s), member_home_dacl, id); - dacl = acl_from_text(dacl_s); - if (dacl == NULL) - fatalpe("Unable to parse member_home_dacl"); + snprintf(acl_s, sizeof(acl_s), member_home_acl, userid); } + krb_ok = ceo_del_princ(userid); krb_ok = krb_ok || ceo_add_princ(userid, password); if (!krb_ok) @@ -102,14 +92,10 @@ int addmember() { if (!group_ok) logmsg("successfully created group for %s", userid); - home_ok = user_ok || ceo_create_home(homedir, id, id, acl, dacl); + home_ok = user_ok || ceo_create_home(homedir, id, id, homedir_mode, acl_s); if (!home_ok) logmsg("successfully created home directory for %s", userid); - quota_ok = user_ok || ceo_set_quota(quota_prototype, id); - if (!quota_ok) - logmsg("successfully set quota for %s", userid); - logmsg("done uid=%s", userid); if (!no_notify && !user_ok) { @@ -140,9 +126,7 @@ int addmember() { fprintf(hkf, "failed to create group\n"); if (home_ok) fprintf(hkf, "failed to create home directory\n"); - if (quota_ok) - fprintf(hkf, "failed to set quota\n"); - if (!group_ok && !home_ok && !quota_ok) + if (!group_ok && !home_ok) fprintf(hkf, "all failures went undetected\n"); fclose(hkf); @@ -159,7 +143,7 @@ int addmember() { ceo_ldap_cleanup(); ceo_krb5_cleanup(); - return krb_ok || user_ok || group_ok || home_ok || quota_ok; + return krb_ok || user_ok || group_ok || home_ok; } int main(int argc, char *argv[]) { diff --git a/src/config.c b/src/config.c index b805d13f7..4afb36995 100644 --- a/src/config.c +++ b/src/config.c @@ -15,21 +15,19 @@ char *groups_base = DEF_STR; char *sudo_base = DEF_STR; char *skeleton_dir = DEF_STR; -char *quota_prototype = DEF_STR; +char *homedir_mode = DEF_STR; char *member_shell = DEF_STR; long member_min_id = DEF_LONG; long member_max_id = DEF_LONG; char *member_home = DEF_STR; char *member_home_acl = DEF_STR; -char *member_home_dacl = DEF_STR; char *club_shell = DEF_STR; long club_min_id = DEF_LONG; long club_max_id = DEF_LONG; char *club_home = DEF_STR; char *club_home_acl = DEF_STR; -char *club_home_dacl = DEF_STR; char *notify_hook = DEF_STR; @@ -47,17 +45,16 @@ char *sasl_mech = DEF_STR; char *privileged_group = DEF_STR; static char *strvarnames[] = { "server_url", "users_base", "admin_principal", - "admin_keytab", "skeleton_dir", "quota_prototype", "member_home", + "admin_keytab", "skeleton_dir", "homedir_mode", "member_home", "member_shell", "club_home", "club_shell", "realm", "admin_bind_userid", "admin_bind_keytab", "groups_base", "privileged_group", "notify_hook", "sasl_realm", "sasl_mech", "sudo_base", "member_home_acl", - "member_home_dacl", "club_home_acl", "club_home_dacl" }; + "club_home_acl" }; static char **strvars[] = { &server_url, &users_base, &admin_principal, - &admin_keytab, &skeleton_dir, "a_prototype, &member_home, - &member_shell, &club_home, &club_shell, &realm, &admin_bind_userid, - &admin_bind_keytab, &groups_base, &privileged_group, ¬ify_hook, - &sasl_realm, &sasl_mech, &sudo_base, &member_home_acl, &member_home_dacl, - &club_home_acl, &club_home_dacl }; + &admin_keytab, &skeleton_dir, &homedir_mode, &member_home, &member_shell, + &club_home, &club_shell, &realm, &admin_bind_userid, &admin_bind_keytab, + &groups_base, &privileged_group, ¬ify_hook, &sasl_realm, &sasl_mech, + &sudo_base, &member_home_acl, &club_home_acl }; static char *longvarnames[] = { "member_min_id", "member_max_id", "club_min_id", "club_max_id" }; diff --git a/src/config.h b/src/config.h index 8bf4c72c8..e67d395a0 100644 --- a/src/config.h +++ b/src/config.h @@ -6,7 +6,6 @@ extern char *groups_base; extern char *sudo_base; extern char *skeleton_dir; -extern char *quota_prototype; extern char *member_shell; extern long member_min_id; @@ -24,7 +23,7 @@ extern char *club_home_dacl; extern char *notify_hook; -extern long homedir_mode; +extern char *homedir_mode; extern char *realm; diff --git a/src/zfsaddhomedir.c b/src/zfsaddhomedir.c new file mode 100644 index 000000000..ebee39bec --- /dev/null +++ b/src/zfsaddhomedir.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "util.h" + +int main(int argc, char *argv[]) { + if(argc < 6) { + fprintf(stderr, "Usage: zfsaddhomedir homedir skeldir uid gid mode acl\n"); + return 1; + } + + // TODO: check return of spawnv + { + char *homedir = argv[1]; + char *skeldir = argv[2]; + char *mode = argv[5]; + char *acl = (argc >= 7) ? argv[6] : NULL; + uid_t uid, gid; + char *zfs_bin = "/usr/sbin/zfs"; + char *chmod_bin = "/usr/bin/chmod"; + char *dataset = homedir + 1; + char *create_argv[] = { "zfs", "create", dataset, NULL }; + char *quota_argv[] = { "zfs", "set", "quota=3G", dataset, NULL }; + char *mode_argv[] = { "chmod", mode, homedir, NULL }; + char *acl_argv[] = { "chmod", acl, homedir, NULL }; + DIR *skel; + struct dirent *skelent; + + assert(homedir[0]); + uid = atol(argv[3]); + gid = atol(argv[4]); + + if(spawnv(zfs_bin, create_argv)) + return 1; + if(spawnv(zfs_bin, quota_argv)) + return 1; + if(spawnv(chmod_bin, mode_argv)) + return 1; + if(acl && spawnv(chmod_bin, acl_argv)) + return 1; + + skel = opendir(skeldir); + if (!skel) { + errorpe("failed to open %s", skeldir); + return -1; + } + + while ((skelent = readdir(skel))) { + struct stat sb; + char src[PATH_MAX], dest[PATH_MAX]; + + if (!strcmp(skelent->d_name, ".") || !strcmp(skelent->d_name, "..")) + continue; + + snprintf(src, sizeof(src), "%s/%s", skeldir, skelent->d_name); + snprintf(dest, sizeof(dest), "/%s/%s", homedir, skelent->d_name); + lstat(src, &sb); + + if (sb.st_uid || sb.st_gid) { + warn("not creating %s due to ownership", dest); + continue; + } + + if (S_ISREG(sb.st_mode)) { + int bytes; + char buf[4096]; + + int srcfd = open(src, O_RDONLY); + if (srcfd == -1) { + warnpe("open: %s", src); + continue; + } + + int destfd = open(dest, O_WRONLY|O_CREAT|O_EXCL, sb.st_mode & 0777); + if (destfd == -1) { + warnpe("open: %s", dest); + close(srcfd); + continue; + } + + for (;;) { + bytes = read(srcfd, buf, sizeof(buf)); + if (!bytes) + break; + if (bytes < 0) { + warnpe("read"); + break; + } + if (write(destfd, buf, bytes) < 0) { + warnpe("write"); + break; + } + } + if (fchown(destfd, uid, gid)) + errorpe("chown: %s", dest); + + close(srcfd); + close(destfd); + } else if (S_ISDIR(sb.st_mode)) { + if (mkdir(dest, sb.st_mode & 0777)) { + warnpe("mkdir: %s", dest); + continue; + } + if (chown(dest, uid, gid)) + errorpe("chown: %s", dest); + } else if (S_ISLNK(sb.st_mode)) { + char lnkdest[PATH_MAX]; + int bytes; + bytes = readlink(src, lnkdest, sizeof(lnkdest)); + lnkdest[bytes] = '\0'; + if (bytes == -1) { + warnpe("readlink: %s", src); + continue; + } + if (symlink(lnkdest, dest)) { + warnpe("symlink: %s", dest); + continue; + } + if (lchown(dest, uid, gid)) + errorpe("lchown: %s", dest); + } else { + warn("not creating %s", dest); + } + } + + closedir(skel); + + if (chown(homedir, uid, gid)) { + errorpe("failed to chown %s", homedir); + return -1; + } + } + + return 0; +}