forked from public/pyceo
Add zfsaddhomedir
This commit is contained in:
parent
a51cbe4e55
commit
a834ffda8f
|
@ -1,4 +1,5 @@
|
||||||
*.o
|
*.o
|
||||||
/addmember
|
/addmember
|
||||||
/addclub
|
/addclub
|
||||||
|
/zfsaddhomedir
|
||||||
/config-test
|
/config-test
|
||||||
|
|
|
@ -10,7 +10,7 @@ PREFIX := /usr/local
|
||||||
all: addmember addclub
|
all: addmember addclub
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f addmember addclub config-test *.o
|
rm -f addmember addclub zfsaddhomedir config-test *.o
|
||||||
|
|
||||||
addmember: $(LIBCEO_OBJECTS) addmember.o
|
addmember: $(LIBCEO_OBJECTS) addmember.o
|
||||||
$(CC) $(LDFLAGS) $(LIBCEO_LDFLAGS) $^ -o $@
|
$(CC) $(LDFLAGS) $(LIBCEO_LDFLAGS) $^ -o $@
|
||||||
|
@ -18,6 +18,9 @@ addmember: $(LIBCEO_OBJECTS) addmember.o
|
||||||
addclub: $(LIBCEO_OBJECTS) addclub.o
|
addclub: $(LIBCEO_OBJECTS) addclub.o
|
||||||
$(CC) $(LDFLAGS) $(LIBCEO_LDFLAGS) $^ -o $@
|
$(CC) $(LDFLAGS) $(LIBCEO_LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
zfsaddhomedir: util.o zfsaddhomedir.o
|
||||||
|
$(CC) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
config-test: config-test.o parser.o util.o
|
config-test: config-test.o parser.o util.o
|
||||||
$(CC) $(LDFLAGS) $^ -o $@
|
$(CC) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/acl.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
@ -42,11 +41,10 @@ static void usage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int addclub() {
|
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;
|
int id;
|
||||||
char homedir[1024];
|
char homedir[1024];
|
||||||
char acl_s[1024], dacl_s[1024];
|
char acl_s[1024] = {0};
|
||||||
acl_t acl = NULL, dacl = NULL;
|
|
||||||
|
|
||||||
logmsg("adding uid=%s cn=%s by %s", userid, name, user);
|
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)
|
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);
|
fatal("no available uids in range [%d, %d]", club_min_id, club_max_id);
|
||||||
|
|
||||||
snprintf(acl_s, sizeof(acl_s), club_home_acl, id);
|
snprintf(acl_s, sizeof(acl_s), club_home_acl, userid);
|
||||||
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
krb_ok = ceo_del_princ(userid);
|
krb_ok = ceo_del_princ(userid);
|
||||||
if (!krb_ok)
|
if (!krb_ok)
|
||||||
|
@ -98,14 +84,10 @@ int addclub() {
|
||||||
if (!sudo_ok)
|
if (!sudo_ok)
|
||||||
logmsg("successfully added group sudo entry for %s", userid);
|
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)
|
if (!home_ok)
|
||||||
logmsg("successfully created home directory for %s", userid);
|
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);
|
logmsg("done uid=%s", userid);
|
||||||
|
|
||||||
if (!no_notify && !user_ok) {
|
if (!no_notify && !user_ok) {
|
||||||
|
@ -136,9 +118,7 @@ int addclub() {
|
||||||
fprintf(hkf, "failed to create group\n");
|
fprintf(hkf, "failed to create group\n");
|
||||||
if (home_ok)
|
if (home_ok)
|
||||||
fprintf(hkf, "failed to create home directory\n");
|
fprintf(hkf, "failed to create home directory\n");
|
||||||
if (quota_ok)
|
if (!group_ok && !home_ok)
|
||||||
fprintf(hkf, "failed to set quota\n");
|
|
||||||
if (!group_ok && !home_ok && !quota_ok)
|
|
||||||
fprintf(hkf, "all failures went undetected\n");
|
fprintf(hkf, "all failures went undetected\n");
|
||||||
|
|
||||||
fclose(hkf);
|
fclose(hkf);
|
||||||
|
@ -155,7 +135,7 @@ int addclub() {
|
||||||
ceo_ldap_cleanup();
|
ceo_ldap_cleanup();
|
||||||
ceo_krb5_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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
138
src/addhomedir.c
138
src/addhomedir.c
|
@ -6,139 +6,23 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "addhomedir.h"
|
#include "addhomedir.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
int ceo_create_home(char *homedir, uid_t uid, gid_t gid, acl_t acl, acl_t dacl) {
|
int ceo_create_home(char *homedir, uid_t uid, gid_t gid, char *mode, char *acl) {
|
||||||
int mask;
|
char uid_str[16], gid_str[16];
|
||||||
DIR *skel;
|
char *zfs_argv[] = { "ssh", "ceo@ginseng", "/usr/sbin/zfsaddhomedir", \
|
||||||
struct dirent *skelent;
|
homedir, skeleton_dir, uid_str, gid_str, mode, acl, NULL };
|
||||||
|
|
||||||
mask = umask(0);
|
assert(homedir[0]);
|
||||||
|
snprintf(uid_str, sizeof(uid_str), "%ld", (long)uid);
|
||||||
if (mkdir(homedir, 0755)) {
|
snprintf(gid_str, sizeof(gid_str), "%ld", (long)uid);
|
||||||
errorpe("failed to create %s", homedir);
|
if(!acl[0]) acl = NULL;
|
||||||
return -1;
|
if(spawnv("/usr/bin/ssh", zfs_argv)) {
|
||||||
}
|
errorpe("failed calling zfsaddhomedir for %s", homedir);
|
||||||
|
|
||||||
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);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
int ceo_create_home(char *, uid_t, gid_t, acl_t, acl_t);
|
int ceo_create_home(char *, uid_t, gid_t, char *, char *);
|
||||||
int ceo_set_quota(char *, int);
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/acl.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
@ -47,11 +46,10 @@ static void usage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int addmember() {
|
int addmember() {
|
||||||
int krb_ok, user_ok, group_ok, home_ok, quota_ok;
|
int krb_ok, user_ok, group_ok, home_ok;
|
||||||
int id;
|
int id;
|
||||||
char homedir[1024];
|
char homedir[1024];
|
||||||
char acl_s[1024], dacl_s[1024];
|
char acl_s[1024] = {0};
|
||||||
acl_t acl = NULL, dacl = NULL;
|
|
||||||
|
|
||||||
logmsg("adding uid=%s cn=%s program=%s by %s", userid, name, program, user);
|
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)
|
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);
|
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) {
|
if (*member_home_acl) {
|
||||||
snprintf(dacl_s, sizeof(dacl_s), member_home_dacl, id);
|
snprintf(acl_s, sizeof(acl_s), member_home_acl, userid);
|
||||||
dacl = acl_from_text(dacl_s);
|
|
||||||
if (dacl == NULL)
|
|
||||||
fatalpe("Unable to parse member_home_dacl");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
krb_ok = ceo_del_princ(userid);
|
krb_ok = ceo_del_princ(userid);
|
||||||
krb_ok = krb_ok || ceo_add_princ(userid, password);
|
krb_ok = krb_ok || ceo_add_princ(userid, password);
|
||||||
if (!krb_ok)
|
if (!krb_ok)
|
||||||
|
@ -102,14 +92,10 @@ int addmember() {
|
||||||
if (!group_ok)
|
if (!group_ok)
|
||||||
logmsg("successfully created group for %s", userid);
|
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)
|
if (!home_ok)
|
||||||
logmsg("successfully created home directory for %s", userid);
|
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);
|
logmsg("done uid=%s", userid);
|
||||||
|
|
||||||
if (!no_notify && !user_ok) {
|
if (!no_notify && !user_ok) {
|
||||||
|
@ -140,9 +126,7 @@ int addmember() {
|
||||||
fprintf(hkf, "failed to create group\n");
|
fprintf(hkf, "failed to create group\n");
|
||||||
if (home_ok)
|
if (home_ok)
|
||||||
fprintf(hkf, "failed to create home directory\n");
|
fprintf(hkf, "failed to create home directory\n");
|
||||||
if (quota_ok)
|
if (!group_ok && !home_ok)
|
||||||
fprintf(hkf, "failed to set quota\n");
|
|
||||||
if (!group_ok && !home_ok && !quota_ok)
|
|
||||||
fprintf(hkf, "all failures went undetected\n");
|
fprintf(hkf, "all failures went undetected\n");
|
||||||
|
|
||||||
fclose(hkf);
|
fclose(hkf);
|
||||||
|
@ -159,7 +143,7 @@ int addmember() {
|
||||||
ceo_ldap_cleanup();
|
ceo_ldap_cleanup();
|
||||||
ceo_krb5_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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
17
src/config.c
17
src/config.c
|
@ -15,21 +15,19 @@ char *groups_base = DEF_STR;
|
||||||
char *sudo_base = DEF_STR;
|
char *sudo_base = DEF_STR;
|
||||||
|
|
||||||
char *skeleton_dir = DEF_STR;
|
char *skeleton_dir = DEF_STR;
|
||||||
char *quota_prototype = DEF_STR;
|
char *homedir_mode = DEF_STR;
|
||||||
|
|
||||||
char *member_shell = DEF_STR;
|
char *member_shell = DEF_STR;
|
||||||
long member_min_id = DEF_LONG;
|
long member_min_id = DEF_LONG;
|
||||||
long member_max_id = DEF_LONG;
|
long member_max_id = DEF_LONG;
|
||||||
char *member_home = DEF_STR;
|
char *member_home = DEF_STR;
|
||||||
char *member_home_acl = DEF_STR;
|
char *member_home_acl = DEF_STR;
|
||||||
char *member_home_dacl = DEF_STR;
|
|
||||||
|
|
||||||
char *club_shell = DEF_STR;
|
char *club_shell = DEF_STR;
|
||||||
long club_min_id = DEF_LONG;
|
long club_min_id = DEF_LONG;
|
||||||
long club_max_id = DEF_LONG;
|
long club_max_id = DEF_LONG;
|
||||||
char *club_home = DEF_STR;
|
char *club_home = DEF_STR;
|
||||||
char *club_home_acl = DEF_STR;
|
char *club_home_acl = DEF_STR;
|
||||||
char *club_home_dacl = DEF_STR;
|
|
||||||
|
|
||||||
char *notify_hook = DEF_STR;
|
char *notify_hook = DEF_STR;
|
||||||
|
|
||||||
|
@ -47,17 +45,16 @@ char *sasl_mech = DEF_STR;
|
||||||
char *privileged_group = DEF_STR;
|
char *privileged_group = DEF_STR;
|
||||||
|
|
||||||
static char *strvarnames[] = { "server_url", "users_base", "admin_principal",
|
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",
|
"member_shell", "club_home", "club_shell", "realm", "admin_bind_userid",
|
||||||
"admin_bind_keytab", "groups_base", "privileged_group", "notify_hook",
|
"admin_bind_keytab", "groups_base", "privileged_group", "notify_hook",
|
||||||
"sasl_realm", "sasl_mech", "sudo_base", "member_home_acl",
|
"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,
|
static char **strvars[] = { &server_url, &users_base, &admin_principal,
|
||||||
&admin_keytab, &skeleton_dir, "a_prototype, &member_home,
|
&admin_keytab, &skeleton_dir, &homedir_mode, &member_home, &member_shell,
|
||||||
&member_shell, &club_home, &club_shell, &realm, &admin_bind_userid,
|
&club_home, &club_shell, &realm, &admin_bind_userid, &admin_bind_keytab,
|
||||||
&admin_bind_keytab, &groups_base, &privileged_group, ¬ify_hook,
|
&groups_base, &privileged_group, ¬ify_hook, &sasl_realm, &sasl_mech,
|
||||||
&sasl_realm, &sasl_mech, &sudo_base, &member_home_acl, &member_home_dacl,
|
&sudo_base, &member_home_acl, &club_home_acl };
|
||||||
&club_home_acl, &club_home_dacl };
|
|
||||||
|
|
||||||
static char *longvarnames[] = { "member_min_id", "member_max_id",
|
static char *longvarnames[] = { "member_min_id", "member_max_id",
|
||||||
"club_min_id", "club_max_id" };
|
"club_min_id", "club_max_id" };
|
||||||
|
|
|
@ -6,7 +6,6 @@ extern char *groups_base;
|
||||||
extern char *sudo_base;
|
extern char *sudo_base;
|
||||||
|
|
||||||
extern char *skeleton_dir;
|
extern char *skeleton_dir;
|
||||||
extern char *quota_prototype;
|
|
||||||
|
|
||||||
extern char *member_shell;
|
extern char *member_shell;
|
||||||
extern long member_min_id;
|
extern long member_min_id;
|
||||||
|
@ -24,7 +23,7 @@ extern char *club_home_dacl;
|
||||||
|
|
||||||
extern char *notify_hook;
|
extern char *notify_hook;
|
||||||
|
|
||||||
extern long homedir_mode;
|
extern char *homedir_mode;
|
||||||
|
|
||||||
extern char *realm;
|
extern char *realm;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#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;
|
||||||
|
}
|
Loading…
Reference in New Issue