Merge branch 'master' of /users/git/public/pyceo
[public/pyceo-broken.git] / src / addmember.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 int use_stdin = 0;
31
32 static char *name = NULL;
33 static char *userid = NULL;
34 static char *program = NULL;
35 static char password[1024];
36
37 static struct option opts[] = {
38     { "force", 0, NULL, 'f' },
39     { "no-notify", 0, NULL, 'q' },
40     { "stdin", 0, NULL, 's' },
41     { NULL, 0, NULL, '\0' },
42 };
43
44 static void usage() {
45     fprintf(stderr, "Usage: %s userid realname [program]\n", prog);
46     exit(2);
47 }
48
49 int addmember() {
50     int krb_ok, user_ok, group_ok, home_ok, quota_ok;
51     int id;
52     char homedir[1024];
53     char acl_s[1024], dacl_s[1024];
54     acl_t acl = NULL, dacl = NULL;
55
56     logmsg("adding uid=%s cn=%s program=%s by %s", userid, name, program, user);
57
58     if (setreuid(0, 0))
59         fatalpe("setreuid");
60
61     if (!force && getpwnam(userid) != NULL)
62         deny("user %s already exists", userid);
63
64     snprintf(homedir, sizeof(homedir), "%s/%s", member_home, userid);
65
66     if (ceo_read_password(password, sizeof(password), use_stdin))
67         return 1;
68
69     ceo_krb5_init();
70     ceo_ldap_init();
71     ceo_kadm_init();
72
73     if (ceo_user_exists(userid))
74         deny("user %s already exists in LDAP", userid);
75
76     if ((id = ceo_new_uid(member_min_id, member_max_id)) <= 0)
77         fatal("no available uids in range [%d, %d]", member_min_id, member_max_id);
78
79     snprintf(acl_s, sizeof(acl_s), member_home_acl, id);
80
81     acl = acl_from_text(acl_s);
82     if (acl == NULL)
83         fatalpe("Unable to parse member_home_acl");
84
85     if (*member_home_acl) {
86         snprintf(dacl_s, sizeof(dacl_s), member_home_dacl, id);
87         dacl = acl_from_text(dacl_s);
88         if (dacl == NULL)
89             fatalpe("Unable to parse member_home_dacl");
90     }
91     krb_ok = ceo_del_princ(userid);
92     krb_ok = krb_ok || ceo_add_princ(userid, password);
93     if (!krb_ok)
94         logmsg("successfully created principal for %s", userid);
95
96     user_ok = krb_ok || ceo_add_user(userid, users_base, "member", name, homedir,
97             member_shell, id, "program", program, NULL);
98     if (!user_ok)
99         logmsg("successfully created account for %s", userid);
100
101     group_ok = user_ok || ceo_add_group(userid, groups_base, id);
102     if (!group_ok)
103         logmsg("successfully created group for %s", userid);
104
105     home_ok = user_ok || ceo_create_home(homedir, id, id, acl, dacl);
106     if (!home_ok)
107         logmsg("successfully created home directory for %s", userid);
108
109     quota_ok = user_ok || ceo_set_quota(quota_prototype, id);
110     if (!quota_ok)
111         logmsg("successfully set quota for %s", userid);
112
113     logmsg("done uid=%s", userid);
114
115     if (!no_notify && !user_ok) {
116         int pid;
117         int hkp[2];
118         FILE *hkf;
119         int status;
120
121         if (pipe(hkp))
122             errorpe("pipe");
123
124         fflush(stdout);
125         fflush(stderr);
126
127         pid = fork();
128
129         if (!pid) {
130             fclose(stdout);
131             fclose(stderr);
132             close(hkp[1]);
133             dup2(hkp[0], 0);
134             exit(execl(notify_hook, notify_hook, prog, user, userid, name, program, NULL));
135         }
136
137         hkf = fdopen(hkp[1], "w");
138
139         if (group_ok)
140             fprintf(hkf, "failed to create group\n");
141         if (home_ok)
142             fprintf(hkf, "failed to create home directory\n");
143         if (quota_ok)
144             fprintf(hkf, "failed to set quota\n");
145         if (!group_ok && !home_ok && !quota_ok)
146             fprintf(hkf, "all failures went undetected\n");
147
148         fclose(hkf);
149
150         waitpid(pid, &status, 0);
151
152         if (WIFEXITED(status) && WEXITSTATUS(status))
153             logmsg("hook %s exited with status %d", notify_hook, WEXITSTATUS(status));
154         else if (WIFSIGNALED(status))
155             logmsg("hook %s killed by signal %d", notify_hook, WTERMSIG(status));
156     }
157
158     ceo_kadm_cleanup();
159     ceo_ldap_cleanup();
160     ceo_krb5_cleanup();
161
162     return krb_ok || user_ok || group_ok || home_ok || quota_ok;
163 }
164
165 int main(int argc, char *argv[]) {
166     int opt;
167
168     openlog(prog, 0, LOG_AUTHPRIV);
169
170     configure();
171
172     prog = basename(argv[0]);
173     user = ceo_get_user();
174     privileged = ceo_get_privileged();
175
176     while ((opt = getopt_long(argc, argv, "", opts, NULL)) != -1) {
177         switch (opt) {
178             case 's':
179                 use_stdin = 1;
180                 break;
181             case 'f':
182                 if (!privileged)
183                     deny("not privileged enough to force");
184                 force = 1;
185                 break;
186             case 'q':
187                 if (!privileged)
188                     deny("not privileged enough to suppress notifications");
189                 no_notify = 1;
190                 break;
191             case '?':
192                 usage();
193                 break;
194             default:
195                 fatal("error parsing arguments");
196         }
197     }
198
199     if (argc - optind != 2 && argc - optind != 3)
200         usage();
201
202     userid = argv[optind++];
203     name = argv[optind++];
204
205     if (argc - optind)
206         program = argv[optind++];
207
208     return addmember();
209 }