/* $Id$ * * Utility functions for outputting ACLs * * Copyright (C) 1999 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . */ #include #include #include #include "util.h" #include #include #include #ifdef HAVE_KRB4 #include #else #include #endif #include EXEC SQL INCLUDE sqlca; RCSID("$Header$"); static char *defaultrealm = NULL; static struct hash *users, *strings; static void save_imember(struct save_queue *sq, char *type, int id, char *tag); static struct imember *imember(char type, char *name, char *tag); static struct save_queue *merge_imembers(struct save_queue *sq, char *(merge_func)(char *, char *)); void init_acls(void) { krb5_context context = NULL; int code; users = create_hash(2000); strings = create_hash(2000); code = krb5_init_context(&context); if (code) goto out; code = krb5_get_default_realm(context, &defaultrealm); if (code) goto out; out: if (context) krb5_free_context(context); } void dump_krb_acl(FILE *out, char *type, int id, int vers) { struct save_queue *sq; struct imember *m; char kbuf[MAX_K_NAME_SZ]; sq = get_acl(type, id, NULL); while (sq_remove_data(sq, &m)) { if (m->name == NULL) { fprintf(stderr, "Found string_id with no associated string. Exiting.\n"); exit(MR_DBMS_ERR); } if (m->type != 'S') { canon_krb(m, vers, kbuf, sizeof(kbuf)); fprintf(out, "%s\n", kbuf); } freeimember(m); } sq_destroy(sq); } void canon_krb(struct imember *m, int vers, char *buf, int len) { char *at; char kbuf[MAX_K_NAME_SZ]; switch (m->type) { case 'U': snprintf(buf, len, "%s@%s", m->name, defaultrealm); break; case 'K': /* We assume we have a krb4-style namespace. If we want a krb5 acl, we need to * krb5_425_conv_principal() on it. For krb4, do nothing special. */ at = strchr(m->name, '@'); if (!at) at = strchr(m->name, '\0'); snprintf(kbuf, len, "%s", m->name); if (!*at) { int plen = strlen(kbuf); snprintf(kbuf + plen, len - plen, "@%s", defaultrealm); } if (vers == 5) { char name[ANAME_SZ] = "\0", inst[INST_SZ] = "\0", realm[REALM_SZ] = "\0"; char *kuser = NULL; krb5_context context = NULL; krb5_principal client = NULL; int status = 0; if (mr_kname_parse(name, inst, realm, kbuf) != 0) goto out; status = krb5_init_context(&context); if (status) goto out; status = krb5_425_conv_principal(context, name, inst, realm, &client); if (status) goto out; status = krb5_unparse_name(context, client, &kuser); if (status) goto out; strncpy(buf, kuser, MAX_K_NAME_SZ); buf[MAX_K_NAME_SZ - 1] = '\0'; out: if (kuser) krb5_free_unparsed_name(context, kuser); if (client) krb5_free_principal(context, client); if (context) krb5_free_context(context); } else { /* v4 output, and we should already have added a realm. */ snprintf(buf, len, "%s", kbuf); } break; } } void dump_user_list(FILE *out, char *type, int id) { struct save_queue *sq; struct imember *m; sq = get_acl(type, id, NULL); while (sq_remove_data(sq, &m)) { if (m->type == 'U' || (m->type == 'S' && !strchr(m->name, '@'))) fprintf(out, "%s\n", m->name); freeimember(m); } sq_destroy(sq); } struct save_queue *get_acl(char *type, int id, char *(merge_func)(char *, char *)) { struct save_queue *sq; sq = sq_create(); save_imember(sq, type, id, NULL); return merge_imembers(sq, merge_func); } static void save_imember(struct save_queue *sq, char *type, int id, char *tag) { EXEC SQL BEGIN DECLARE SECTION; int lid = id, mid, mid2, tagid, status; char mtype[IMEMBERS_MEMBER_TYPE_SIZE]; EXEC SQL END DECLARE SECTION; char *mtag; switch (*type) { case 'U': EXEC SQL SELECT status INTO :status FROM users WHERE users_id = :id; if (status != 3) sq_save_data(sq, imember('U', user_lookup(id), tag)); break; case 'K': case 'S': sq_save_data(sq, imember(*type, string_lookup(id), tag)); break; case 'L': EXEC SQL DECLARE csr_acl_mem CURSOR FOR SELECT member_type, member_id, tag FROM imembers WHERE list_id = :lid AND direct = 1; EXEC SQL OPEN csr_acl_mem; while (1) { EXEC SQL FETCH csr_acl_mem INTO :mtype, :mid, :tagid; if (sqlca.sqlcode) break; if (tag) mtag = tag; else mtag = string_lookup(tagid); if (mtype[0] == 'L') { EXEC SQL DECLARE csr_list CURSOR FOR SELECT member_type, member_id FROM imembers WHERE list_id = :mid AND member_type != 'LIST'; EXEC SQL OPEN csr_list; while (1) { EXEC SQL FETCH csr_list INTO :mtype, :mid; if (sqlca.sqlcode) break; save_imember(sq, mtype, mid, mtag); } EXEC SQL CLOSE csr_list; } else save_imember(sq, mtype, mid, mtag); } } } static struct save_queue *merge_imembers(struct save_queue *sq, char *(merge_func)(char *, char *)) { int n; struct imember *m1, *m2; struct save_queue *out; char *t1; out = sq_create(); while (sq_remove_data(sq, &m1)) { while (sq_get_data(sq, &m2)) { if (m1->type == m2->type && !strcmp(m1->name, m2->name)) { sq_remove_last_data(sq); if (merge_func) { t1 = m1->tag; m1->tag = merge_func(m1->tag, m2->tag); free(t1); } freeimember(m2); } } sq_save_data(out, m1); } sq_destroy(sq); return out; } static struct imember *imember(char type, char *name, char *tag) { struct imember *m; m = malloc(sizeof(struct imember)); m->type = type; m->name = name; m->tag = strdup(tag ? tag : ""); return m; } void freeimember(struct imember *m) { free(m->tag); free(m); } char *user_lookup(int users_id) { char *u; u = hash_lookup(users, users_id); if (u) return u; else { EXEC SQL BEGIN DECLARE SECTION; char login[USERS_LOGIN_SIZE]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT login INTO :login FROM users WHERE users_id = :users_id; if (sqlca.sqlcode) return NULL; u = strdup(strtrim(login)); hash_store(users, users_id, u); return u; } } char *string_lookup(int string_id) { char *s; s = hash_lookup(strings, string_id); if (s) return s; else { EXEC SQL BEGIN DECLARE SECTION; char string[STRINGS_STRING_SIZE]; EXEC SQL END DECLARE SECTION; EXEC SQL SELECT string INTO :string FROM strings WHERE string_id = :string_id; if (sqlca.sqlcode) return NULL; s = strdup(strtrim(string)); hash_store(strings, string_id, s); return s; } }