forked from public/pyceo
parent
7de577ab32
commit
ef6b18c7bb
@ -0,0 +1,10 @@ |
||||
/* dmain.c */ |
||||
extern int terminate; |
||||
extern int fatal_signal; |
||||
|
||||
/* dslave.c */ |
||||
void slave_main(int sock, struct sockaddr *addr); |
||||
void setup_slave(void); |
||||
|
||||
/* builtin-adduser.c */ |
||||
extern void builtin_adduser(struct sctp_meta *in, struct sctp_meta *out); |
@ -0,0 +1,173 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <signal.h> |
||||
#include <string.h> |
||||
#include <syslog.h> |
||||
#include <libgen.h> |
||||
#include <getopt.h> |
||||
#include <errno.h> |
||||
#include <netdb.h> |
||||
#include <alloca.h> |
||||
|
||||
#include "util.h" |
||||
#include "net.h" |
||||
#include "config.h" |
||||
#include "gss.h" |
||||
#include "daemon.h" |
||||
#include "ldap.h" |
||||
#include "kadm.h" |
||||
#include "krb5.h" |
||||
#include "ops.h" |
||||
|
||||
static struct option opts[] = { |
||||
{ "detach", 0, NULL, 'd' }, |
||||
{ NULL, 0, NULL, '\0' }, |
||||
}; |
||||
|
||||
char *prog = NULL; |
||||
|
||||
int terminate = 0; |
||||
int fatal_signal; |
||||
|
||||
static int detach = 0; |
||||
|
||||
static void usage() { |
||||
fprintf(stderr, "Usage: %s [--detach]\n", prog); |
||||
exit(2); |
||||
} |
||||
|
||||
static void signal_handler(int sig) { |
||||
if (sig == SIGTERM || sig == SIGINT) { |
||||
const char *s = (sig == SIGTERM) ? "terminated" : "interrupt"; |
||||
notice("shutting down (%s)", s); |
||||
terminate = 1; |
||||
fatal_signal = sig; |
||||
signal(sig, SIG_DFL); |
||||
} else if (sig == SIGSEGV) { |
||||
error("segmentation fault"); |
||||
signal(sig, SIG_DFL); |
||||
raise(sig); |
||||
} else if (sig != SIGCHLD) { |
||||
fatal("unhandled signal %d", sig); |
||||
} |
||||
} |
||||
|
||||
static void setup_signals(void) { |
||||
struct sigaction sa; |
||||
memset(&sa, 0, sizeof(sa)); |
||||
sigemptyset(&sa.sa_mask); |
||||
sa.sa_handler = signal_handler; |
||||
|
||||
sigaction(SIGINT, &sa, NULL); |
||||
sigaction(SIGTERM, &sa, NULL); |
||||
sigaction(SIGSEGV, &sa, NULL); |
||||
|
||||
signal(SIGPIPE, SIG_IGN); |
||||
signal(SIGCHLD, SIG_IGN); |
||||
} |
||||
|
||||
static void setup_daemon(void) { |
||||
if (chdir("/")) |
||||
fatalpe("chdir('/')"); |
||||
if (detach) { |
||||
pid_t pid = fork(); |
||||
if (pid < 0) |
||||
fatalpe("fork"); |
||||
if (pid) |
||||
exit(0); |
||||
if (setsid() < 0) |
||||
fatalpe("setsid"); |
||||
close(STDIN_FILENO); |
||||
close(STDOUT_FILENO); |
||||
close(STDERR_FILENO); |
||||
} |
||||
} |
||||
|
||||
static void setup_auth(void) { |
||||
if (setenv("KRB5CCNAME", "MEMORY:ceod", 1)) |
||||
fatalpe("setenv"); |
||||
server_acquire_creds("ceod"); |
||||
} |
||||
|
||||
static void accept_one_client(int server) { |
||||
struct sockaddr_in addr; |
||||
socklen_t addrlen = sizeof(addr); |
||||
memset(&addr, 0, addrlen); |
||||
|
||||
int client = accept(server, (sa *)&addr, &addrlen); |
||||
if (client < 0) { |
||||
if (errno == EINTR) |
||||
return; |
||||
fatalpe("accept"); |
||||
} |
||||
|
||||
pid_t pid = fork(); |
||||
if (!pid) { |
||||
close(server); |
||||
slave_main(client, (sa *)&addr); |
||||
exit(0); |
||||
} |
||||
|
||||
close(client); |
||||
} |
||||
|
||||
static int master_main(void) { |
||||
int sock; |
||||
struct sockaddr_in addr; |
||||
|
||||
memset(&addr, 0, sizeof(addr)); |
||||
addr.sin_family = AF_INET; |
||||
addr.sin_port = htons(9987); |
||||
addr.sin_addr.s_addr = INADDR_ANY; |
||||
|
||||
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP); |
||||
if (sock < 0) |
||||
fatalpe("socket"); |
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) |
||||
fatalpe("bind"); |
||||
|
||||
if (listen(sock, 128)) |
||||
fatalpe("listen"); |
||||
|
||||
setup_daemon(); |
||||
setup_fqdn(); |
||||
setup_signals(); |
||||
setup_auth(); |
||||
setup_ops(); |
||||
|
||||
notice("now accepting connections"); |
||||
|
||||
while (!terminate) |
||||
accept_one_client(sock); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) { |
||||
int opt; |
||||
|
||||
prog = basename(argv[0]); |
||||
init_log(prog, LOG_PID, LOG_DAEMON); |
||||
|
||||
configure(); |
||||
|
||||
while ((opt = getopt_long(argc, argv, "", opts, NULL)) != -1) { |
||||
switch (opt) { |
||||
case 'd': |
||||
detach = 1; |
||||
break; |
||||
case '?': |
||||
usage(); |
||||
break; |
||||
default: |
||||
fatal("error parsing arguments"); |
||||
} |
||||
} |
||||
|
||||
if (argc != optind) |
||||
usage(); |
||||
|
||||
return master_main(); |
||||
} |
@ -0,0 +1,146 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <signal.h> |
||||
#include <string.h> |
||||
#include <syslog.h> |
||||
#include <libgen.h> |
||||
#include <getopt.h> |
||||
#include <errno.h> |
||||
#include <netdb.h> |
||||
#include <alloca.h> |
||||
|
||||
#include "util.h" |
||||
#include "strbuf.h" |
||||
#include "net.h" |
||||
#include "config.h" |
||||
#include "gss.h" |
||||
#include "daemon.h" |
||||
#include "ldap.h" |
||||
#include "kadm.h" |
||||
#include "krb5.h" |
||||
#include "ops.h" |
||||
|
||||
static void signal_handler(int sig) { |
||||
if (sig == SIGSEGV) { |
||||
error("segmentation fault"); |
||||
signal(sig, SIG_DFL); |
||||
raise(sig); |
||||
} else if (sig != SIGCHLD) { |
||||
fatal("unhandled signal %d", sig); |
||||
} |
||||
} |
||||
|
||||
static void setup_slave_sigs(void) { |
||||
struct sigaction sa; |
||||
memset(&sa, 0, sizeof(sa)); |
||||
sigemptyset(&sa.sa_mask); |
||||
sa.sa_handler = signal_handler; |
||||
|
||||
sigaction(SIGCHLD, &sa, NULL); |
||||
sigaction(SIGSEGV, &sa, NULL); |
||||
|
||||
signal(SIGINT, SIG_DFL); |
||||
signal(SIGTERM, SIG_DFL); |
||||
signal(SIGPIPE, SIG_IGN); |
||||
|
||||
if (terminate) |
||||
raise(fatal_signal); |
||||
} |
||||
|
||||
static void setup_client(int client, struct sockaddr *addr) { |
||||
struct sctp_event_subscribe events; |
||||
memset(&events, 0, sizeof(events)); |
||||
events.sctp_data_io_event = 1; |
||||
events.sctp_address_event = 1; |
||||
events.sctp_send_failure_event = 1; |
||||
events.sctp_peer_error_event = 1; |
||||
events.sctp_partial_delivery_event = 1; |
||||
events.sctp_adaptation_layer_event = 1; |
||||
|
||||
if (setsockopt(client, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events))) |
||||
fatalpe("setsockopt(SCTP_EVENTS)"); |
||||
} |
||||
|
||||
static void handle_auth_message(struct strbuf *in, struct strbuf *out) { |
||||
gss_buffer_desc incoming_tok, outgoing_tok; |
||||
OM_uint32 maj_stat, min_stat; |
||||
|
||||
incoming_tok.value = in->buf; |
||||
incoming_tok.length = in->len; |
||||
|
||||
process_server_token(&incoming_tok, &outgoing_tok); |
||||
|
||||
strbuf_add(out, outgoing_tok.value, outgoing_tok.length); |
||||
|
||||
if (outgoing_tok.length) { |
||||
maj_stat = gss_release_buffer(&min_stat, &outgoing_tok); |
||||
if (maj_stat != GSS_S_COMPLETE) |
||||
gss_fatal("gss_release_buffer", maj_stat, min_stat); |
||||
} |
||||
} |
||||
|
||||
static void handle_op_message(uint32_t in_type, struct strbuf *in, struct strbuf *out) { |
||||
struct op *op = get_local_op(in_type); |
||||
char *envp[16]; |
||||
|
||||
debug("running op: %s", op->name); |
||||
|
||||
if (!op->name) |
||||
fatal("operation %x does not exist", in_type); |
||||
|
||||
make_env(envp, "LANG", "C", "CEO_USER", client_username(), |
||||
"CEO_CONFIG_DIR", config_dir, NULL); |
||||
char *argv[] = { op->path, NULL, }; |
||||
|
||||
if (spawnvem(op->path, argv, envp, in, out, 0)) |
||||
fatal("child %s failed", op->path); |
||||
|
||||
free_env(envp); |
||||
} |
||||
|
||||
static void handle_one_message(int sock, struct sctp_meta *in_meta, struct strbuf *in) { |
||||
struct strbuf out = STRBUF_INIT; |
||||
uint32_t ppid = in_meta->sinfo.sinfo_ppid; |
||||
|
||||
if (ppid == MSG_AUTH) |
||||
handle_auth_message(in, &out); |
||||
else |
||||
handle_op_message(ppid, in, &out); |
||||
|
||||
if (out.len && sctp_sendmsg(sock, out.buf, out.len, |
||||
(sa *)&in_meta->from, in_meta->fromlen, ppid, |
||||
0, 0, 0, 0) < 0) |
||||
fatalpe("sctp_sendmsg"); |
||||
|
||||
strbuf_release(&out); |
||||
} |
||||
|
||||
void slave_main(int sock, struct sockaddr *addr) { |
||||
char addrstr[INET_ADDRSTRLEN]; |
||||
struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; |
||||
struct sctp_meta msg_meta; |
||||
struct strbuf msg = STRBUF_INIT; |
||||
|
||||
if (addr->sa_family != AF_INET) |
||||
fatal("unsupported address family %d", addr->sa_family); |
||||
|
||||
if (!inet_ntop(AF_INET, &addr_in->sin_addr, addrstr, sizeof(addrstr))) |
||||
fatalpe("inet_ntop"); |
||||
|
||||
notice("accepted connection from %s", addrstr); |
||||
|
||||
setup_slave_sigs(); |
||||
setup_client(sock, addr); |
||||
|
||||
while (!terminate) { |
||||
if (!receive_one_message(sock, &msg_meta, &msg)) |
||||
break; |
||||
handle_one_message(sock, &msg_meta, &msg); |
||||
} |
||||
|
||||
notice("connection closed by peer %s", addrstr); |
||||
|
||||
strbuf_release(&msg); |
||||
} |
||||
|
@ -0,0 +1,183 @@ |
||||
#include <string.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <grp.h> |
||||
|
||||
#include "util.h" |
||||
#include "gss.h" |
||||
#include "net.h" |
||||
#include "strbuf.h" |
||||
|
||||
static gss_cred_id_t my_creds = GSS_C_NO_CREDENTIAL; |
||||
static gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; |
||||
static gss_name_t peer_name = GSS_C_NO_NAME; |
||||
static gss_name_t imported_service = GSS_C_NO_NAME; |
||||
static gss_OID mech_type = GSS_C_NO_OID; |
||||
static gss_buffer_desc peer_principal; |
||||
static char *peer_username; |
||||
static OM_uint32 ret_flags; |
||||
static int complete; |
||||
char service_name[128]; |
||||
|
||||
static void display_status(char *prefix, OM_uint32 code, int type) { |
||||
OM_uint32 maj_stat, min_stat; |
||||
gss_buffer_desc msg; |
||||
OM_uint32 msg_ctx = 0; |
||||
|
||||
maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, |
||||
&msg_ctx, &msg); |
||||
logmsg(LOG_ERR, "%s: %s", prefix, (char *)msg.value); |
||||
gss_release_buffer(&min_stat, &msg); |
||||
|
||||
while (msg_ctx) { |
||||
maj_stat = gss_display_status(&min_stat, code, type, GSS_C_NULL_OID, |
||||
&msg_ctx, &msg); |
||||
logmsg(LOG_ERR, "additional: %s", (char *)msg.value); |
||||
gss_release_buffer(&min_stat, &msg); |
||||
} |
||||
} |
||||
|
||||
void gss_fatal(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat) { |
||||
logmsg(LOG_ERR, "fatal: %s", msg); |
||||
display_status("major", maj_stat, GSS_C_GSS_CODE); |
||||
display_status("minor", min_stat, GSS_C_MECH_CODE); |
||||
exit(1); |
||||
} |
||||
|
||||
static void import_service(const char *service, const char *hostname) { |
||||
OM_uint32 maj_stat, min_stat; |
||||
gss_buffer_desc buf_desc; |
||||
|
||||
if (snprintf(service_name, sizeof(service_name), |
||||
"%s@%s", service, hostname) >= sizeof(service_name)) |
||||
fatal("service name too long"); |
||||
|
||||
buf_desc.value = service_name; |
||||
buf_desc.length = strlen(service_name); |
||||
|
||||
maj_stat = gss_import_name(&min_stat, &buf_desc, |
||||
GSS_C_NT_HOSTBASED_SERVICE, &imported_service); |
||||
if (maj_stat != GSS_S_COMPLETE) |
||||
gss_fatal("gss_import_name", maj_stat, min_stat); |
||||
} |
||||
|
||||
static void check_services(OM_uint32 flags) { |
||||
debug("gss services: %sconf %sinteg %smutual %sreplay %ssequence", |
||||
flags & GSS_C_CONF_FLAG ? "+" : "-", |
||||
flags & GSS_C_INTEG_FLAG ? "+" : "-", |
||||
flags & GSS_C_MUTUAL_FLAG ? "+" : "-", |
||||
flags & GSS_C_REPLAY_FLAG ? "+" : "-", |
||||
flags & GSS_C_SEQUENCE_FLAG ? "+" : "-"); |
||||
if (~flags & GSS_C_CONF_FLAG) |
||||
fatal("confidentiality service required"); |
||||
if (~flags & GSS_C_INTEG_FLAG) |
||||
fatal("integrity service required"); |
||||
if (~flags & GSS_C_MUTUAL_FLAG) |
||||
fatal("mutual authentication required"); |
||||
} |
||||
|
||||
void server_acquire_creds(const char *service) { |
||||
OM_uint32 maj_stat, min_stat; |
||||
OM_uint32 time_rec; |
||||
|
||||
if (!strlen(fqdn.buf)) |
||||
fatal("empty fqdn"); |
||||
|
||||
import_service(service, fqdn.buf); |
||||
|
||||
notice("acquiring credentials for %s", service_name); |
||||
|
||||
maj_stat = gss_acquire_cred(&min_stat, imported_service, GSS_C_INDEFINITE, |
||||
GSS_C_NULL_OID_SET, GSS_C_ACCEPT, &my_creds, |
||||
NULL, &time_rec); |
||||
if (maj_stat != GSS_S_COMPLETE) |
||||
gss_fatal("gss_acquire_cred", maj_stat, min_stat); |
||||
|
||||
if (time_rec != GSS_C_INDEFINITE) |
||||
fatal("credentials valid for %d seconds (oops)", time_rec); |
||||
} |
||||
|
||||
void client_acquire_creds(const char *service, const char *hostname) { |
||||
import_service(service, hostname); |
||||
} |
||||
|
||||
int process_server_token(gss_buffer_t incoming_tok, gss_buffer_t outgoing_tok) { |
||||
OM_uint32 maj_stat, min_stat; |
||||
OM_uint32 time_rec; |
||||
gss_OID name_type; |
||||
|
||||
if (complete) |
||||
fatal("unexpected %zd-byte token from peer", incoming_tok->length); |
||||
|
||||
maj_stat = gss_accept_sec_context(&min_stat, &context_handle, my_creds, |
||||
incoming_tok, GSS_C_NO_CHANNEL_BINDINGS, &peer_name, &mech_type, |
||||
outgoing_tok, &ret_flags, &time_rec, NULL); |
||||
if (maj_stat == GSS_S_COMPLETE) { |
||||
check_services(ret_flags); |
||||
|
||||
complete = 1; |
||||
|
||||
maj_stat = gss_display_name(&min_stat, peer_name, &peer_principal, &name_type); |
||||
if (maj_stat != GSS_S_COMPLETE) |
||||
gss_fatal("gss_display_name", maj_stat, min_stat); |
||||
|
||||
notice("client authenticated as %s", (char *)peer_principal.value); |
||||
debug("context expires in %d seconds",time_rec); |
||||
|
||||
} else if (maj_stat != GSS_S_CONTINUE_NEEDED) { |
||||
gss_fatal("gss_accept_sec_context", maj_stat, min_stat); |
||||
} |
||||
|
||||
return complete; |
||||
} |
||||
|
||||
int process_client_token(gss_buffer_t incoming_tok, gss_buffer_t outgoing_tok) { |
||||
OM_uint32 maj_stat, min_stat; |
||||
OM_uint32 time_rec; |
||||
gss_OID_desc krb5 = *gss_mech_krb5; |
||||
|
||||
if (complete) |
||||
fatal("unexpected token from peer"); |
||||
|
||||
maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context_handle, |
||||
imported_service, &krb5, GSS_C_MUTUAL_FLAG | |
||||
GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG, |
||||
GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, |
||||
incoming_tok, NULL, outgoing_tok, &ret_flags, |
||||
&time_rec); |
||||
if (maj_stat == GSS_S_COMPLETE) { |
||||
notice("server authenticated as %s", service_name); |
||||
notice("context expires in %d seconds", time_rec); |
||||
|
||||
check_services(ret_flags); |
||||
|
||||
complete = 1; |
||||
|
||||
} else if (maj_stat != GSS_S_CONTINUE_NEEDED) { |
||||
gss_fatal("gss_init_sec_context", maj_stat, min_stat); |
||||
} |
||||
|
||||
return complete; |
||||
} |
||||
|
||||
int initial_client_token(gss_buffer_t outgoing_tok) { |
||||
return process_client_token(GSS_C_NO_BUFFER, outgoing_tok); |
||||
} |
||||
|
||||
char *client_principal(void) { |
||||
return complete ? (char *)peer_principal.value : NULL; |
||||
} |
||||
|
||||
char *client_username(void) { |
||||
if (!peer_username) { |
||||
char *princ = client_principal(); |
||||
if (princ) { |
||||
peer_username = xstrdup(princ); |
||||
char *c = strchr(peer_username, '@'); |
||||
if (c) |
||||
*c = '\0'; |
||||
} |
||||
} |
||||
return peer_username; |
||||
} |
||||
|
@ -0,0 +1,11 @@ |
||||
#include <gssapi/gssapi.h> |
||||
#include <gssapi/gssapi_krb5.h> |
||||
|
||||
void server_acquire_creds(const char *service); |
||||
void client_acquire_creds(const char *service, const char *hostname); |
||||
void gss_fatal(char *msg, OM_uint32 maj_stat, OM_uint32 min_stat); |
||||
int process_server_token(gss_buffer_t incoming_tok, gss_buffer_t outgoing_tok); |
||||
int process_client_token(gss_buffer_t incoming_tok, gss_buffer_t outgoing_tok); |
||||
int initial_client_token(gss_buffer_t outgoing_tok); |
||||
char *client_principal(void); |
||||
char *client_username(void); |
@ -0,0 +1,141 @@ |
||||
#include <stdio.h> |
||||
#include <sys/utsname.h> |
||||
#include <unistd.h> |
||||
#include <netdb.h> |
||||
|
||||
#include "util.h" |
||||
#include "net.h" |
||||
#include "gss.h" |
||||
#include "strbuf.h" |
||||
|
||||
struct strbuf fqdn = STRBUF_INIT; |
||||
|
||||
const size_t MAX_MSGLEN = 65536; |
||||
const size_t MSG_BUFINC = 4096; |
||||
|
||||
void setup_fqdn(void) { |
||||
struct utsname uts; |
||||
struct hostent *lo; |
||||
|
||||
if (uname(&uts)) |
||||
fatalpe("uname"); |
||||
lo = gethostbyname(uts.nodename); |
||||
if (!lo) |
||||
fatalpe("gethostbyname"); |
||||
|
||||
strbuf_addstr(&fqdn, lo->h_name); |
||||
} |
||||
|
||||
static size_t recv_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg, int *notification) { |
||||
size_t len = 0; |
||||
int flags; |
||||
int bytes; |
||||
|
||||
strbuf_reset(msg); |
||||
|
||||
do { |
||||
msg_meta->fromlen = sizeof(msg_meta->from); |
||||
|
||||
bytes = sctp_recvmsg(sock, msg->buf + len, strbuf_avail(msg) - len, |
||||
(sa *)&msg_meta->from, &msg_meta->fromlen, &msg_meta->sinfo, &flags); |
||||
|
||||
if (bytes < 0) |
||||
fatalpe("sctp_recvmsg"); |
||||
if (!bytes) |
||||
break; |
||||
len += bytes; |
||||
|
||||
if (msg->len > MAX_MSGLEN) |
||||
fatal("oversized message received"); |
||||
if (strbuf_avail(msg) < MSG_BUFINC) |
||||
strbuf_grow(msg, MSG_BUFINC); |
||||
|
||||
} while (~flags & MSG_EOR); |
||||
|
||||
if (!bytes && len) |
||||
fatalpe("EOF in the middle of a message"); |
||||
|
||||
*notification = flags & MSG_NOTIFICATION; |
||||
if (*notification) |
||||
notification_dbg(msg->buf); |
||||
|
||||
strbuf_setlen(msg, len); |
||||
return len; |
||||
} |
||||
|
||||
int receive_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg) { |
||||
int notification = 0; |
||||
|
||||
do { |
||||
recv_one_message(sock, msg_meta, msg, ¬ification); |
||||
} while (notification); |
||||
|
||||
return msg->len > 0; |
||||
} |
||||
|
||||
void notification_dbg(char *notification) { |
||||
union sctp_notification *sn = (union sctp_notification *) notification; |
||||
char *extra; |
||||
|
||||
switch (sn->sn_header.sn_type) { |
||||
case SCTP_ASSOC_CHANGE: |
||||
extra = "unknown state"; |
||||
switch (sn->sn_assoc_change.sac_state) { |
||||
case SCTP_COMM_UP: extra = "established"; break; |
||||
case SCTP_COMM_LOST: extra = "lost"; break; |
||||
case SCTP_RESTART: extra = "restarted"; break; |
||||
case SCTP_SHUTDOWN_COMP: extra = "completed shutdown"; break; |
||||
case SCTP_CANT_STR_ASSOC: extra = "cannot start"; break; |
||||
} |
||||
debug("association changed: association 0x%x %s", sn->sn_assoc_change.sac_assoc_id, extra); |
||||
break; |
||||
case SCTP_PEER_ADDR_CHANGE: |
||||
extra = "unknown state"; |
||||
switch (sn->sn_paddr_change.spc_state) { |
||||
case SCTP_ADDR_AVAILABLE: extra = "unavailable"; break; |
||||
case SCTP_ADDR_UNREACHABLE: extra = "unreachable"; break; |
||||
case SCTP_ADDR_REMOVED: extra = "removed"; break; |
||||
case SCTP_ADDR_ADDED: extra = "added"; break; |
||||
case SCTP_ADDR_MADE_PRIM: extra = "made primary"; break; |
||||
#ifdef SCTP_ADDR_CONFIRMED |
||||
case SCTP_ADDR_CONFIRMED: extra = "confirmed"; break; |
||||
#endif |
||||
} |
||||
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *) &sn->sn_paddr_change.spc_aaddr; |
||||
char addr[INET_ADDRSTRLEN]; |
||||
inet_ntop(AF_INET, &sa->sin_addr, addr, sizeof(addr)); |
||||
debug("peer address change: remote address %s %s", addr, extra); |
||||
break; |
||||
case SCTP_REMOTE_ERROR: |
||||
debug("remote error: association=0x%x error=0x%x", |
||||
sn->sn_remote_error.sre_assoc_id, |
||||
sn->sn_remote_error.sre_error); |
||||
break; |
||||
case SCTP_SEND_FAILED: |
||||
debug("send failed: association=0x%x error=0x%x", |
||||
sn->sn_send_failed.ssf_assoc_id, |
||||
sn->sn_send_failed.ssf_error); |
||||
break; |
||||
case SCTP_ADAPTATION_INDICATION: |
||||
debug("adaptation indication: 0x%x", |
||||
sn->sn_adaptation_event.sai_adaptation_ind); |
||||
break; |
||||
case SCTP_PARTIAL_DELIVERY_EVENT: |
||||
extra = "unknown indication"; |
||||
switch (sn->sn_pdapi_event.pdapi_indication) { |
||||
case SCTP_PARTIAL_DELIVERY_ABORTED: |
||||
extra = "partial delivery aborted"; |
||||
break; |
||||
} |
||||
debug("partial delivery event: %s", extra); |
||||
break; |
||||
case SCTP_SHUTDOWN_EVENT: |
||||
debug("association 0x%x was shut down", |
||||
sn->sn_shutdown_event.sse_assoc_id); |
||||
break; |
||||
default: |
||||
debug("unknown sctp notification type 0x%x\n", |
||||
sn->sn_header.sn_type); |
||||
} |
||||
} |
@ -0,0 +1,45 @@ |
||||
#include <sys/types.h> |
||||
#include <sys/socket.h> |
||||
#include <netinet/in.h> |
||||
#include <netinet/sctp.h> |
||||
#include <arpa/inet.h> |
||||
#include <gssapi/gssapi.h> |
||||
|
||||
#if ! defined(SCTP_ADDR_CONFIRMED) && defined(__linux__) |
||||
#define SCTP_ADDR_CONFIRMED 5 |
||||
#endif |
||||
|
||||
void notification_dbg(char *); |
||||
|
||||
#ifdef SCTP_ADAPTION_LAYER |
||||
#define sctp_adaptation_layer_event sctp_adaption_layer_event |
||||
#define sn_adaptation_event sn_adaption_event |
||||
#define sai_adaptation_ind sai_adaption_ind |
||||
#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTION_INDICATION |
||||
#endif |
||||
|
||||
typedef struct sockaddr sa; |
||||
|
||||
extern struct strbuf fqdn; |
||||
extern void setup_fqdn(void); |
||||
|
||||
struct sctp_meta { |
||||
struct sockaddr_storage from; |
||||
socklen_t fromlen; |
||||
struct sctp_sndrcvinfo sinfo; |
||||
}; |
||||
|
||||
enum { |
||||
MSG_AUTH = 0x8000000, |
||||
MSG_EXPLODE = 0x8000001, |
||||
}; |
||||
|
||||
#ifdef MSG_ABORT |
||||
#define SCTP_ABORT MSG_ABORT |
||||
#define SCTP_EOF MSG_EOF |
||||
#endif |
||||
|
||||
#define EKERB -2 |
||||
#define ELDAP -3 |
||||
|
||||
int receive_one_message(int sock, struct sctp_meta *msg_meta, struct strbuf *msg); |
@ -0,0 +1,110 @@ |
||||
#include <errno.h> |
||||
#include <inttypes.h> |
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
#include <netdb.h> |
||||
|
||||
#include "strbuf.h" |
||||
#include "ops.h" |
||||
#include "net.h" |
||||
#include "util.h" |
||||
#include "config.h" |
||||
|
||||
static struct op *ops; |
||||
|
||||
static const char *default_op_dir = "/usr/lib/ceod"; |
||||
static const char *op_dir; |
||||
|
||||
static void add_op(char *host, char *name, uint32_t id) { |
||||
struct op *new = xmalloc(sizeof(struct op)); |
||||
errno = 0; |
||||
new->next = ops; |
||||
new->name = xstrdup(name); |
||||
new->id = id; |
||||
new->path = NULL; |
||||
|
||||
struct hostent *hostent = gethostbyname(host); |
||||
if (!hostent) |
||||
badconf("cannot add op %s: %s: %s", name, host, hstrerror(h_errno)); |
||||
new->hostname = strdup(hostent->h_name); |
||||
new->local = !strcmp(fqdn.buf, hostent->h_name); |
||||
new->addr = *(struct in_addr *)hostent->h_addr_list[0]; |
||||
|
||||
if (new->local) { |
||||
new->path = xmalloc(strlen(op_dir) + strlen("/op-") + strlen(name) + 1); |
||||
sprintf(new->path, "%s/op-%s", op_dir, name); |
||||
if (access(new->path, X_OK)) |
||||
fatalpe("cannot add op: %s: %s", name, new->path); |
||||
} |
||||
|
||||
ops = new; |
||||
debug("added op %s (%s%s)", new->name, new->local ? "" : "on ", |
||||
new->local ? "local" : host); |
||||
} |
||||
|
||||
struct op *get_local_op(uint32_t id) { |
||||
for (struct op *op = ops; op; op = op->next) { |
||||
if (op->local && op->id == id) |
||||
return op; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
struct op *find_op(const char *name) { |
||||
for (struct op *op = ops; op; op = op->next) { |
||||
if (!strcmp(name, op->name)) |
||||
return op; |
||||
} |
||||
return NULL; |
||||
} |
||||
|
||||
void setup_ops(void) { |
||||
char op_config_dir[1024]; |
||||
DIR *dp; |
||||
struct dirent *de; |
||||
struct strbuf line = STRBUF_INIT; |
||||
unsigned lineno = 0; |
||||
unsigned op_count = 0; |
||||
|
||||
op_dir = getenv("CEO_LIB_DIR") ?: default_op_dir; |
||||
|
||||
if (snprintf(op_config_dir, sizeof(op_config_dir), "%s/%s", config_dir, "ops.d") >= sizeof(op_config_dir)) |
||||
fatal("ops dir path too long"); |
||||
|
||||
dp = opendir(op_config_dir); |
||||
if (!dp) |
||||
fatalpe("opendir: %s", op_config_dir); |
||||
|
||||
while ((de = readdir(dp))) { |
||||
FILE *fp = fopenat(dp, de->d_name, O_RDONLY); |
||||
if (!fp) |
||||
warnpe("open: %s/%s", op_config_dir, de->d_name); |
||||
while (strbuf_getline(&line, fp, '\n') != EOF) { |
||||
lineno++; |
||||
strbuf_trim(&line); |
||||
|
||||
if (!line.len || line.buf[0] == '#') |
||||
continue; |
||||
|
||||
struct strbuf **words = strbuf_splitws(&line); |
||||
|
||||
if (strbuf_list_len(words) != 3) |
||||
badconf("%s/%s: expected three words on line %d", op_config_dir, de->d_name, lineno); |
||||
|
||||
errno = 0; |
||||
char *end; |
||||
int id = strtol(words[2]->buf, &end, 0); |
||||
if (errno || *end) |
||||
badconf("%s/%s: invalid id '%s' on line %d", op_config_dir, de->d_name, words[2]->buf, lineno); |
||||
|
||||
add_op(words[0]->buf, words[1]->buf, id); |
||||
op_count++; |
||||
|
||||
strbuf_list_free(words); |
||||
} |
||||
} |
||||
|
||||
closedir(dp); |
||||
strbuf_release(&line); |
||||
} |
||||
|
@ -0,0 +1,13 @@ |
||||
struct op { |
||||
char *name; |
||||
uint32_t id; |
||||
int local; |
||||
char *hostname; |
||||
char *path; |
||||
struct in_addr addr; |
||||
struct op *next; |
||||
}; |
||||
|
||||
void setup_ops(void); |
||||
struct op *find_op(const char *name); |
||||
struct op *get_local_op(uint32_t id); |
Loading…
Reference in new issue