Resurrect linux homedir support
authorMichael Spang <mspang@uwaterloo.ca>
Wed, 29 Jul 2009 12:56:20 +0000 (08:56 -0400)
committerMichael Spang <mspang@uwaterloo.ca>
Wed, 29 Jul 2009 12:56:27 +0000 (08:56 -0400)
debian/control
src/Makefile
src/config-vars.h
src/homedir.c [new file with mode: 0644]
src/homedir.h [new file with mode: 0644]
src/op-adduser.c

index 80500d3..46595da 100644 (file)
@@ -2,7 +2,7 @@ Source: ceo
 Section: admin
 Priority: optional
 Maintainer: Systems Committee <syscom@csclub.uwaterloo.ca>
-Build-Depends: debhelper (>= 5.0.0), python-dev (>= 2.4), python-support (>= 0.3), libkrb5-dev, libldap2-dev, libsasl2-dev, libsctp-dev, libprotobuf-c0-dev
+Build-Depends: debhelper (>= 5.0.0), python-dev (>= 2.4), python-support (>= 0.3), libkrb5-dev, libldap2-dev, libsasl2-dev, libsctp-dev, libprotobuf-c0-dev, libacl1-dev
 Standards-Version: 3.8.2
 
 Package: ceo
index e9ac610..7b4bec0 100644 (file)
@@ -16,6 +16,9 @@ LDAP_PROGS     := addmember addclub op-adduser
 KRB5_OBJECTS   := krb5.o kadm.o
 KRB5_LDFLAGS   := $(shell krb5-config --libs krb5 kadm-client)
 KRB5_PROGS     := addmember addclub op-adduser
+HOME_OBJECTS   := homedir.o
+HOME_LDFLAGS   := -lacl
+HOME_PROGS     := op-adduser
 NET_OBJECTS    := net.o gss.o ops.o
 NET_LDFLAGS    := -lsctp $(shell krb5-config --libs gssapi)
 NET_PROGS      := ceod ceoc
@@ -57,6 +60,8 @@ $(LDAP_PROGS):   LDFLAGS += $(LDAP_LDFLAGS)
 $(LDAP_PROGS):   $(LDAP_OBJECTS)
 $(KRB5_PROGS):   LDFLAGS += $(KRB5_LDFLAGS)
 $(KRB5_PROGS):   $(KRB5_OBJECTS)
+$(HOME_PROGS):   LDFLAGS += $(HOME_LDFLAGS)
+$(HOME_PROGS):   $(HOME_OBJECTS)
 $(PROTO_PROGS):  LDFLAGS += $(PROTO_LDFLAGS)
 $(PROTO_PROGS):  $(PROTO_OBJECTS)
 $(CONFIG_PROGS): LDFLAGS += $(CONFIG_LDFLAGS)
index 2c2334c..c7a2094 100644 (file)
@@ -5,20 +5,16 @@ CONFIG_STR(groups_base)
 CONFIG_STR(sudo_base)
 
 CONFIG_STR(skeleton_dir)
-CONFIG_STR(homedir_mode)
-CONFIG_STR(refquota)
 
 CONFIG_STR(member_shell)
 CONFIG_INT(member_min_id)
 CONFIG_INT(member_max_id)
 CONFIG_STR(member_home)
-CONFIG_STR(member_home_acl)
 
 CONFIG_STR(club_shell)
 CONFIG_INT(club_min_id)
 CONFIG_INT(club_max_id)
 CONFIG_STR(club_home)
-CONFIG_STR(club_home_acl)
 
 CONFIG_STR(notify_hook)
 
diff --git a/src/homedir.c b/src/homedir.c
new file mode 100644 (file)
index 0000000..83772df
--- /dev/null
@@ -0,0 +1,121 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/acl.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <fcntl.h>
+
+#include "homedir.h"
+#include "util.h"
+#include "config.h"
+
+int ceo_create_home(char *homedir, uid_t uid, gid_t gid) {
+    int mask;
+    DIR *skel;
+    struct dirent *skelent;
+
+    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;
+    }
+
+    umask(mask);
+
+    return 0;
+}
diff --git a/src/homedir.h b/src/homedir.h
new file mode 100644 (file)
index 0000000..8bc04bf
--- /dev/null
@@ -0,0 +1,3 @@
+#include <sys/acl.h>
+
+int ceo_create_home(char *homedir, uid_t uid, gid_t gid);
index c75f8bb..17f3602 100644 (file)
@@ -19,6 +19,7 @@
 #include "gss.h"
 #include "krb5.h"
 #include "ldap.h"
+#include "homedir.h"
 #include "kadm.h"
 #include "daemon.h"
 #include "strbuf.h"
@@ -136,7 +137,7 @@ static void adduser_spam(Ceo__AddUser *in, Ceo__AddUserResponse *out, char *clie
 
 static int32_t addmember(Ceo__AddUser *in, Ceo__AddUserResponse *out) {
     char homedir[1024];
-    int user_stat, group_stat, krb_stat;
+    int user_stat, group_stat, krb_stat, home_stat;
     int id;
 
     if (snprintf(homedir, sizeof(homedir), "%s/%s",
@@ -165,12 +166,15 @@ static int32_t addmember(Ceo__AddUser *in, Ceo__AddUserResponse *out) {
     else
         response_message(out, 0, "successfully created ldap group");
 
-    return krb_stat || user_stat || group_stat;
+    if ((home_stat = ceo_create_home(homedir, id, id)))
+        notice("successfully created home directory for %s", in->username);
+
+    return krb_stat || user_stat || group_stat || home_stat;
 }
 
 static int32_t addclub(Ceo__AddUser *in, Ceo__AddUserResponse *out) {
     char homedir[1024];
-    int krb_stat, user_stat, group_stat, sudo_stat;
+    int krb_stat, user_stat, group_stat, sudo_stat, home_stat;
     int id;
 
     if (snprintf(homedir, sizeof(homedir), "%s/%s",
@@ -200,7 +204,10 @@ static int32_t addclub(Ceo__AddUser *in, Ceo__AddUserResponse *out) {
     else
         response_message(out, 0, "successfully created ldap sudoers");
 
-    return user_stat || group_stat || sudo_stat;
+    if ((home_stat = ceo_create_home(homedir, id, id)))
+        notice("successfully created home directory for %s", in->username);
+
+    return user_stat || group_stat || sudo_stat || home_stat;
 }
 
 static int32_t adduser(Ceo__AddUser *in, Ceo__AddUserResponse *out, char *client) {