From 8e3761a291f20f12754477e7e05514e1117d2344 Mon Sep 17 00:00:00 2001 From: zacheiss Date: Tue, 3 Dec 2002 21:22:26 +0000 Subject: [PATCH] First cut of mailman support. - New list queries that add mailman and mailman_server arguments. - Don't let non-dbadmin set mailman bit on a list (this will go away when the second tier of features is added). - Add two arguments to end of incremental argv for benefit of mailman.incr. - Make sure the magic mailman administrative lists (foo-admin, foo-request, foo-admin) are treated as reserved if the mailman list foo exists. --- server/increment.pc | 20 ++++-- server/qaccess.pc | 59 +++++++++-------- server/qfollow.pc | 19 ++++-- server/qsetup.pc | 95 ++++++++++++++++++++++++++- server/queries2.c | 152 +++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 296 insertions(+), 49 deletions(-) diff --git a/server/increment.pc b/server/increment.pc index cf30ddda..7f803aee 100644 --- a/server/increment.pc +++ b/server/increment.pc @@ -197,9 +197,15 @@ void incremental_before(enum tables table, char *qual, char **argv) case LIST_TABLE: sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, " "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, " - "l.description, l.list_id FROM list l WHERE %s", qual); + "l.description, l.list_id, l.mailman, l.mailman_id " + "FROM list l WHERE %s", qual); dosql(before); - beforec = 11; + name = xmalloc(0); + id = atoi(before[12]); + id_to_name(id, MACHINE_TABLE, &name); + strcpy(before[12], name); + free(name); + beforec = 13; break; case IMEMBERS_TABLE: id = (int) argv[0]; @@ -380,9 +386,15 @@ void incremental_after(enum tables table, char *qual, char **argv) case LIST_TABLE: sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, " "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, " - "l.description, l.list_id FROM list l WHERE %s", qual); + "l.description, l.list_id, l.mailman, l.mailman_id " + "FROM list l WHERE %s", qual); dosql(after); - afterc = 11; + name = xmalloc(0); + id = atoi(after[12]); + id_to_name(id, MACHINE_TABLE, &name); + strcpy(after[12], name); + free(name); + afterc = 13; break; case IMEMBERS_TABLE: id = (int) argv[0]; diff --git a/server/qaccess.pc b/server/qaccess.pc index dd473bc1..c80e8426 100644 --- a/server/qaccess.pc +++ b/server/qaccess.pc @@ -128,18 +128,18 @@ int access_list(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int list_id, acl_id, flags, gid, users_id, member_id, member_acl_id; - int memacl_id; + int memacl_id, mailman, mailman_id; char acl_type[LIST_ACL_TYPE_SIZE], name[LIST_NAME_SIZE], *newname; char member_acl_type[LIST_ACL_TYPE_SIZE], memacl_type[LIST_ACL_TYPE_SIZE]; EXEC SQL END DECLARE SECTION; - int status; + int status, cnt; list_id = *(int *)argv[0]; member_id = *(int *)argv[2]; EXEC SQL SELECT acl_id, acl_type, memacl_id, memacl_type, - gid, publicflg, name + gid, publicflg, name, mailman, mailman_id INTO :acl_id, :acl_type, :memacl_id, :memacl_type, - :gid, :flags, :name + :gid, :flags, :name, :mailman, :mailman_id FROM list WHERE list_id = :list_id; @@ -163,32 +163,41 @@ int access_list(struct query *q, char *argv[], client *cl) newname = argv[1]; - if (!strcmp("ulis", q->shortname)) - { - /* Check that it doesn't conflict with the Grouper namespace. */ - if (strlen(newname) > 4 && isdigit(newname[2]) && - isdigit(newname[3]) && newname[4] == '-') - { - if (!strncasecmp(newname, "fa", 2) || - !strncasecmp(newname, "sp", 2) || - !strncasecmp(newname, "su", 2) || - !strncasecmp(newname, "ja", 2)) - return MR_RESERVED; - } - - /* Don't let anyone take owner-foo list names. They interact - * weirdly with the aliases automatically generated by - * mailhub.gen. - */ - if (!strncasecmp(newname, "owner-", 6)) - return MR_RESERVED; - } - + /* Check that it doesn't conflict with the Grouper namespace. */ + if (strlen(newname) > 4 && isdigit(newname[2]) && + isdigit(newname[3]) && newname[4] == '-') + { + if (!strncasecmp(newname, "fa", 2) || + !strncasecmp(newname, "sp", 2) || + !strncasecmp(newname, "su", 2) || + !strncasecmp(newname, "ja", 2)) + return MR_RESERVED; + } + + /* Don't let anyone take owner-foo list names. They interact + * weirdly with the aliases automatically generated by + * mailhub.gen. + */ + if (!strncasecmp(newname, "owner-", 6)) + return MR_RESERVED; + EXEC SQL SELECT users_id INTO :users_id FROM users WHERE login = :newname; if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) && (users_id != cl->users_id)) return MR_PERM; + + /* For modern enough clients, don't allow ordinary users to toggle + * the mailman bit or change the server. + */ + if (q->version >= 10) + { + if (mailman != atoi(argv[9])) + return MR_PERM; + + if (mailman_id != *(int *)argv[10]) + return MR_PERM; + } } /* check for client in access control list and return success right diff --git a/server/qfollow.pc b/server/qfollow.pc index 24864e60..3b6becbd 100644 --- a/server/qfollow.pc +++ b/server/qfollow.pc @@ -606,16 +606,21 @@ int followup_glin(struct query *q, struct save_queue *sq, struct validate *v, if (q->version == 2) status = fix_ace(argv[7], &argv[8]); - else + else if (q->version > 2 && q->version < 10) status = fix_ace(argv[8], &argv[9]); + else + status = fix_ace(argv[10], &argv[11]); + + if (status && status != MR_NO_MATCH) + return status; + + if (q->version > 3 && q->version < 10) + status = fix_ace(argv[10], &argv[11]); + else + status = fix_ace(argv[12], &argv[13]); + if (status && status != MR_NO_MATCH) return status; - if (q->version > 3) - { - status = fix_ace(argv[10], &argv[11]); - if (status && status != MR_NO_MATCH) - return status; - } if (atoi(argv[6]) == -1) { diff --git a/server/qsetup.pc b/server/qsetup.pc index 99cd2bbf..24431f9f 100644 --- a/server/qsetup.pc +++ b/server/qsetup.pc @@ -36,6 +36,7 @@ int hostname_check(char *name); int hostinfo_check(char *name, int num); int prefetch_value(struct query *q, char **argv, client *cl); int check_nfs(int mach_idx, char *name, char *access); +int check_mailman_listname(char *name, const char *suffix); /* Setup Routines */ @@ -367,11 +368,11 @@ static int badlistchars[] = { int setup_alis(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; - int ngid, cnt; + int ngid, cnt, mailman, mailman_id; char *name, *desc; EXEC SQL END DECLARE SECTION; unsigned char *p; - int idx, err; + int idx, err, best = -1, usage; if (!strcmp(q->shortname, "alis")) idx = 0; @@ -383,8 +384,10 @@ int setup_alis(struct query *q, char *argv[], client *cl) desc = argv[9 + idx]; else if (q->version == 3) desc = argv[10 + idx]; - else if (q->version >= 4) + else if (q->version == 4) desc = argv[12 + idx]; + else if (q->version >= 10) + desc = argv[14 + idx]; if (idx == 1) { @@ -431,6 +434,68 @@ int setup_alis(struct query *q, char *argv[], client *cl) strcpy(argv[6 + idx], "-1"); } + /* Don't let someone rename a list to one of the magic mailman names + * (foo-admin, etc) if foo already exists as a mailman list. + */ + if ((err = check_mailman_listname(name, "-admin")) != MR_SUCCESS) + return err; + if ((err = check_mailman_listname(name, "-owner")) != MR_SUCCESS) + return err; + if ((err = check_mailman_listname(name, "-request")) != MR_SUCCESS) + return err; + + if (q->version >= 10) + { + /* Don't let them take this name for a mailman list if we can't + * reserve the -admin, -owner, and -request names. + */ + if (atoi(argv[8 + idx])) + { + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE (name = :name || '-admin' OR name = :name || '-owner' OR + name = :name || '-request'); + if (cnt) + return MR_EXISTS; + } + + /* Handle the [ANY] case for mailman server. */ + mailman_id = *(int *)argv[9 + idx]; + if (mailman_id == -1) + { + EXEC SQL DECLARE csr_mailman CURSOR FOR + SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN' + AND enable = 1; + if (dbms_errno) + return mr_errcode; + EXEC SQL OPEN csr_mailman; + if (dbms_errno) + return mr_errcode; + + while (1) + { + EXEC SQL FETCH csr_mailman INTO :mailman_id; + if (sqlca.sqlcode) + break; + + EXEC SQL SELECT COUNT(name) INTO :usage FROM list + WHERE mailman_id = :mailman_id; + + if (best < 0 || usage < best) + { + best = usage; + *(int *)argv[9 + idx] = mailman_id; + break; + } + } + EXEC SQL CLOSE csr_mailman; + if (dbms_errno) + return mr_errcode; + + if (best == -1) + return MR_SERVICE; + } + } + if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS) return mr_errcode; @@ -1473,3 +1538,27 @@ int setup_acon(struct query *q, char *argv[], client *cl) return MR_SUCCESS; } + +int check_mailman_listname(char *name, const char *suffix) +{ + char *p; + EXEC SQL BEGIN DECLARE SECTION; + int i, cnt; + EXEC SQL END DECLARE SECTION; + + p = strstr(name, suffix); + if (p) + { + if (strlen(name) == (p - name + strlen(suffix))) + { + /* list is of the form "name-suffix" */ + i = (p - name); + EXEC SQL SELECT COUNT(name) INTO :cnt FROM list + WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1; + if (cnt > 0) + return MR_EXISTS; + } + } + + return MR_SUCCESS; +} diff --git a/server/queries2.c b/server/queries2.c index 8277ac01..634a401e 100644 --- a/server/queries2.c +++ b/server/queries2.c @@ -1526,13 +1526,20 @@ static char *glin3_fields[] = { "modwith", }; -static char *glin_fields[] = { +static char *glin4_fields[] = { "name", "name", "active", "publicflg", "hidden", "maillist", "grouplist", "gid", "nfsgroup", "ace_type", "ace_name", "memace_type", "memace_name", "description", "modtime", "modby", "modwith", }; +static char *glin_fields[] = { + "name", + "name", "active", "publicflg", "hidden", "maillist", "grouplist", "gid", + "nfsgroup", "mailman", "mailman_server", "ace_type", "ace_name", + "memace_type", "memace_name", "description", "modtime", "modby", "modwith", +}; + static struct validate glin_validate = { 0, 0, @@ -1606,13 +1613,13 @@ static struct validate alis3_validate = { set_modtime, }; -static char *alis_fields[] = { +static char *alis4_fields[] = { "name", "active", "publicflg", "hidden", "maillist", "grouplist", "gid", "nfsgroup", "ace_type", "ace_name", "memace_type", "memace_name", "description", }; -static struct valobj alis_valobj[] = { +static struct valobj alis4_valobj[] = { {V_CHAR, 0, LIST_TABLE, "name"}, {V_NUM, 1}, {V_NUM, 2}, @@ -1628,9 +1635,45 @@ static struct valobj alis_valobj[] = { {V_LEN, 12, LIST_TABLE, "description"}, }; +static struct validate alis4_validate = { + alis4_valobj, + 13, + "name", + "name = '%s'", + 1, + "list_id", + 0, + setup_alis, + set_modtime, +}; + +static char *alis_fields[] = { + "name", "active", "publicflg", "hidden", "maillist", "grouplist", "gid", + "nfsgroup", "mailman", "mailman_server", "ace_type", "ace_name", + "memace_type", "memace_name", "description", +}; + +static struct valobj alis_valobj[] = { + {V_CHAR, 0, LIST_TABLE, "name"}, + {V_NUM, 1}, + {V_NUM, 2}, + {V_NUM, 3}, + {V_NUM, 4}, + {V_NUM, 5}, + {V_NUM, 6}, + {V_NUM, 7}, + {V_NUM, 8}, + {V_ID, 9, MACHINE_TABLE, "name", "mach_id", MR_MACHINE}, + {V_TYPE, 10, 0, "ace_type", 0, MR_ACE}, + {V_TYPEDATA, 11, 0, 0, "list_id", MR_ACE}, + {V_TYPE, 12, 0, "ace_type", 0, MR_ACE}, + {V_TYPEDATA, 13, 0, 0, "list_id", MR_ACE}, + {V_LEN, 14, LIST_TABLE, "description"}, +}; + static struct validate alis_validate = { alis_valobj, - 13, + 15, "name", "name = '%s'", 1, @@ -1705,14 +1748,14 @@ static struct validate ulis3_validate = { set_modtime_by_id, }; -static char *ulis_fields[] = { +static char *ulis4_fields[] = { "name", "newname", "active", "publicflg", "hidden", "maillist", "grouplist", "gid", "nfsgroup", "ace_type", "ace_name", "memace_type", "memace_name", "description", }; -static struct valobj ulis_valobj[] = { +static struct valobj ulis4_valobj[] = { {V_ID, 0, LIST_TABLE, "name", "list_id", MR_LIST}, {V_RENAME, 1, LIST_TABLE, "name", "list_id", MR_NOT_UNIQUE}, {V_NUM, 2}, @@ -1729,9 +1772,47 @@ static struct valobj ulis_valobj[] = { {V_LEN, 13, LIST_TABLE, "description"}, }; +static struct validate ulis4_validate = { + ulis4_valobj, + 14, + "name", + "list_id = %d", + 1, + "list_id", + access_list, + setup_alis, + set_modtime_by_id, +}; + +static char *ulis_fields[] = { + "name", + "newname", "active", "publicflg", "hidden", "maillist", "grouplist", "gid", + "nfsgroup", "mailman", "mailman_server", "ace_type", "ace_name", + "memace_type", "memace_name", "description", +}; + +static struct valobj ulis_valobj[] = { + {V_ID, 0, LIST_TABLE, "name", "list_id", MR_LIST}, + {V_RENAME, 1, LIST_TABLE, "name", "list_id", MR_NOT_UNIQUE}, + {V_NUM, 2}, + {V_NUM, 3}, + {V_NUM, 4}, + {V_NUM, 5}, + {V_NUM, 6}, + {V_NUM, 7}, + {V_NUM, 8}, + {V_NUM, 9}, + {V_ID, 10, MACHINE_TABLE, "name", "mach_id", MR_MACHINE}, + {V_TYPE, 11, 0, "ace_type", 0, MR_ACE}, + {V_TYPEDATA, 12, 0, 0, "list_id", MR_ACE}, + {V_TYPE, 13, 0, "ace_type", 0, MR_ACE}, + {V_TYPEDATA, 14, 0, 0, "list_id", MR_ACE}, + {V_LEN, 15, LIST_TABLE, "description"}, +}; + static struct validate ulis_validate = { ulis_valobj, - 14, + 16, "name", "list_id = %d", 1, @@ -5226,7 +5307,7 @@ struct query Queries[] = { "l", LIST_TABLE, "name, active, publicflg, hidden, maillist, grouplist, gid, nfsgroup, acl_type, acl_id, memacl_type, memacl_id, description, TO_CHAR(modtime, 'DD-mon-YYYY HH24:MI:SS'), modby, modwith FROM list", - glin_fields, + glin4_fields, 16, "name LIKE '%s'", 1, @@ -5234,6 +5315,23 @@ struct query Queries[] = { &glin_validate, }, + { + /* Q_GLIN - GET_LIST_INFO, v10 */ + "get_list_info", + "glin", + 10, + RETRIEVE, + "l", + LIST_TABLE, + "l.name, l.active, l.publicflg, l.hidden, l.maillist, l.grouplist, l.gid, l.nfsgroup, l.mailman, m.name, l.acl_type, l.acl_id, l.memacl_type, l.memacl_id, l.description, TO_CHAR(l.modtime, 'DD-mon-YYYY HH24:MI:SS'), l.modby, l.modwith FROM list l, machine m", + glin_fields, + 18, + "l.name LIKE '%s' AND m.mach_id = l.mailman_id", + 1, + "l.name", + &glin_validate, + }, + { /* Q_EXLN - EXPAND_LIST_NAMES */ "expand_list_names", @@ -5294,11 +5392,28 @@ struct query Queries[] = { "l", LIST_TABLE, "INTO list (name, active, publicflg, hidden, maillist, grouplist, gid, nfsgroup, acl_type, acl_id, memacl_type, memacl_id, description, list_id) VALUES ('%s', %s, %s, %s, %s, %s, %s, %s, '%s', %d, '%s', %d, NVL('%s', CHR(0)), %s)", - alis_fields, + alis4_fields, 13, 0, 0, NULL, + &alis4_validate, + }, + + { + /* Q_ALIS - ADD_LIST, v10 */ /* uses prefetch_value() for list_id */ + "add_list", + "alis", + 10, + APPEND, + "l", + LIST_TABLE, + "INTO list (name, active, publicflg, hidden, maillist, grouplist, gid, nfsgroup, mailman, mailman_id, acl_type, acl_id, memacl_type, memacl_id, description, list_id) VALUES ('%s', %s, %s, %s, %s, %s, %s, %s, %s, %d, '%s', %d, '%s', %d, NVL('%s', CHR(0)), %s)", + alis_fields, + 15, + 0, + 0, + NULL, &alis_validate, }, @@ -5345,11 +5460,28 @@ struct query Queries[] = { "l", LIST_TABLE, "list SET name = '%s', active = %s, publicflg = %s, hidden = %s, maillist = %s, grouplist = %s, gid = %s, nfsgroup = %s, acl_type = '%s', acl_id = %d, memacl_type = '%s', memacl_id = %d, description = NVL('%s', CHR(0))", - ulis_fields, + ulis4_fields, 13, "list_id = %d", 1, NULL, + &ulis4_validate, + }, + + { + /* Q_ULIS, UPDATE_LIST, v10 */ + "update_list", + "ulis", + 10, + UPDATE, + "l", + LIST_TABLE, + "list SET name = '%s', active = %s, publicflg = %s, hidden = %s, maillist = %s, grouplist = %s, gid = %s, nfsgroup = %s, mailman = %s, mailman_id = %d, acl_type = '%s', acl_id = %d, memacl_type = '%s', memacl_id = %d, description = NVL('%s', CHR(0))", + ulis_fields, + 15, + "list_id = %d", + 1, + NULL, &ulis_validate, }, -- 2.45.2