]> andersk Git - moira.git/blob - gen/acl.pc
Build without krb4 if it's unavailable.
[moira.git] / gen / acl.pc
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 #ifdef HAVE_KRB4
23 #include <krb.h>
24 #endif
25
26 EXEC SQL INCLUDE sqlca;
27
28 RCSID("$Header$");
29
30 char *whoami = "acl.gen";
31 char *db = "moira/moira";
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;
44   int mid, lid, discuss_uid = -1;
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
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);
119               else if (!strcasecmp(kind, "userlist"))
120                 dump_user_list(out, "LIST", lid);
121             }
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;
138   char *name, *lasts = NULL;
139   int i = 0;
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         }
151       else if (m->type == 'K')
152         {
153           name = strtok_r(m->name, "@", &lasts);
154           EXEC SQL SELECT count(login) INTO :i FROM users 
155             WHERE login = :name and status != 3;
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         }
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;
217   char starbits[8] = { 0 };
218   int num;
219
220   num = 0;
221   while (sq_get_data(sq, &m))
222     {
223       if (m->type != 'S' || !strcmp(m->name, "*"))
224         num++;
225     }
226
227   fprintf(out, "%d\n", num);
228   while (sq_remove_data(sq, &m))
229     {
230       bits = merge_discuss_acls(m->tag, "");
231       if (m->type != 'S')
232         {
233           canon_krb(m, 4, name, sizeof(name));
234           fprintf(out, "%s:%s\n", bits, name);
235         }
236       else if (!strcmp(m->name, "*"))
237         strcpy(starbits, bits);
238       free(bits);
239       freeimember(m);
240     }
241   sq_destroy(sq);
242
243   /* Discuss ACLs are ordered, so "*" must come last. */
244   if (*starbits)
245     fprintf(out, "%s:*\n", starbits);
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];
271   int uid, i = 0;
272   char *name, *n, *lasts = NULL;
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;
300
301         case 'K':
302           name = strtok_r(m->name, "@", &lasts);
303             
304           EXEC SQL SELECT count(login) INTO :i FROM users WHERE 
305             login = :name and status != 3;
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;
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;
339   int lid = id, mid, gid, grouplist, i = 0;
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;
344   char *maybecomma, *s, *n, *lasts = NULL;
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                 }
378               else if (m->type == 'K')
379                 {
380                   n = strtok_r(m->name, "@", &lasts);
381                   EXEC SQL SELECT count(login) INTO :i FROM users
382                     WHERE login = :n and status != 3;
383                   if (i == 1)
384                     {
385                       fprintf(out, "%s%s", maybecomma, n);
386                       maybecomma = ",";
387                     }
388                 }
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 }
This page took 0.067528 seconds and 5 git commands to generate.