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