source: trunk/third/moira/gen/acl.pc @ 23178

Revision 23178, 9.2 KB checked in by broder, 16 years ago (diff)
Take a new snapshot from CVS for Moira, and add a debathena-moira-update-server package
Line 
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
24EXEC SQL INCLUDE sqlca;
25
26RCSID("$Header$");
27
28char *whoami = "acl.gen";
29char *db = "moira/moira";
30char defaultrealm[REALM_SZ];
31
32void dump_access_file(FILE *out, int lid);
33char *merge_access_bits(char *t1, char *t2);
34void dump_discuss_acl(FILE *out, int lid);
35void dump_passwd_file(FILE *out, int lid);
36void dump_group_file(FILE *out, int id);
37char *merge_discuss_acls(char *one, char *two);
38void sqlerr(void);
39
40int main(int argc, char **argv)
41{
42  EXEC SQL BEGIN DECLARE SECTION;
43  int mid, lid, discuss_uid = -1;
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
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              else if (!strcasecmp(kind, "userlist"))
119                dump_user_list(out, "LIST", lid);
120            }
121
122          tarfile_end(tf);
123        }
124
125      tarfile_close(tf);
126    }
127
128  EXEC SQL COMMIT RELEASE;
129
130  exit(MR_SUCCESS);
131}
132
133void dump_access_file(FILE *out, int lid)
134{
135  struct save_queue *sq = get_acl("LIST", lid, merge_access_bits);
136  struct imember *m;
137  char *name, *lasts = NULL;
138  int i = 0;
139
140  while (sq_remove_data(sq, &m))
141    {
142      if (m->type == 'U' ||
143          (m->type == 'S' && m->name[0] == '*'))
144        {
145          if (*(m->tag))
146            fprintf(out, "%-10s %s\n", m->name, m->tag);
147          else
148            fprintf(out, "%-10s rl\n", m->name);
149        }
150      else if (m->type == 'K')
151        {
152          name = strtok_r(m->name, "@", &lasts);
153          EXEC SQL SELECT count(login) INTO :i FROM users
154            WHERE login = :name and status != 3;
155          if (i == 1)
156            {
157              if (*(m->tag))
158                fprintf(out, "%-10s %s\n", m->name, m->tag);
159              else
160                fprintf(out, "%-10s rl\n", m->name);
161            }
162        }
163      freeimember(m);
164    }
165  sq_destroy(sq);
166}
167
168char *merge_access_bits(char *t1, char *t2)
169{
170  char *m = NULL, *ans;
171  int r = 1, l = 1;
172
173  /* Clear bits that aren't granted by both tags. */
174  if ((*t1 && t1[0] != 'r' && t1[1] != 'r') ||
175      (*t2 && t2[0] != 'r' && t2[1] != 'r'))
176    r = 0;
177  if ((*t1 && t1[0] != 'l' && t1[1] != 'l') ||
178      (*t2 && t2[0] != 'l' && t2[1] != 'l'))
179    l = 0;
180
181  if (!r || !l)
182    {
183      /* Skip to message part of tag 1 */
184      m = t1;
185      while (*m && !isspace(*m))
186        m++;
187      while (isspace(*m))
188        m++;
189
190      /* If nothing there, skip to message part of tag 2 */
191      if (!*m)
192        {
193          m = t2;
194          while (*m && !isspace(*m))
195            m++;
196          while (isspace(*m))
197            m++;
198        }
199
200      ans = malloc(4 + strlen(m));
201      sprintf(ans, "%c  %s", r ? 'r' : l ? 'l' : '-', m);
202    }
203  else
204    {
205      ans = malloc(3);
206      strcpy(ans, "rl");
207    }
208  return ans;
209}
210
211void dump_discuss_acl(FILE *out, int lid)
212{
213  struct save_queue *sq = get_acl("LIST", lid, merge_discuss_acls);
214  struct imember *m;
215  char name[STRINGS_STRING_SIZE], *bits;
216  char starbits[8] = { 0 };
217  int num;
218
219  num = 0;
220  while (sq_get_data(sq, &m))
221    {
222      if (m->type != 'S' || !strcmp(m->name, "*"))
223        num++;
224    }
225
226  fprintf(out, "%d\n", num);
227  while (sq_remove_data(sq, &m))
228    {
229      bits = merge_discuss_acls(m->tag, "");
230      if (m->type != 'S')
231        {
232          canon_krb(m, 4, name, sizeof(name));
233          fprintf(out, "%s:%s\n", bits, name);
234        }
235      else if (!strcmp(m->name, "*"))
236        strcpy(starbits, bits);
237      free(bits);
238      freeimember(m);
239    }
240  sq_destroy(sq);
241
242  /* Discuss ACLs are ordered, so "*" must come last. */
243  if (*starbits)
244    fprintf(out, "%s:*\n", starbits);
245}
246
247char *merge_discuss_acls(char *one, char *two)
248{
249  char bits[8];
250
251  sprintf(bits, "%c%c%c%c%c%c%c",
252          strchr(one, 'a') || strchr(two, 'a') ? 'a' : ' ',
253          strchr(one, 'c') || strchr(two, 'c') ? 'c' : ' ',
254          strchr(one, 'd') || strchr(two, 'd') ? 'd' : ' ',
255          strchr(one, 'o') || strchr(two, 'o') ? 'o' : ' ',
256          strchr(one, 'r') || strchr(two, 'r') ? 'r' : ' ',
257          strchr(one, 's') || strchr(two, 's') ? 's' : ' ',
258          strchr(one, 'w') || strchr(two, 'w') ? 'w' : ' ');
259  return strdup(bits);
260}
261
262void dump_passwd_file(FILE *out, int lid)
263{
264  struct save_queue *sq = get_acl("LIST", lid, NULL);
265  struct imember *m;
266  EXEC SQL BEGIN DECLARE SECTION;
267  char shell[USERS_SHELL_SIZE], fullname[USERS_FULLNAME_SIZE];
268  char nickname[USERS_NICKNAME_SIZE], oa[USERS_OFFICE_ADDR_SIZE];
269  char op[USERS_OFFICE_PHONE_SIZE], hp[USERS_HOME_PHONE_SIZE];
270  int uid, i = 0;
271  char *name, *n, *lasts = NULL;
272  EXEC SQL END DECLARE SECTION;
273
274  while (sq_remove_data(sq, &m))
275    {
276      switch (m->type)
277        {
278        case 'U':
279          name = m->name;
280
281          EXEC SQL SELECT unix_uid, shell, fullname, nickname,
282            office_addr, office_phone, home_phone
283            INTO :uid, :shell, :fullname, :nickname, :oa, :op, :hp
284            FROM users
285            WHERE login = :name AND status != 3;
286          if (sqlca.sqlcode)
287            continue;
288
289          strtrim(shell);
290          strtrim(fullname);
291          strtrim(nickname);
292          strtrim(op);
293          strtrim(oa);
294          strtrim(hp);
295
296          fprintf(out, "%s:*:%d:101:%s,%s,%s,%s,%s:/mit/%s:%s\n",
297                  name, uid, fullname, nickname, oa, op, hp, name, shell);
298          break;
299
300        case 'K':
301          name = strtok_r(m->name, "@", &lasts);
302           
303          EXEC SQL SELECT count(login) INTO :i FROM users WHERE
304            login = :name and status != 3;
305          if (i == 1)
306            {
307              EXEC SQL SELECT unix_uid, shell, fullname, nickname,
308                office_addr, office_phone, home_phone
309                INTO :uid, :shell, :fullname, :nickname, :oa, :op, :hp
310                FROM users
311                WHERE login = :name AND status != 3;         
312              if (sqlca.sqlcode)
313                continue;
314             
315              strtrim(shell);
316              strtrim(fullname);
317              strtrim(nickname);
318              strtrim(op);
319              strtrim(oa);
320              strtrim(hp);
321             
322              fprintf(out, "%s:*:%d:101:%s,%s,%s,%s,%s:/mit/%s:%s\n",
323                      name, uid, fullname, nickname, oa, op, hp, name, shell);
324            }
325          break;
326        }
327      freeimember(m);
328    }
329  sq_destroy(sq);
330}
331
332/* This one is a bit weird since we actually look at top-level
333 * lists rather then flattening them.
334 */
335void dump_group_file(FILE *out, int id)
336{
337  EXEC SQL BEGIN DECLARE SECTION;
338  int lid = id, mid, gid, grouplist, i = 0;
339  char mtype[IMEMBERS_MEMBER_TYPE_SIZE], name[LIST_NAME_SIZE];
340  EXEC SQL END DECLARE SECTION;
341  struct save_queue *sq;
342  struct imember *m;
343  char *maybecomma, *s, *n, *lasts = NULL;
344
345  EXEC SQL DECLARE csr_grp CURSOR FOR
346    SELECT member_type, member_id FROM imembers
347    WHERE list_id = :lid AND direct = 1;
348  EXEC SQL OPEN csr_grp;
349  while (1)
350    {
351      EXEC SQL FETCH csr_grp INTO :mtype, :mid;
352      if (sqlca.sqlcode)
353        break;
354
355      switch (*mtype)
356        {
357        case 'L':
358          EXEC SQL SELECT name, gid, grouplist
359            INTO :name, :gid, :grouplist
360            FROM list
361            WHERE list_id = :mid;
362          if (sqlca.sqlcode || !grouplist)
363            break;
364
365          strtrim(name);
366
367          fprintf(out, "%s:*:%d:", name, gid);
368          sq = get_acl("LIST", mid, NULL);
369          maybecomma = "";
370          while (sq_remove_data(sq, &m))
371            {
372              if (m->type == 'U')
373                {
374                  fprintf(out, "%s%s", maybecomma, m->name);
375                  maybecomma = ",";
376                }
377              else if (m->type == 'K')
378                {
379                  n = strtok_r(m->name, "@", &lasts);
380                  EXEC SQL SELECT count(login) INTO :i FROM users
381                    WHERE login = :n and status != 3;
382                  if (i == 1)
383                    {
384                      fprintf(out, "%s%s", maybecomma, n);
385                      maybecomma = ",";
386                    }
387                }
388              freeimember(m);
389            }
390          fprintf(out, "\n");
391          sq_destroy(sq);
392          break;
393        }
394    }
395  EXEC SQL CLOSE csr_grp;
396}
397
398void sqlerr(void)
399{
400  db_error(sqlca.sqlcode);
401  exit(MR_DBMS_ERR);
402}
Note: See TracBrowser for help on using the repository browser.