From: Martin Mares Date: Mon, 4 Jun 2007 07:44:51 +0000 (+0200) Subject: Added general command code. X-Git-Tag: python-dummy-working~409 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=0b68418072c29bd0d6e32c78f26c104117a5695a;p=moe.git Added general command code. --- diff --git a/submit/Makefile b/submit/Makefile index 847f15e..b5a7c1d 100644 --- a/submit/Makefile +++ b/submit/Makefile @@ -9,8 +9,9 @@ CFLAGS+=-Wno-pointer-sign -Wdisabled-optimization -Wno-missing-field-initializer all: submitd connect -submitd: submitd.o lib/libucw.a lib/libsh.a -submitd.o: submitd.c +submitd: submitd.o commands.o lib/libsh.a lib/libucw.a +submitd.o: submitd.c submitd.h +commands.o: commands.c submitd.h connect: connect.o lib/libucw.a connect.o: connect.c diff --git a/submit/commands.c b/submit/commands.c new file mode 100644 index 0000000..dc71e30 --- /dev/null +++ b/submit/commands.c @@ -0,0 +1,149 @@ +/* + * The Submit Daemon: Processing of Commands + * + * (c) 2007 Martin Mares + */ + +#include "lib/lib.h" +#include "lib/mempool.h" +#include "lib/stkstring.h" +#include "sherlock/object.h" +#include "sherlock/objread.h" + +#include + +#include "submitd.h" + +static void NONRET +read_error_cb(struct obj_read_state *st UNUSED, byte *msg) +{ + client_error("Request parse error: %s", msg); +} + +static int +read_request(struct conn *c) +{ + if (c->pool) + mp_flush(c->pool); + else + c->pool = mp_new(1024); + c->request = obj_new(c->pool); + c->reply = obj_new(c->pool); + + struct obj_read_state st; + obj_read_start(&st, c->request); + st.error_callback = read_error_cb; + byte line[1024]; + uns size = 0; + for (;;) + { + int l = bgets_nodie(&c->rx_fb, line, sizeof(line)); + if (l < 0) + client_error("Request line too long"); + if (!l) + { + if (!size) + return 0; + else + client_error("Truncated request"); + } + if (l == 1) + break; + size += l; + if (size >= max_request_size) + client_error("Request too long"); + obj_read_attr(&st, line[0], line+1); + } + obj_read_end(&st); + return 1; +} + +static void +write_reply(struct conn *c) +{ + if (trace_commands) + { + byte *msg; + if (msg = obj_find_aval(c->reply, '-')) + log(L_DEBUG, ">> -%s", msg); + else if (msg = obj_find_aval(c->reply, '+')) + log(L_DEBUG, ">> +%s", msg); + else + log(L_DEBUG, ">> ???"); + } + put_attr_set_type(BUCKET_TYPE_PLAIN); + bput_object(&c->tx_fb, c->reply); + bputc(&c->tx_fb, '\n'); + bflush(&c->tx_fb); +} + +static void +execute_command(struct conn *c) +{ + byte *cmd = obj_find_aval(c->request, '!'); + if (!cmd) + { + obj_set_attr(c->reply, '-', "Missing command"); + return; + } + if (trace_commands) + log(L_DEBUG, "<< %s", cmd); + obj_set_attr(c->reply, '-', "Unknown command"); +} + +int +process_command(struct conn *c) +{ + if (!read_request(c)) + return 0; + execute_command(c); + write_reply(c); + return 1; +} + +static int +user_exists_p(byte *user) +{ + byte *fn = stk_printf("solutions/%s/status", user); + struct stat st; + return !stat(fn, &st) && S_ISREG(st.st_mode); +} + +static void +execute_init(struct conn *c) +{ + byte *user = obj_find_aval(c->request, 'U'); + if (!user) + { + obj_set_attr(c->reply, '-', "Missing user"); + return; + } + if (!c->cert_name || + !strcmp(user, c->cert_name) || + c->rule->allow_admin && !strcmp(c->cert_name, "admin")) + { + if (!user_exists_p(user)) + { + obj_set_attr(c->reply, '-', "Unknown user"); + return; + } + log(L_INFO, "Logged in %s", user); + } + else + { + obj_set_attr(c->reply, '-', "Permission denied"); + log(L_ERROR, "Unauthorized attempt to log in as %s", user); + return; + } + obj_set_attr(c->reply, '+', "OK"); +} + +int +process_init(struct conn *c) +{ + if (!read_request(c)) + return 0; + execute_init(c); + write_reply(c); + return !!obj_find_attr(c->reply, '+'); +} diff --git a/submit/connect.c b/submit/connect.c index d0c83ff..7f60f6d 100644 --- a/submit/connect.c +++ b/submit/connect.c @@ -156,20 +156,36 @@ int main(int argc UNUSED, char **argv UNUSED) for (;;) { byte buf[1024]; - if (!fgets(buf, sizeof(buf), stdin)) - break; - int len = strlen(buf); - err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send); - err = gnutls_record_recv(s, buf, len); TLS_CHECK(gnutls_record_recv); - if (!err) + do { - log(L_INFO, "Connection closed"); - break; + if (!fgets(buf, sizeof(buf), stdin)) + goto done; + int len = strlen(buf); + err = gnutls_record_send(s, buf, len); TLS_CHECK(gnutls_record_send); } - fwrite(buf, 1, err, stdout); + while (buf[0] != '\n'); + int last = 0; + for (;;) + { + err = gnutls_record_recv(s, buf, sizeof(buf)); TLS_CHECK(gnutls_record_recv); + if (!err) + { + log(L_INFO, "Connection closed"); + break; + } + fwrite(buf, 1, err, stdout); + for (int i=0; i #include @@ -27,8 +25,8 @@ #include #include #include -#include -#include + +#include "submitd.h" /*** CONFIGURATION ***/ @@ -40,14 +38,10 @@ static byte *ca_cert_name = "?"; static byte *server_cert_name = "?"; static byte *server_key_name = "?"; static clist access_rules; - -struct access_rule { - cnode n; - struct ip_addrmask addrmask; - uns allow_admin; - uns plain_text; - uns max_conn; -}; +static uns trace_tls; +uns max_request_size; +uns max_attachment_size; +uns trace_commands; static struct cf_section access_conf = { CF_TYPE(struct access_rule), @@ -74,27 +68,20 @@ static struct cf_section submitd_conf = { CF_UNS("DHBits", &dh_bits), CF_UNS("MaxConn", &max_conn), CF_UNS("SessionTimeout", &session_timeout), + CF_UNS("MaxRequestSize", &max_request_size), + CF_UNS("MaxAttachSize", &max_attachment_size), CF_STRING("CACert", &ca_cert_name), CF_STRING("ServerCert", &server_cert_name), CF_STRING("ServerKey", &server_key_name), CF_LIST("Access", &access_rules, &access_conf), + CF_UNS("TraceTLS", &trace_tls), + CF_UNS("TraceCommands", &trace_commands), CF_END } }; /*** CONNECTIONS ***/ -struct conn { - cnode n; - u32 ip; // Used by the main loop connection logic - pid_t pid; - uns id; - struct access_rule *rule; // Rule matched by this connection - int sk; // Client socket - gnutls_session_t tls; // TLS session - struct fastbuf rx_fb, tx_fb; // Fastbufs for communication with the client -}; - static clist connections; static uns last_conn_id; static uns num_conn; @@ -108,7 +95,7 @@ conn_init(void) static struct conn * conn_new(void) { - struct conn *c = xmalloc(sizeof(*c)); + struct conn *c = xmalloc_zero(sizeof(*c)); c->id = ++last_conn_id; clist_add_tail(&connections, &c->n); num_conn++; @@ -187,8 +174,9 @@ tls_new_session(int sk) } static const char * -tls_verify_cert(gnutls_session_t s) +tls_verify_cert(struct conn *c) { + gnutls_session_t s = c->tls; uns status, num_certs; int err; gnutls_x509_crt_t cert; @@ -223,7 +211,9 @@ tls_verify_cert(gnutls_session_t s) err = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn, &dn_len); if (err < 0) return "Cannot retrieve common name"; - log(L_INFO, "Cert CN: %s", dn); + if (trace_tls) + log(L_INFO, "Cert CN: %s", dn); + c->cert_name = xstrdup(dn); /* Check certificate purpose */ byte purp[256]; @@ -244,8 +234,11 @@ tls_verify_cert(gnutls_session_t s) } static void -tls_log_params(gnutls_session_t s) +tls_log_params(struct conn *c) { + if (!trace_tls) + return; + gnutls_session_t s = c->tls; const char *proto = gnutls_protocol_get_name(gnutls_protocol_get_version(s)); const char *kx = gnutls_kx_get_name(gnutls_kx_get(s)); const char *cert = gnutls_certificate_type_get_name(gnutls_certificate_type_get(s)); @@ -258,7 +251,7 @@ tls_log_params(gnutls_session_t s) /*** SOCKET FASTBUFS ***/ -static void NONRET +void NONRET client_error(char *msg, ...) { va_list args; @@ -383,22 +376,23 @@ client_loop(struct conn *c) int err = gnutls_handshake(c->tls); if (err < 0) client_error("TLS handshake failed: %s", gnutls_strerror(err)); - tls_log_params(c->tls); - const char *cert_err = tls_verify_cert(c->tls); + tls_log_params(c); + const char *cert_err = tls_verify_cert(c); if (cert_err) client_error("TLS certificate failure: %s", cert_err); init_tls_fastbufs(c); } - for (;;) - { - alarm(session_timeout); - byte buf[1024]; - if (!bgets(&c->rx_fb, buf, sizeof(buf))) - break; - bputsn(&c->tx_fb, buf); - bflush(&c->tx_fb); - } + alarm(session_timeout); + if (!process_init(c)) + log(L_ERROR, "Protocol handshake failed"); + else + for (;;) + { + alarm(session_timeout); + if (!process_command(c)) + break; + } if (c->tls) gnutls_bye(c->tls, GNUTLS_SHUT_WR); diff --git a/submit/submitd.h b/submit/submitd.h new file mode 100644 index 0000000..7e0d434 --- /dev/null +++ b/submit/submitd.h @@ -0,0 +1,55 @@ +/* + * The Submit Daemon + * + * (c) 2007 Martin Mares + */ + +#ifndef _SUBMITD_H +#define _SUBMITD_H + +#include "lib/clists.h" +#include "lib/ipaccess.h" +#include "lib/fastbuf.h" + +#include +#include + +struct access_rule { + cnode n; + struct ip_addrmask addrmask; + uns allow_admin; + uns plain_text; + uns max_conn; +}; + +struct conn { + // Set up by the master process + cnode n; + u32 ip; + pid_t pid; + uns id; + struct access_rule *rule; // Rule matched by this connection + int sk; // Client socket + byte *cert_name; // Client name from the certificate (NULL if no TLS) + + // Used by the child process + gnutls_session_t tls; // TLS session + struct fastbuf rx_fb, tx_fb; // Fastbufs for communication with the client (either plain-text or TLS) + struct mempool *pool; + struct odes *request; + struct odes *reply; + byte *user; +}; + +extern uns max_request_size, max_attachment_size, trace_commands; + +/* submitd.c */ + +void NONRET client_error(char *msg, ...); + +/* commands.c */ + +int process_init(struct conn *c); +int process_command(struct conn *c); + +#endif