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

Revision 24319, 6.9 KB checked in by broder, 14 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: genacl.pc 3956 2010-01-05 20:56:56Z zacheiss $
2 *
3 * Utility functions for outputting ACLs
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 <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#ifdef HAVE_KRB4
20#include <krb.h>
21#else
22#include <mr_krb.h>
23#endif
24#include <krb5.h>
25
26EXEC SQL INCLUDE sqlca;
27
28RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/gen/genacl.pc $ $Id: genacl.pc 3956 2010-01-05 20:56:56Z zacheiss $");
29
30static char *defaultrealm = NULL;
31
32static struct hash *users, *strings;
33
34static void save_imember(struct save_queue *sq, char *type, int id, char *tag);
35static struct imember *imember(char type, char *name, char *tag);
36static struct save_queue *merge_imembers(struct save_queue *sq,
37                                         char *(merge_func)(char *, char *));
38
39void init_acls(void)
40{
41  krb5_context context = NULL;
42  int code;
43
44  users = create_hash(2000);
45  strings = create_hash(2000);
46
47  code = krb5_init_context(&context);
48  if (code)
49    goto out;
50
51  code = krb5_get_default_realm(context, &defaultrealm);
52  if (code)
53    goto out;
54
55 out:
56  if (context)
57    krb5_free_context(context);
58}
59
60void dump_krb_acl(FILE *out, char *type, int id, int vers)
61{
62  struct save_queue *sq;
63  struct imember *m;
64  char kbuf[MAX_K_NAME_SZ];
65
66  sq = get_acl(type, id, NULL);
67  while (sq_remove_data(sq, &m))
68    {
69      if (m->name == NULL)
70        {
71          fprintf(stderr, "Found string_id with no associated string.  Exiting.\n");
72          exit(MR_DBMS_ERR);
73        }
74      if (m->type != 'S')
75        {
76          canon_krb(m, vers, kbuf, sizeof(kbuf));
77          fprintf(out, "%s\n", kbuf);
78        }
79      freeimember(m);
80    }
81  sq_destroy(sq);
82}
83
84void canon_krb(struct imember *m, int vers, char *buf, int len)
85{
86  char *at;
87  char kbuf[MAX_K_NAME_SZ];
88
89  switch (m->type)
90    {
91    case 'U':
92      snprintf(buf, len, "%s@%s", m->name, defaultrealm);
93      break;
94
95    case 'K':
96      /* We assume we have a krb4-style namespace.  If we want a krb5 acl, we need to
97       * krb5_425_conv_principal() on it. For krb4, do nothing special.
98       */
99      at = strchr(m->name, '@');
100      if (!at)
101        at = strchr(m->name, '\0');
102      snprintf(kbuf, len, "%s", m->name);
103
104      if (!*at)
105        {
106          int plen = strlen(kbuf);
107          snprintf(kbuf + plen, len - plen, "@%s", defaultrealm);
108        }
109
110      if (vers == 5)
111        {
112          char name[ANAME_SZ] = "\0", inst[INST_SZ] = "\0", realm[REALM_SZ] = "\0";
113          char *kuser = NULL;
114          krb5_context context = NULL;
115          krb5_principal client = NULL;
116          int status = 0;
117
118          if (mr_kname_parse(name, inst, realm, kbuf) != 0)
119            goto out;
120
121          status = krb5_init_context(&context);
122          if (status)
123            goto out;
124
125          status = krb5_425_conv_principal(context, name, inst, realm, &client);
126          if (status)
127            goto out;
128
129          status = krb5_unparse_name(context, client, &kuser);
130          if (status)
131            goto out;
132
133          strncpy(buf, kuser, MAX_K_NAME_SZ);
134          buf[MAX_K_NAME_SZ - 1] = '\0';
135
136        out:
137          if (kuser)
138            krb5_free_unparsed_name(context, kuser);
139          if (client)
140            krb5_free_principal(context, client);
141          if (context)
142            krb5_free_context(context);
143        }
144      else
145        {
146          /* v4 output, and we should already have added a realm. */
147          snprintf(buf, len, "%s", kbuf);
148        }
149      break;
150    }
151}
152
153void dump_user_list(FILE *out, char *type, int id)
154{
155  struct save_queue *sq;
156  struct imember *m;
157
158  sq = get_acl(type, id, NULL);
159  while (sq_remove_data(sq, &m))
160    {
161      if (m->type == 'U' || (m->type == 'S' && !strchr(m->name, '@')))
162        fprintf(out, "%s\n", m->name);
163      freeimember(m);
164    }
165  sq_destroy(sq);
166}
167
168struct save_queue *get_acl(char *type, int id,
169                           char *(merge_func)(char *, char *))
170{
171  struct save_queue *sq;
172
173  sq = sq_create();
174  save_imember(sq, type, id, NULL);
175  return merge_imembers(sq, merge_func);
176}
177
178static void save_imember(struct save_queue *sq, char *type, int id, char *tag)
179{
180  EXEC SQL BEGIN DECLARE SECTION;
181  int lid = id, mid, mid2, tagid, status;
182  char mtype[IMEMBERS_MEMBER_TYPE_SIZE];
183  EXEC SQL END DECLARE SECTION;
184  char *mtag;
185
186  switch (*type)
187    {
188    case 'U':
189      EXEC SQL SELECT status INTO :status FROM users WHERE users_id = :id;
190      if (status != 3)
191        sq_save_data(sq, imember('U', user_lookup(id), tag));
192      break;
193
194    case 'K':
195    case 'S':
196      sq_save_data(sq, imember(*type, string_lookup(id), tag));
197      break;
198
199    case 'L':
200      EXEC SQL DECLARE csr_acl_mem CURSOR FOR
201        SELECT member_type, member_id, tag FROM imembers
202        WHERE list_id = :lid AND direct = 1;
203      EXEC SQL OPEN csr_acl_mem;
204      while (1)
205        {
206          EXEC SQL FETCH csr_acl_mem INTO :mtype, :mid, :tagid;
207          if (sqlca.sqlcode)
208            break;
209
210          if (tag)
211            mtag = tag;
212          else
213            mtag = string_lookup(tagid);
214          if (mtype[0] == 'L')
215            {
216              EXEC SQL DECLARE csr_list CURSOR FOR
217                SELECT member_type, member_id FROM imembers
218                WHERE list_id = :mid AND member_type != 'LIST';
219              EXEC SQL OPEN csr_list;
220              while (1)
221                {
222                  EXEC SQL FETCH csr_list INTO :mtype, :mid;
223                  if (sqlca.sqlcode)
224                    break;
225
226                  save_imember(sq, mtype, mid, mtag);
227                }
228              EXEC SQL CLOSE csr_list;
229            }
230          else
231            save_imember(sq, mtype, mid, mtag);
232        }
233    }
234}
235
236static struct save_queue *merge_imembers(struct save_queue *sq,
237                                         char *(merge_func)(char *, char *))
238{
239  int n;
240  struct imember *m1, *m2;
241  struct save_queue *out;
242  char *t1;
243
244  out = sq_create();
245  while (sq_remove_data(sq, &m1))
246    {
247      while (sq_get_data(sq, &m2))
248        {
249          if (m1->type == m2->type && !strcmp(m1->name, m2->name))
250            {
251              sq_remove_last_data(sq);
252              if (merge_func)
253                {
254                  t1 = m1->tag;
255                  m1->tag = merge_func(m1->tag, m2->tag);
256                  free(t1);
257                }
258              freeimember(m2);
259            }
260        }
261      sq_save_data(out, m1);
262    }
263  sq_destroy(sq);
264  return out;
265
266
267static struct imember *imember(char type, char *name, char *tag)
268{
269  struct imember *m;
270  m = malloc(sizeof(struct imember));
271  m->type = type;
272  m->name = name;
273  m->tag = strdup(tag ? tag : "");
274  return m;
275}
276
277void freeimember(struct imember *m)
278{
279  free(m->tag);
280  free(m);
281}
282
283char *user_lookup(int users_id)
284{
285  char *u;
286
287  u = hash_lookup(users, users_id);
288  if (u)
289    return u;
290  else
291    {
292      EXEC SQL BEGIN DECLARE SECTION;
293      char login[USERS_LOGIN_SIZE];
294      EXEC SQL END DECLARE SECTION;
295
296      EXEC SQL SELECT login INTO :login FROM users
297        WHERE users_id = :users_id;
298      if (sqlca.sqlcode)
299        return NULL;
300
301      u = strdup(strtrim(login));
302      hash_store(users, users_id, u);
303      return u;
304    }
305}
306
307char *string_lookup(int string_id)
308{
309  char *s;
310
311  s = hash_lookup(strings, string_id);
312  if (s)
313    return s;
314  else
315    {
316      EXEC SQL BEGIN DECLARE SECTION;
317      char string[STRINGS_STRING_SIZE];
318      EXEC SQL END DECLARE SECTION;
319
320      EXEC SQL SELECT string INTO :string FROM strings
321        WHERE string_id = :string_id;
322      if (sqlca.sqlcode)
323        return NULL;
324
325      s = strdup(strtrim(string));
326      hash_store(strings, string_id, s);
327      return s;
328    }
329}
Note: See TracBrowser for help on using the repository browser.