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

Revision 24319, 9.3 KB checked in by broder, 15 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: acl.pc 3956 2010-01-05 20:56:56Z zacheiss $
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
26EXEC SQL INCLUDE sqlca;
27
28RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/gen/acl.pc $ $Id: acl.pc 3956 2010-01-05 20:56:56Z zacheiss $");
29
30char *whoami = "acl.gen";
31char *db = "moira/moira";
32
33void dump_access_file(FILE *out, int lid);
34char *merge_access_bits(char *t1, char *t2);
35void dump_discuss_acl(FILE *out, int lid);
36void dump_passwd_file(FILE *out, int lid);
37void dump_group_file(FILE *out, int id);
38char *merge_discuss_acls(char *one, char *two);
39void sqlerr(void);
40
41int 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
134void 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
169char *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
212void 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
248char *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
263void 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 */
336void 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
399void sqlerr(void)
400{
401  db_error(sqlca.sqlcode);
402  exit(MR_DBMS_ERR);
403}
Note: See TracBrowser for help on using the repository browser.