87abcae736cca4efc6356a8a8d26f4e35dee9547
[public/pyceo-broken.git] / src / addclub.c
1 #include <unistd.h>
2 #include <sys/types.h>
3 #include <sys/wait.h>
4 #include <sys/acl.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <getopt.h>
8 #include <ctype.h>
9 #include <pwd.h>
10 #include <grp.h>
11 #include <errno.h>
12 #include <libgen.h>
13 #include <syslog.h>
14
15 #include "util.h"
16 #include "common.h"
17 #include "config.h"
18 #include "ldap.h"
19 #include "krb5.h"
20 #include "kadm.h"
21 #include "addhomedir.h"
22
23 char *prog = NULL;
24 char *user = NULL;
25 int privileged = 0;
26
27 static int force = 0;
28 static int no_notify = 0;
29
30 static char *name = NULL;
31 static char *userid = NULL;
32
33 static struct option opts[] = {
34     { "force", 0, NULL, 'f' },
35     { "no-notify", 0, NULL, 'q' },
36     { NULL, 0, NULL, '\0' },
37 };
38
39 static void usage() {
40     fprintf(stderr, "Usage: %s userid clubname\n", prog);
41     exit(2);
42 }
43
44 int addclub() {
45     int krb_ok, user_ok, group_ok, sudo_ok, home_ok, quota_ok;
46     int id;
47     char homedir[1024];
48     char acl_s[1024], dacl_s[1024];
49     acl_t acl = NULL, dacl = NULL;
50
51     logmsg("adding uid=%s cn=%s by %s", userid, name, user);
52
53     if (setreuid(0, 0))
54         fatalpe("setreuid");
55
56     if (!force && getpwnam(userid) != NULL)
57         deny("user %s already exists", userid);
58
59     snprintf(homedir, sizeof(homedir), "%s/%s", club_home, userid);
60     ceo_krb5_init();
61     ceo_ldap_init();
62     ceo_kadm_init();
63
64     if (ceo_user_exists(userid))
65         deny("user %s already exists in LDAP", userid);
66
67     if ((id = ceo_new_uid(club_min_id, club_max_id)) <= 0)
68         fatal("no available uids in range [%d, %d]", club_min_id, club_max_id);
69
70     snprintf(acl_s, sizeof(acl_s), club_home_acl, id);
71
72     acl = acl_from_text(acl_s);
73     if (acl == NULL)
74         fatalpe("Unable to parse club_home_acl");
75
76     if (*club_home_dacl) {
77         snprintf(dacl_s, sizeof(dacl_s), club_home_dacl, id);
78         dacl = acl_from_text(dacl_s);
79         if (dacl == NULL)
80             fatalpe("Unable to parse club_home_dacl");
81     }
82
83
84     krb_ok = ceo_del_princ(userid);
85     if (!krb_ok)
86         logmsg("successfully cleared principal for %s", userid);
87
88     user_ok = krb_ok || ceo_add_user(userid, users_base, "club", name, homedir,
89             club_shell, id, NULL);
90     if (!user_ok)
91         logmsg("successfully created account for %s", userid);
92
93     group_ok = user_ok || ceo_add_group(userid, groups_base, id);
94     if (!group_ok)
95         logmsg("successfully created group for %s", userid);
96
97     sudo_ok = user_ok || ceo_add_group_sudo(userid, sudo_base);
98     if (!sudo_ok)
99         logmsg("successfully added group sudo entry for %s", userid);
100
101     home_ok = user_ok || ceo_create_home(homedir, id, id, acl, dacl);
102     if (!home_ok)
103         logmsg("successfully created home directory for %s", userid);
104
105     quota_ok = user_ok || ceo_set_quota(quota_prototype, id);
106     if (!quota_ok)
107         logmsg("successfully set quota for %s", userid);
108
109     logmsg("done uid=%s", userid);
110
111     if (!no_notify && !user_ok) {
112         int pid;
113         int hkp[2];
114         FILE *hkf;
115         int status;
116
117         if (pipe(hkp))
118             errorpe("pipe");
119
120         fflush(stdout);
121         fflush(stderr);
122
123         pid = fork();
124
125         if (!pid) {
126             fclose(stdout);
127             fclose(stderr);
128             close(hkp[1]);
129             dup2(hkp[0], 0);
130             exit(execl(notify_hook, notify_hook, prog, user, userid, name, NULL));
131         }
132
133         hkf = fdopen(hkp[1], "w");
134
135         if (group_ok)
136             fprintf(hkf, "failed to create group\n");
137         if (home_ok)
138             fprintf(hkf, "failed to create home directory\n");
139         if (quota_ok)
140             fprintf(hkf, "failed to set quota\n");
141         if (!group_ok && !home_ok && !quota_ok)
142             fprintf(hkf, "all failures went undetected\n");
143
144         fclose(hkf);
145
146         waitpid(pid, &status, 0);
147
148         if (WIFEXITED(status) && WEXITSTATUS(status))
149             logmsg("hook %s exited with status %d", notify_hook, WEXITSTATUS(status));
150         else if (WIFSIGNALED(status))
151             logmsg("hook %s killed by signal %d", notify_hook, WTERMSIG(status));
152     }
153
154     ceo_kadm_cleanup();
155     ceo_ldap_cleanup();
156     ceo_krb5_cleanup();
157
158     return krb_ok || user_ok || group_ok || home_ok || quota_ok;
159 }
160
161 int main(int argc, char *argv[]) {
162     int opt;
163
164     openlog(prog, 0, LOG_AUTHPRIV);
165
166     configure();
167
168     prog = basename(argv[0]);
169     user = ceo_get_user();
170     privileged = ceo_get_privileged();
171
172     while ((opt = getopt_long(argc, argv, "", opts, NULL)) != -1) {
173         switch (opt) {
174             case 'f':
175                 if (!privileged)
176                     deny("not privileged enough to force");
177                 force = 1;
178                 break;
179             case 'q':
180                 if (!privileged)
181                     deny("not privileged enough to suppress notifications");
182                 no_notify = 1;
183                 break;
184             case '?':
185                 usage();
186                 break;
187             default:
188                 fatal("error parsing arguments");
189         }
190     }
191
192     if (argc - optind != 2)
193         usage();
194
195     userid = argv[optind++];
196     name = argv[optind++];
197
198     return addclub();
199 }