Add mysql database stuff
[public/pyceo-broken.git] / src / dslave.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <signal.h>
5 #include <string.h>
6 #include <syslog.h>
7 #include <libgen.h>
8 #include <getopt.h>
9 #include <errno.h>
10 #include <netdb.h>
11 #include <alloca.h>
12
13 #include "util.h"
14 #include "strbuf.h"
15 #include "net.h"
16 #include "config.h"
17 #include "gss.h"
18 #include "daemon.h"
19 #include "ldap.h"
20 #include "kadm.h"
21 #include "krb5.h"
22 #include "ops.h"
23
24 static void signal_handler(int sig) {
25     if (sig == SIGSEGV) {
26         error("segmentation fault");
27         signal(sig, SIG_DFL);
28         raise(sig);
29     } else if (sig != SIGCHLD) {
30         fatal("unhandled signal %d", sig);
31     }
32 }
33
34 static void setup_slave_sigs(void) {
35     struct sigaction sa;
36     memset(&sa, 0, sizeof(sa));
37     sigemptyset(&sa.sa_mask);
38     sa.sa_handler = signal_handler;
39
40     sigaction(SIGCHLD, &sa, NULL);
41     sigaction(SIGSEGV, &sa, NULL);
42
43     signal(SIGINT,  SIG_DFL);
44     signal(SIGTERM, SIG_DFL);
45     signal(SIGPIPE, SIG_IGN);
46
47     if (terminate)
48         raise(fatal_signal);
49 }
50
51 static void setup_client(int client, struct sockaddr *addr) {
52     struct sctp_event_subscribe events;
53     memset(&events, 0, sizeof(events));
54     events.sctp_data_io_event = 1;
55     events.sctp_address_event = 1;
56     events.sctp_send_failure_event = 1;
57     events.sctp_peer_error_event = 1;
58     events.sctp_partial_delivery_event = 1;
59     events.sctp_adaptation_layer_event = 1;
60
61     if (setsockopt(client, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events)))
62         fatalpe("setsockopt(SCTP_EVENTS)");
63 }
64
65 static void handle_auth_message(struct strbuf *in, struct strbuf *out) {
66     gss_buffer_desc incoming_tok, outgoing_tok;
67     OM_uint32 maj_stat, min_stat;
68
69     incoming_tok.value = in->buf;
70     incoming_tok.length = in->len;
71
72     process_server_token(&incoming_tok, &outgoing_tok);
73
74     strbuf_add(out, outgoing_tok.value, outgoing_tok.length);
75
76     if (outgoing_tok.length) {
77         maj_stat = gss_release_buffer(&min_stat, &outgoing_tok);
78         if (maj_stat != GSS_S_COMPLETE)
79             gss_fatal("gss_release_buffer", maj_stat, min_stat);
80     }
81 }
82
83 static void handle_op_message(uint32_t in_type, struct strbuf *in, struct strbuf *out) {
84     struct op *op = get_local_op(in_type);
85     char *envp[16];
86
87     debug("running op: %s", op->name);
88
89     if (!op->name)
90         fatal("operation %x does not exist", in_type);
91
92     /* TEMPORARY */
93     if (!client_username())
94         fatal("unathenticated");
95
96     make_env(envp, "LANG", "C", "CEO_USER", client_username(),
97                    "CEO_CONFIG_DIR", config_dir, NULL);
98     char *argv[] = { op->path, NULL, };
99
100     if (spawnvemu(op->path, argv, envp, in, out, 0, op->user))
101         fatal("child %s failed", op->path);
102
103     if (!out->len)
104         fatal("no response from op");
105
106     free_env(envp);
107 }
108
109 static void handle_one_message(int sock, struct sctp_meta *in_meta, struct strbuf *in) {
110     struct strbuf out = STRBUF_INIT;
111     uint32_t ppid = in_meta->sinfo.sinfo_ppid;
112
113     if (ppid == MSG_AUTH)
114         handle_auth_message(in, &out);
115     else
116         handle_op_message(ppid, in, &out);
117
118     if (out.len && sctp_sendmsg(sock, out.buf, out.len,
119                 (sa *)&in_meta->from, in_meta->fromlen, ppid,
120                 0, 0, 0, 0) < 0)
121         fatalpe("sctp_sendmsg");
122
123     strbuf_release(&out);
124 }
125
126 void slave_main(int sock, struct sockaddr *addr) {
127     char addrstr[INET_ADDRSTRLEN];
128     struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
129     struct sctp_meta msg_meta;
130     struct strbuf msg = STRBUF_INIT;
131
132     if (addr->sa_family != AF_INET)
133         fatal("unsupported address family %d", addr->sa_family);
134
135     if (!inet_ntop(AF_INET, &addr_in->sin_addr, addrstr, sizeof(addrstr)))
136         fatalpe("inet_ntop");
137
138     notice("accepted connection from %s", addrstr);
139
140     setup_slave_sigs();
141     setup_client(sock, addr);
142
143     while (!terminate) {
144         if (!receive_one_message(sock, &msg_meta, &msg))
145             break;
146         handle_one_message(sock, &msg_meta, &msg);
147     }
148
149     notice("connection closed by peer %s", addrstr);
150
151     strbuf_release(&msg);
152
153     /* stuff allocated by dmaster */
154     free_gss();
155     free_config();
156     free_fqdn();
157     free_ops();
158     free(prog);
159 }
160