Skip to content

Commit

Permalink
Add command "mxqset"
Browse files Browse the repository at this point in the history
Add a new command which can be used to modify an existing group.

Examples:

    mxqset group 123 --closed
    mxqset group 123 --open
    mxqset group 123 --blacklist "dontpanic"          # replace
    mxqset group 123 --whitelist "+uselessbox +gula"  # add
    mxqset group 123 --blacklist -dontpanic           # remove
    mxqset group 123 --whitelist ""                   # clear

The flags open and closed can be set from mxqadmin as well
(`mxqadmin --close=123`) , but the synopsis, in which the options take
the groupid as a value is difficult to expand to new options, which take a
value.
donald committed Apr 15, 2020
1 parent b02acb4 commit f03f238
Showing 1 changed file with 245 additions and 0 deletions.
245 changes: 245 additions & 0 deletions mxqset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
#define _GNU_SOURCE
#include <argp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sysexits.h>
#include "mx_mysql.h"
#include "mxq.h"
#include "mxq_group.h"
#include "keywordset.h"
#include "stdarg.h"

static __attribute__ ((noreturn)) void die(char *msg, ...) {
va_list ap;

va_start(ap, msg);
fprintf(stderr, "%s: ",program_invocation_short_name);
vfprintf(stderr, msg, ap);
va_end(ap);
exit(1);
}

static void verify_group_permission(struct mx_mysql *mysql , long unsigned groupid, uid_t client_uid) {
struct mx_mysql_stmt *stmt = NULL;
unsigned long long num_rows;
unsigned uid;

stmt = mx_mysql_statement_prepare(mysql,"SELECT user_uid FROM mxq_group WHERE group_id = ? LIMIT 1");
if (!stmt)
die("%m\n");
mx_mysql_statement_param_bind(stmt, 0, uint64, &(groupid));
if (mx_mysql_statement_execute(stmt, &num_rows) < 0)
die("%m\n");
if (num_rows < 1)
die("no such group %ld\n", groupid);
mx_mysql_statement_result_bind(stmt, 0, uint32, &uid);
if (mx_mysql_statement_fetch(stmt) < 0)
die("%m\n");
if ( client_uid != 0 && client_uid != uid )
die("no permission to access this group\n");
mx_mysql_statement_close(&stmt);
}

enum OPEN_CLOSED {
OPEN_CLOSED_UNSET = 0,
OPEN_CLOSED_CLOSED,
OPEN_CLOSED_OPEN,
};

static void update_closed_flag(struct mx_mysql *mysql, long unsigned groupid, enum OPEN_CLOSED open_closed) {

struct mx_mysql_stmt *stmt = NULL;
unsigned long long num_rows;

uint64_t mask = ~MXQ_GROUP_FLAG_CLOSED;
uint64_t value = open_closed == OPEN_CLOSED_CLOSED ? MXQ_GROUP_FLAG_CLOSED : 0;

stmt = mx_mysql_statement_prepare(mysql,
"UPDATE mxq_group SET group_flags = ( group_flags & ?) | ? WHERE group_id = ?");
if (!stmt)
die("%m\n");
mx_mysql_statement_param_bind(stmt, 0, uint64, &(mask));
mx_mysql_statement_param_bind(stmt, 1, uint64, &(value));
mx_mysql_statement_param_bind(stmt, 2, uint64, &(groupid));
if (mx_mysql_statement_execute(stmt, &num_rows) < 0)
die("%m\n");
if (num_rows < 1)
die("no such group %ld\n", groupid);
mx_mysql_statement_close(&stmt);
}

static void update_blacklist(struct mx_mysql *mysql, long unsigned groupid, char *update_blacklist) {

struct mx_mysql_stmt *stmt = NULL;
unsigned long long num_rows;
char *group_blacklist = NULL;
struct keywordset *blacklist;

if (strcmp(update_blacklist, "") !=0 ) {
stmt = mx_mysql_statement_prepare(mysql,
"SELECT group_blacklist FROM mxq_group WHERE group_id = ? LIMIT 1");
if (!stmt)
die("%m\n");
mx_mysql_statement_param_bind(stmt, 0, uint64, &groupid);
if (mx_mysql_statement_execute(stmt, &num_rows) < 0)
die("%m\n");
if (num_rows < 1)
die("no such group %ld\n", groupid);
mx_mysql_statement_result_bind(stmt, 0, string, &group_blacklist);
if (mx_mysql_statement_fetch(stmt) < 0)
die("%m\n");
mx_mysql_statement_close(&stmt);
blacklist = keywordset_new(group_blacklist);
free(group_blacklist);
} else {
blacklist = keywordset_new(NULL);
}
keywordset_update(blacklist, update_blacklist);

group_blacklist = keywordset_get(blacklist);

stmt = mx_mysql_statement_prepare(mysql,
"UPDATE mxq_group SET group_blacklist = ? WHERE group_id = ?");
if (!stmt)
die("%m\n");
mx_mysql_statement_param_bind(stmt, 0, string, &group_blacklist);
mx_mysql_statement_param_bind(stmt, 1, uint64, &groupid);
if (mx_mysql_statement_execute(stmt, &num_rows) < 0)
die("%m\n");
if (num_rows < 1)
die("no such group %ld\n", groupid);
mx_mysql_statement_close(&stmt);
free(group_blacklist);
keywordset_free(blacklist);
}

static void update_whitelist(struct mx_mysql *mysql, long unsigned groupid, char *update_whitelist) {

struct mx_mysql_stmt *stmt = NULL;
unsigned long long num_rows;
char *group_whitelist = NULL;
struct keywordset *whitelist;

if (strcmp(update_whitelist, "") !=0 ) {
stmt = mx_mysql_statement_prepare(mysql,
"SELECT group_whitelist FROM mxq_group WHERE group_id = ? LIMIT 1");
if (!stmt)
die("%m\n");
mx_mysql_statement_param_bind(stmt, 0, uint64, &groupid);
if (mx_mysql_statement_execute(stmt, &num_rows) < 0)
die("%m\n");
if (num_rows < 1)
die("no such group %ld\n", groupid);
mx_mysql_statement_result_bind(stmt, 0, string, &group_whitelist);
if (mx_mysql_statement_fetch(stmt) < 0)
die("%m\n");
mx_mysql_statement_close(&stmt);
whitelist = keywordset_new(group_whitelist);
free(group_whitelist);
} else {
whitelist = keywordset_new(NULL);
}
keywordset_update(whitelist, update_whitelist);

group_whitelist = keywordset_get(whitelist);

stmt = mx_mysql_statement_prepare(mysql,
"UPDATE mxq_group SET group_whitelist = ? WHERE group_id = ?");
if (!stmt)
die("%m\n");
mx_mysql_statement_param_bind(stmt, 0, string, &group_whitelist);
mx_mysql_statement_param_bind(stmt, 1, uint64, &groupid);
if (mx_mysql_statement_execute(stmt, &num_rows) < 0)
die("%m\n");
if (num_rows < 1)
die("no such group %ld\n", groupid);
mx_mysql_statement_close(&stmt);
free(group_whitelist);
keywordset_free(whitelist);
}

struct opts {
enum OPEN_CLOSED open_closed;
char *update_blacklist;
char *update_whitelist;
};

static error_t parser (int key, char *arg, struct argp_state *state) {
struct opts *opts = state->input;
switch (key) {
case 10:
opts->open_closed = OPEN_CLOSED_CLOSED;
return 0;
case 11:
opts->open_closed = OPEN_CLOSED_OPEN;
return 0;
case 13:
opts->update_blacklist = arg;
return 0;
case 15:
opts->update_whitelist = arg;
return 0;
}
return ARGP_ERR_UNKNOWN;
}

static const struct argp_option options[] = {
{"closed", 10, NULL, 0, NULL},
{"open", 11, NULL, 0, NULL},
{"blacklist", 13, "", 0, NULL},
{"whitelist", 15, "", 0, NULL},
{0}
};

static const struct argp argp = { options, parser, NULL, NULL };

static __attribute__ ((noreturn)) void exit_usage(char *argv0) {
fprintf(stderr,
"usage: %s group GID [group-options]\n"
"\n"
"group options:\n"
"\n"
" --open\n"
" --closed\n"
" --blacklist=STRING\n"
" --whitelist=STRING\n"
,program_invocation_short_name);
exit(EX_USAGE);
}

int main(int argc, char **argv) {

char *argv0=argv[0];
struct mx_mysql *mysql = NULL;
int groupid;
uid_t uid = getuid();

if (argc<3 || strcmp(argv[1],"group") != 0)
exit_usage(argv0);
groupid=atoi(argv[2]);

int sts;
struct opts opts={0};

sts=argp_parse (&argp, argc-3, &argv[3], ARGP_PARSE_ARGV0|ARGP_SILENT, NULL, &opts);
if (sts)
exit_usage(argv0);

assert(mx_mysql_initialize(&mysql) == 0);
mx_mysql_option_set_default_file(mysql, MXQ_MYSQL_DEFAULT_FILE);
mx_mysql_option_set_default_group(mysql, MXQ_MYSQL_DEFAULT_GROUP);
assert(mx_mysql_connect_forever(&mysql) == 0);

verify_group_permission(mysql, groupid, uid);

if ( opts.open_closed != OPEN_CLOSED_UNSET)
update_closed_flag(mysql, groupid, opts.open_closed);
if ( opts.update_blacklist != NULL)
update_blacklist(mysql, groupid, opts.update_blacklist);
if ( opts.update_whitelist != NULL)
update_whitelist(mysql, groupid, opts.update_whitelist);

mx_mysql_finish(&mysql);
}

0 comments on commit f03f238

Please sign in to comment.