Make CEO non-SUID
[mspang/pyceo.git] / src / addhomedir.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <dirent.h>
6 #include <pwd.h>
7 #include <fcntl.h>
8
9 #include "addhomedir.h"
10 #include "util.h"
11 #include "config.h"
12
13 int ceo_create_home(char *homedir, uid_t uid, gid_t gid) {
14     int mask;
15     DIR *skel;
16     struct dirent *skelent;
17
18     mask = umask(0);
19
20     if (mkdir(homedir, homedir_mode)) {
21         errorpe("failed to create %s", homedir);
22         return -1;
23     }
24
25     skel = opendir(skeleton_dir);
26     if (!skel) {
27         errorpe("failed to open %s", skeleton_dir);
28         return -1;
29     }
30
31     while ((skelent = readdir(skel))) {
32         struct stat sb;
33         char src[PATH_MAX], dest[PATH_MAX];
34
35         if (!strcmp(skelent->d_name, ".") || !strcmp(skelent->d_name, ".."))
36             continue;
37
38         snprintf(src, sizeof(src), "%s/%s", skeleton_dir, skelent->d_name);
39         snprintf(dest, sizeof(dest), "%s/%s", homedir, skelent->d_name);
40         lstat(src, &sb);
41
42         if (sb.st_uid || sb.st_gid) {
43             warn("not creating %s due to ownership", dest);
44             continue;
45         }
46
47         if (S_ISREG(sb.st_mode)) {
48             int bytes;
49             char buf[4096];
50
51             int srcfd = open(src, O_RDONLY);
52             if (srcfd == -1) {
53                 warnpe("open: %s", src);
54                 continue;
55             }
56
57             int destfd = open(dest, O_WRONLY|O_CREAT|O_EXCL, sb.st_mode & 0777);
58             if (destfd == -1) {
59                 warnpe("open: %s", dest);
60                 close(srcfd);
61                 continue;
62             }
63
64             for (;;) {
65                 bytes = read(srcfd, buf, sizeof(buf));
66                 if (!bytes)
67                     break;
68                 if (bytes < 0) {
69                     warnpe("read");
70                     break;
71                 }
72                 if (write(destfd, buf, bytes) < 0) {
73                     warnpe("write");
74                     break;
75                 }
76             }
77
78             if (fchown(destfd, uid, gid))
79                 errorpe("chown: %s", dest);
80
81             close(srcfd);
82             close(destfd);
83         } else if (S_ISDIR(sb.st_mode)) {
84             if (mkdir(dest, sb.st_mode & 0777)) {
85                 warnpe("mkdir: %s", dest);
86                 continue;
87             }
88             if (chown(dest, uid, gid))
89                 errorpe("chown: %s", dest);
90         } else if (S_ISLNK(sb.st_mode)) {
91             char lnkdest[PATH_MAX];
92             int bytes;
93             bytes = readlink(src, lnkdest, sizeof(lnkdest));
94             lnkdest[bytes] = '\0';
95             if (bytes == -1) {
96                 warnpe("readlink: %s", src);
97                 continue;
98             }
99             if (symlink(lnkdest, dest)) {
100                 warnpe("symlink: %s", dest);
101                 continue;
102             }
103             if (lchown(dest, uid, gid))
104                 errorpe("lchown: %s", dest);
105         } else {
106             warn("not creating %s", dest);
107         }
108     }
109
110     closedir(skel);
111
112     if (chown(homedir, uid, gid))
113         errorpe("failed to chown %s", homedir);
114
115     umask(mask);
116
117     return 0;
118 }
119
120 int ceo_set_quota(char *proto, int id) {
121     char user[128];
122     char *sqargs[] = { "setquota", "-a", "-p", proto, NULL, NULL };
123
124     snprintf(user, sizeof(user), "%d", id);
125     sqargs[4] = user;
126
127     if (spawnv("/usr/sbin/setquota", sqargs)) {
128         error("failed to set quota for %s", user);
129         return -1;
130     }
131
132     return 0;
133 }