]>
Commit | Line | Data |
---|---|---|
883e2e2b | 1 | /* $Id$ |
2 | * | |
3 | * This generates acl files for various servers. | |
4 | * | |
5 | * Copyright (C) 1999 by the Massachusetts Institute of Technology. | |
6 | * For copying and distribution information, please see the file | |
7 | * <mit-copyright.h>. | |
8 | */ | |
9 | ||
10 | #include <mit-copyright.h> | |
11 | #include <moira.h> | |
12 | #include <moira_site.h> | |
13 | #include "util.h" | |
14 | ||
15 | #include <sys/stat.h> | |
16 | #include <sys/types.h> | |
17 | ||
18 | #include <stdio.h> | |
19 | #include <stdlib.h> | |
20 | #include <string.h> | |
21 | ||
cb974713 | 22 | #ifdef HAVE_KRB4 |
883e2e2b | 23 | #include <krb.h> |
cb974713 | 24 | #endif |
883e2e2b | 25 | |
26 | EXEC SQL INCLUDE sqlca; | |
27 | ||
28 | RCSID("$Header$"); | |
29 | ||
30 | char *whoami = "acl.gen"; | |
31 | char *db = "moira/moira"; | |
883e2e2b | 32 | |
33 | void dump_access_file(FILE *out, int lid); | |
34 | char *merge_access_bits(char *t1, char *t2); | |
35 | void dump_discuss_acl(FILE *out, int lid); | |
36 | void dump_passwd_file(FILE *out, int lid); | |
37 | void dump_group_file(FILE *out, int id); | |
38 | char *merge_discuss_acls(char *one, char *two); | |
39 | void sqlerr(void); | |
40 | ||
41 | int main(int argc, char **argv) | |
42 | { | |
43 | EXEC SQL BEGIN DECLARE SECTION; | |
5904ab19 | 44 | int mid, lid, discuss_uid = -1; |
883e2e2b | 45 | char target[ACL_TARGET_SIZE], kind[ACL_KIND_SIZE]; |
46 | char host[MACHINE_NAME_SIZE]; | |
47 | EXEC SQL END DECLARE SECTION; | |
48 | char filename[MAXPATHLEN]; | |
49 | TARFILE *tf; | |
50 | FILE *out; | |
51 | struct save_queue *sq; | |
52 | time_t now = time(NULL); | |
53 | ||
54 | EXEC SQL WHENEVER SQLERROR DO sqlerr(); | |
55 | EXEC SQL CONNECT :db; | |
56 | init_acls(); | |
57 | ||
58 | EXEC SQL DECLARE csr_mach CURSOR FOR | |
59 | SELECT UNIQUE mach_id FROM acl; | |
60 | EXEC SQL OPEN csr_mach; | |
61 | while (1) | |
62 | { | |
63 | EXEC SQL FETCH csr_mach INTO :mid; | |
64 | if (sqlca.sqlcode) | |
65 | break; | |
66 | ||
67 | EXEC SQL SELECT name INTO :host FROM machine | |
68 | WHERE mach_id = :mid; | |
69 | if (sqlca.sqlcode) | |
70 | continue; | |
71 | strtrim(host); | |
72 | ||
73 | sprintf(filename, "%s/acl/%s", DCM_DIR, host); | |
74 | tf = tarfile_open(filename); | |
75 | ||
76 | EXEC SQL DECLARE csr_acl CURSOR FOR | |
77 | SELECT target, kind, list_id | |
78 | FROM acl | |
79 | WHERE mach_id = :mid; | |
80 | EXEC SQL OPEN csr_acl; | |
81 | while (1) | |
82 | { | |
83 | EXEC SQL FETCH csr_acl INTO :target, :kind, :lid; | |
84 | if (sqlca.sqlcode) | |
85 | break; | |
86 | ||
87 | strtrim(target); | |
88 | strtrim(kind); | |
89 | ||
5904ab19 | 90 | if (!strcasecmp(kind, "discuss")) |
91 | { | |
92 | /* Discuss acls need to be owned by discuss. */ | |
93 | if (discuss_uid == -1) | |
94 | { | |
95 | EXEC SQL SELECT unix_uid INTO :discuss_uid | |
96 | FROM users WHERE login = 'discuss'; | |
97 | } | |
98 | out = tarfile_start(tf, target, 0644, discuss_uid, 1, | |
99 | "discuss", "daemon", now); | |
100 | dump_discuss_acl(out, lid); | |
101 | } | |
102 | else | |
103 | { | |
104 | /* Otherwise own by root? Perhaps the acl table should | |
105 | * say, really... | |
106 | */ | |
107 | out = tarfile_start(tf, target, 0644, 0, 0, "root", "root", now); | |
108 | ||
109 | if (!strcasecmp(kind, "kerberos4")) | |
110 | dump_krb_acl(out, "LIST", lid, 4); | |
111 | else if (!strcasecmp(kind, "kerberos5")) | |
112 | dump_krb_acl(out, "LIST", lid, 5); | |
113 | else if (!strcasecmp(kind, "access")) | |
114 | dump_access_file(out, lid); | |
115 | else if (!strcasecmp(kind, "passwd")) | |
116 | dump_passwd_file(out, lid); | |
117 | else if (!strcasecmp(kind, "group")) | |
118 | dump_group_file(out, lid); | |
458b64a1 | 119 | else if (!strcasecmp(kind, "userlist")) |
120 | dump_user_list(out, "LIST", lid); | |
5904ab19 | 121 | } |
883e2e2b | 122 | |
123 | tarfile_end(tf); | |
124 | } | |
125 | ||
126 | tarfile_close(tf); | |
127 | } | |
128 | ||
129 | EXEC SQL COMMIT RELEASE; | |
130 | ||
131 | exit(MR_SUCCESS); | |
132 | } | |
133 | ||
134 | void dump_access_file(FILE *out, int lid) | |
135 | { | |
136 | struct save_queue *sq = get_acl("LIST", lid, merge_access_bits); | |
137 | struct imember *m; | |
39fa010c | 138 | char *name, *lasts = NULL; |
139 | int i = 0; | |
883e2e2b | 140 | |
141 | while (sq_remove_data(sq, &m)) | |
142 | { | |
143 | if (m->type == 'U' || | |
144 | (m->type == 'S' && m->name[0] == '*')) | |
145 | { | |
146 | if (*(m->tag)) | |
147 | fprintf(out, "%-10s %s\n", m->name, m->tag); | |
148 | else | |
149 | fprintf(out, "%-10s rl\n", m->name); | |
150 | } | |
39fa010c | 151 | else if (m->type == 'K') |
152 | { | |
153 | name = strtok_r(m->name, "@", &lasts); | |
154 | EXEC SQL SELECT count(login) INTO :i FROM users | |
f5da21ba | 155 | WHERE login = :name and status != 3; |
39fa010c | 156 | if (i == 1) |
157 | { | |
158 | if (*(m->tag)) | |
159 | fprintf(out, "%-10s %s\n", m->name, m->tag); | |
160 | else | |
161 | fprintf(out, "%-10s rl\n", m->name); | |
162 | } | |
163 | } | |
883e2e2b | 164 | freeimember(m); |
165 | } | |
166 | sq_destroy(sq); | |
167 | } | |
168 | ||
169 | char *merge_access_bits(char *t1, char *t2) | |
170 | { | |
171 | char *m = NULL, *ans; | |
172 | int r = 1, l = 1; | |
173 | ||
174 | /* Clear bits that aren't granted by both tags. */ | |
175 | if ((*t1 && t1[0] != 'r' && t1[1] != 'r') || | |
176 | (*t2 && t2[0] != 'r' && t2[1] != 'r')) | |
177 | r = 0; | |
178 | if ((*t1 && t1[0] != 'l' && t1[1] != 'l') || | |
179 | (*t2 && t2[0] != 'l' && t2[1] != 'l')) | |
180 | l = 0; | |
181 | ||
182 | if (!r || !l) | |
183 | { | |
184 | /* Skip to message part of tag 1 */ | |
185 | m = t1; | |
186 | while (*m && !isspace(*m)) | |
187 | m++; | |
188 | while (isspace(*m)) | |
189 | m++; | |
190 | ||
191 | /* If nothing there, skip to message part of tag 2 */ | |
192 | if (!*m) | |
193 | { | |
194 | m = t2; | |
195 | while (*m && !isspace(*m)) | |
196 | m++; | |
197 | while (isspace(*m)) | |
198 | m++; | |
199 | } | |
200 | ||
201 | ans = malloc(4 + strlen(m)); | |
202 | sprintf(ans, "%c %s", r ? 'r' : l ? 'l' : '-', m); | |
203 | } | |
204 | else | |
205 | { | |
206 | ans = malloc(3); | |
207 | strcpy(ans, "rl"); | |
208 | } | |
209 | return ans; | |
210 | } | |
211 | ||
212 | void dump_discuss_acl(FILE *out, int lid) | |
213 | { | |
214 | struct save_queue *sq = get_acl("LIST", lid, merge_discuss_acls); | |
215 | struct imember *m; | |
216 | char name[STRINGS_STRING_SIZE], *bits; | |
5904ab19 | 217 | char starbits[8] = { 0 }; |
883e2e2b | 218 | int num; |
219 | ||
220 | num = 0; | |
221 | while (sq_get_data(sq, &m)) | |
5904ab19 | 222 | { |
223 | if (m->type != 'S' || !strcmp(m->name, "*")) | |
224 | num++; | |
225 | } | |
883e2e2b | 226 | |
227 | fprintf(out, "%d\n", num); | |
228 | while (sq_remove_data(sq, &m)) | |
229 | { | |
5904ab19 | 230 | bits = merge_discuss_acls(m->tag, ""); |
883e2e2b | 231 | if (m->type != 'S') |
232 | { | |
233 | canon_krb(m, 4, name, sizeof(name)); | |
5904ab19 | 234 | fprintf(out, "%s:%s\n", bits, name); |
883e2e2b | 235 | } |
5904ab19 | 236 | else if (!strcmp(m->name, "*")) |
237 | strcpy(starbits, bits); | |
238 | free(bits); | |
883e2e2b | 239 | freeimember(m); |
240 | } | |
241 | sq_destroy(sq); | |
5904ab19 | 242 | |
243 | /* Discuss ACLs are ordered, so "*" must come last. */ | |
244 | if (*starbits) | |
245 | fprintf(out, "%s:*\n", starbits); | |
883e2e2b | 246 | } |
247 | ||
248 | char *merge_discuss_acls(char *one, char *two) | |
249 | { | |
250 | char bits[8]; | |
251 | ||
252 | sprintf(bits, "%c%c%c%c%c%c%c", | |
253 | strchr(one, 'a') || strchr(two, 'a') ? 'a' : ' ', | |
254 | strchr(one, 'c') || strchr(two, 'c') ? 'c' : ' ', | |
255 | strchr(one, 'd') || strchr(two, 'd') ? 'd' : ' ', | |
256 | strchr(one, 'o') || strchr(two, 'o') ? 'o' : ' ', | |
257 | strchr(one, 'r') || strchr(two, 'r') ? 'r' : ' ', | |
258 | strchr(one, 's') || strchr(two, 's') ? 's' : ' ', | |
259 | strchr(one, 'w') || strchr(two, 'w') ? 'w' : ' '); | |
260 | return strdup(bits); | |
261 | } | |
262 | ||
263 | void dump_passwd_file(FILE *out, int lid) | |
264 | { | |
265 | struct save_queue *sq = get_acl("LIST", lid, NULL); | |
266 | struct imember *m; | |
267 | EXEC SQL BEGIN DECLARE SECTION; | |
268 | char shell[USERS_SHELL_SIZE], fullname[USERS_FULLNAME_SIZE]; | |
269 | char nickname[USERS_NICKNAME_SIZE], oa[USERS_OFFICE_ADDR_SIZE]; | |
270 | char op[USERS_OFFICE_PHONE_SIZE], hp[USERS_HOME_PHONE_SIZE]; | |
39fa010c | 271 | int uid, i = 0; |
272 | char *name, *n, *lasts = NULL; | |
883e2e2b | 273 | EXEC SQL END DECLARE SECTION; |
274 | ||
275 | while (sq_remove_data(sq, &m)) | |
276 | { | |
277 | switch (m->type) | |
278 | { | |
279 | case 'U': | |
280 | name = m->name; | |
281 | ||
282 | EXEC SQL SELECT unix_uid, shell, fullname, nickname, | |
283 | office_addr, office_phone, home_phone | |
284 | INTO :uid, :shell, :fullname, :nickname, :oa, :op, :hp | |
285 | FROM users | |
286 | WHERE login = :name AND status != 3; | |
287 | if (sqlca.sqlcode) | |
288 | continue; | |
289 | ||
290 | strtrim(shell); | |
291 | strtrim(fullname); | |
292 | strtrim(nickname); | |
293 | strtrim(op); | |
294 | strtrim(oa); | |
295 | strtrim(hp); | |
296 | ||
297 | fprintf(out, "%s:*:%d:101:%s,%s,%s,%s,%s:/mit/%s:%s\n", | |
298 | name, uid, fullname, nickname, oa, op, hp, name, shell); | |
299 | break; | |
39fa010c | 300 | |
301 | case 'K': | |
302 | name = strtok_r(m->name, "@", &lasts); | |
303 | ||
304 | EXEC SQL SELECT count(login) INTO :i FROM users WHERE | |
f5da21ba | 305 | login = :name and status != 3; |
39fa010c | 306 | if (i == 1) |
307 | { | |
308 | EXEC SQL SELECT unix_uid, shell, fullname, nickname, | |
309 | office_addr, office_phone, home_phone | |
310 | INTO :uid, :shell, :fullname, :nickname, :oa, :op, :hp | |
311 | FROM users | |
312 | WHERE login = :name AND status != 3; | |
313 | if (sqlca.sqlcode) | |
314 | continue; | |
315 | ||
316 | strtrim(shell); | |
317 | strtrim(fullname); | |
318 | strtrim(nickname); | |
319 | strtrim(op); | |
320 | strtrim(oa); | |
321 | strtrim(hp); | |
322 | ||
323 | fprintf(out, "%s:*:%d:101:%s,%s,%s,%s,%s:/mit/%s:%s\n", | |
324 | name, uid, fullname, nickname, oa, op, hp, name, shell); | |
325 | } | |
326 | break; | |
883e2e2b | 327 | } |
328 | freeimember(m); | |
329 | } | |
330 | sq_destroy(sq); | |
331 | } | |
332 | ||
333 | /* This one is a bit weird since we actually look at top-level | |
334 | * lists rather then flattening them. | |
335 | */ | |
336 | void dump_group_file(FILE *out, int id) | |
337 | { | |
338 | EXEC SQL BEGIN DECLARE SECTION; | |
39fa010c | 339 | int lid = id, mid, gid, grouplist, i = 0; |
883e2e2b | 340 | char mtype[IMEMBERS_MEMBER_TYPE_SIZE], name[LIST_NAME_SIZE]; |
341 | EXEC SQL END DECLARE SECTION; | |
342 | struct save_queue *sq; | |
343 | struct imember *m; | |
39fa010c | 344 | char *maybecomma, *s, *n, *lasts = NULL; |
883e2e2b | 345 | |
346 | EXEC SQL DECLARE csr_grp CURSOR FOR | |
347 | SELECT member_type, member_id FROM imembers | |
348 | WHERE list_id = :lid AND direct = 1; | |
349 | EXEC SQL OPEN csr_grp; | |
350 | while (1) | |
351 | { | |
352 | EXEC SQL FETCH csr_grp INTO :mtype, :mid; | |
353 | if (sqlca.sqlcode) | |
354 | break; | |
355 | ||
356 | switch (*mtype) | |
357 | { | |
358 | case 'L': | |
359 | EXEC SQL SELECT name, gid, grouplist | |
360 | INTO :name, :gid, :grouplist | |
361 | FROM list | |
362 | WHERE list_id = :mid; | |
363 | if (sqlca.sqlcode || !grouplist) | |
364 | break; | |
365 | ||
366 | strtrim(name); | |
367 | ||
368 | fprintf(out, "%s:*:%d:", name, gid); | |
369 | sq = get_acl("LIST", mid, NULL); | |
370 | maybecomma = ""; | |
371 | while (sq_remove_data(sq, &m)) | |
372 | { | |
373 | if (m->type == 'U') | |
374 | { | |
375 | fprintf(out, "%s%s", maybecomma, m->name); | |
376 | maybecomma = ","; | |
377 | } | |
39fa010c | 378 | else if (m->type == 'K') |
379 | { | |
380 | n = strtok_r(m->name, "@", &lasts); | |
381 | EXEC SQL SELECT count(login) INTO :i FROM users | |
f5da21ba | 382 | WHERE login = :n and status != 3; |
39fa010c | 383 | if (i == 1) |
384 | { | |
385 | fprintf(out, "%s%s", maybecomma, n); | |
386 | maybecomma = ","; | |
387 | } | |
388 | } | |
883e2e2b | 389 | freeimember(m); |
390 | } | |
391 | fprintf(out, "\n"); | |
392 | sq_destroy(sq); | |
393 | break; | |
394 | } | |
395 | } | |
396 | EXEC SQL CLOSE csr_grp; | |
397 | } | |
398 | ||
399 | void sqlerr(void) | |
400 | { | |
401 | db_error(sqlca.sqlcode); | |
402 | exit(MR_DBMS_ERR); | |
403 | } |