summaryrefslogtreecommitdiffstats
path: root/contrib/bind/bin/irpd/irpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind/bin/irpd/irpd.c')
-rw-r--r--contrib/bind/bin/irpd/irpd.c2252
1 files changed, 2252 insertions, 0 deletions
diff --git a/contrib/bind/bin/irpd/irpd.c b/contrib/bind/bin/irpd/irpd.c
new file mode 100644
index 0000000..a2b13cb
--- /dev/null
+++ b/contrib/bind/bin/irpd/irpd.c
@@ -0,0 +1,2252 @@
+/*
+ * Copyright(c) 1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/* Notes. */
+
+#if 0
+
+I have to use an AF_INET. Ctl_server should probably take a AF arugment.
+
+The server has no way to issue any other greeting than HELLO. E.g., would
+like to be able to drop connection on greeting if client is not comming
+from 127.0.0.1.
+
+Need to fix client to handle response with body.
+
+should add iovec with body to the struct ctl_sess?
+
+should we close connections on some errors (like marshalling errors)?
+
+getnetbyname falls back to /etc/networks when named not running. Does not
+seem to be so for getnetbyaddr
+
+#endif
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$Id: irpd.c,v 1.7 1999/10/13 16:26:23 vixie Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+/* Imports. */
+
+#include "port_before.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <utmp.h>
+
+#ifdef EMPTY
+/* Digital UNIX utmp.h defines this. */
+#undef EMPTY
+#endif
+
+#include <isc/ctl.h>
+#include <isc/assertions.h>
+#include <isc/list.h>
+#include <isc/memcluster.h>
+#include <isc/logging.h>
+
+#include <irs.h>
+#include <irp.h>
+#include <isc/irpmarshall.h>
+#include <irs_data.h>
+
+#include "port_after.h"
+
+/* Macros. */
+
+#define ALLDIGITS(s) (strspn((s), "0123456789") == strlen((s)))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+#define MAXNETNAMELEN 256
+
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof (*(su)) - sizeof ((su)->sun_path) + strlen((su)->sun_path))
+#endif
+
+/*
+ * This macro is used to initialize a specified field of a net_data struct.
+ * If the initialization fails then an error response code is sent with a
+ * description of which field failed to be initialized.
+ *
+ * This is only meant for use at the start of the various verb functions.
+ */
+
+#define ND_INIT(nd, field, sess, respcode) \
+ do{ if ((nd)->field == 0) { \
+ (nd)->field = (*(nd)->irs->field ## _map)(nd->irs); \
+ if ((nd)->field == 0) { \
+ char *msg = "net_data " #field " initialization failed"; \
+ ctl_response(sess, respcode, msg, CTL_EXIT, NULL, \
+ NULL, NULL, NULL, 0); \
+ return; \
+ } \
+ } \
+ } while (0)
+
+/* Data structures. */
+
+struct arg_s {
+ struct iovec * iov;
+ int iovlen;
+};
+
+struct response_buff {
+ char * buff;
+ size_t bufflen;
+};
+
+struct client_ctx {
+ struct net_data * net_data;
+};
+
+/* Forwards. */
+
+static struct response_buff *newbuffer(u_int length);
+static void release_buffer(struct response_buff *b);
+static struct arg_s *split_string(const char *string);
+static void free_args(struct arg_s *args);
+static int is_all_digits(char *p);
+static struct client_ctx *make_cli_ctx(void);
+static struct net_data *get_net_data(struct ctl_sess *sess);
+
+static void irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getservbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getprotobynumber(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+static void irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx);
+
+static void irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ void *param);
+static void response_done(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ void *uap);
+static void logger(enum ctl_severity, const char *fmt, ...);
+
+/* Constants. */
+
+static const u_int hello_code = IRPD_WELCOME_CODE;
+static const char hello_msg[] = "Welcome to IRPD (v 1)";
+static const u_int unkncode = 500;
+static const u_int timeoutcode = 501;
+static const u_int irpd_quit_ok = 201;
+static const u_int timeout = IRPD_TIMEOUT;
+
+/* Globals. */
+
+static int main_needs_exit = 0;
+static evContext ev;
+
+struct ctl_verb verbs [] = {
+ { "gethostbyname", irpd_gethostbyname },
+ { "gethostbyname2", irpd_gethostbyname2 },
+ { "gethostbyaddr", irpd_gethostbyaddr },
+ { "gethostent", irpd_gethostent },
+ { "sethostent", irpd_sethostent },
+#ifdef WANT_IRS_PW
+ { "getpwnam", irpd_getpwnam },
+ { "getpwuid", irpd_getpwuid },
+ { "getpwent", irpd_getpwent },
+ { "setpwent", irpd_setpwent },
+#endif
+ { "getnetbyname", irpd_getnetbyname },
+ { "getnetbyaddr", irpd_getnetbyaddr },
+ { "getnetent", irpd_getnetent },
+ { "setnetent", irpd_setnetent },
+#ifdef WANT_IRS_GR
+ { "getgrnam", irpd_getgrnam },
+ { "getgrgid", irpd_getgrgid },
+ { "getgrent", irpd_getgrent },
+ { "setgrent", irpd_setgrent },
+#endif
+ { "getservbyname", irpd_getservbyname },
+ { "getservbyport", irpd_getservbyport },
+ { "getservent", irpd_getservent },
+ { "setservent", irpd_setservent },
+
+ { "getprotobyname", irpd_getprotobyname },
+ { "getprotobynumber", irpd_getprotobynumber },
+ { "getprotoent", irpd_getprotoent },
+ { "setprotoent", irpd_setprotoent },
+
+ { "getnetgrent", irpd_getnetgrent },
+ { "innetgr", irpd_innetgr },
+ { "setnetgrent", irpd_setnetgrent },
+ { "endnetgrent", irpd_endnetgrent },
+ { "quit", irpd_quit },
+ { "help", irpd_help },
+
+ { "", irpd_accept }, /* For connection setups. */
+
+ /* abort is a verb expected by the ctl library. Is called when the
+ * client drops the connection unexpectedly.
+ */
+ { "abort", irpd_abort },
+
+ { NULL, NULL }
+};
+
+/*
+ * An empty string causes the library to use the compiled in
+ * defaults and to ignore any external files.
+ */
+char *conffile = "";
+
+/* Public. */
+
+int
+main(int argc, char **argv) {
+ struct ctl_sctx *ctx;
+ struct sockaddr *addr;
+ struct sockaddr_un uaddr;
+ struct sockaddr_in iaddr;
+ log_channel chan;
+ short port = IRPD_PORT;
+ char *prog = argv[0];
+ char *sockname = IRPD_PATH;
+ char *p;
+ int ch;
+ size_t socksize;
+
+ addr = (struct sockaddr *)&iaddr;
+ socksize = sizeof iaddr;
+
+ openlog("iprd", LOG_CONS|LOG_PID, LOG_DAEMON);
+ while ((ch = getopt(argc, argv, "u:p:c:")) != -1) {
+ switch(ch) {
+ case 'c':
+ conffile = optarg;
+ break;
+
+ case 'p':
+ port = strtol(optarg, &p, 10);
+ if (*p != '\0') {
+ /* junk in argument */
+ syslog(LOG_ERR, "port option not a number");
+ exit(1);
+ }
+ break;
+
+ case 'u':
+ sockname = optarg;
+ addr = (struct sockaddr *)&uaddr;
+ socksize = sizeof uaddr;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ fprintf(stderr, "%s [ -c config-file ]\n", prog);
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ memset(&uaddr, 0, sizeof uaddr);
+ memset(&iaddr, 0, sizeof iaddr);
+
+#ifdef HAVE_SA_LEN
+ iaddr.sin_len = sizeof iaddr;
+#endif
+ iaddr.sin_family = AF_INET;
+ iaddr.sin_port = htons(IRPD_PORT);
+ iaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ uaddr.sun_family = AF_UNIX;
+ strncpy(uaddr.sun_path, sockname, sizeof uaddr.sun_path);
+#ifdef HAVE_SA_LEN
+ uaddr.sun_len = SUN_LEN(&uaddr);
+#endif
+
+ if (addr == (struct sockaddr *)&uaddr)
+ socksize = SUN_LEN(&uaddr);
+
+ /* XXX what if this file is not currently a socket? */
+ unlink(sockname);
+
+ evCreate(&ev);
+
+ ctx = ctl_server(ev, addr, socksize, verbs,
+ unkncode, timeoutcode, /* IRPD_TIMEOUT */ 30, 5,
+ IRPD_MAXSESS, logger, NULL);
+
+ INSIST(ctx != NULL);
+
+ while (!main_needs_exit) {
+ evEvent event;
+
+ INSIST_ERR(evGetNext(ev, &event, EV_WAIT) != -1);
+ INSIST_ERR(evDispatch(ev, event) != -1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * static void
+ * simple_response(struct ctl_sess *sess, u_int code, char *msg);
+ * Send back a simple, one-line response to the client.
+ */
+static void
+simple_response(struct ctl_sess *sess, u_int code, char *msg) {
+ struct response_buff *b = newbuffer(strlen(msg) + 1);
+
+ if (b == 0)
+ return;
+ strcpy(b->buff, msg);
+ ctl_response(sess, code, b->buff, 0, 0, response_done, b, NULL, 0);
+}
+
+/*
+ * static void
+ * send_hostent(struct ctl_sess *sess, struct hostent *ho);
+ * Send a hostent struct over the wire. If HO is NULL, then
+ * a "No such host" is sent instead.
+ */
+static void
+send_hostent(struct ctl_sess *sess, struct hostent *ho) {
+ if (ho == NULL)
+ simple_response(sess, IRPD_GETHOST_NONE, "No such host");
+ else {
+ size_t need;
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_ho(ho, &b->buff, &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Internal error");
+ logger(ctl_warning,
+ "Cannot marshall host data for %s\n",
+ ho->h_name);
+ release_buffer(b);
+ } else {
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETHOST_OK, "Host found",
+ 0, 0, response_done,
+ b, b->buff, strlen(b->buff));
+ }
+ }
+}
+
+/*
+ * static void
+ * do_gethostbyname2(struct ctl_sess *sess, struct net_data *nd,
+ * const char *hostname, int af);
+ * Look up the given HOSTNAME by Address-Family
+ * and then send the results to the client connected to
+ * SESS.
+ */
+static void
+do_gethostbyname2(struct ctl_sess *sess, struct net_data *nd,
+ const char *hostname, int af)
+{
+ struct hostent *ho;
+
+ ho = gethostbyname2_p(hostname, af, nd);
+ send_hostent(sess, ho);
+}
+
+/*
+ * static void
+ * irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTBYNAME verb.
+ */
+static void
+irpd_gethostbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char hname[MAXHOSTNAMELEN];
+ struct arg_s *args;
+ int i;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Incorrect usage: GETHOSTBYNAME hostname");
+ } else {
+ if (args->iov[0].iov_len >= sizeof hname) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "GETHOSTBYNAME: name too long");
+ } else {
+ strncpy(hname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ hname[args->iov[0].iov_len] = '\0';
+ do_gethostbyname2(sess, netdata, hname, AF_INET);
+ }
+ }
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTBYNAME2 verb.
+ */
+static void
+irpd_gethostbyname2(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char hname[MAXHOSTNAMELEN];
+ struct arg_s *args;
+ int i;
+ int af;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Incorrect usage: GETHOSTBYNAME2 hostname AF");
+ } else if (args->iov[0].iov_len >= sizeof hname) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "GETHOSTBYNAME2: name too long");
+ } else {
+ if (strncasecmp(args->iov[1].iov_base, "af_inet6", 8) == 0)
+ af = AF_INET6;
+ else if (strncasecmp(args->iov[1].iov_base, "af_inet", 7) == 0)
+ af = AF_INET;
+ else {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Unknown address family");
+ goto untimely;
+ }
+
+ strncpy(hname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ hname[args->iov[0].iov_len] = '\0';
+ do_gethostbyname2(sess, netdata, hname, af);
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTBYADDR verb.
+ */
+static void
+irpd_gethostbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct hostent *ho;
+ char haddr[MAXHOSTNAMELEN];
+ char tmpaddr[NS_IN6ADDRSZ];
+ struct arg_s *args;
+ int i;
+ int af;
+ int addrlen;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "GETHOSTBYADDR addr afamily");
+ } else {
+ if (args->iov[0].iov_len >= sizeof haddr) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Address too long");
+ } else {
+ strncpy(haddr, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ haddr[args->iov[1].iov_len] = '\0';
+ if (strcasecmp(haddr, "af_inet") == 0) {
+ af = AF_INET;
+ addrlen = NS_INADDRSZ;
+ } else if (strcasecmp(haddr, "af_inet6") == 0) {
+ af = AF_INET6;
+ addrlen = NS_IN6ADDRSZ;
+ } else {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Unknown address family");
+ goto untimely;
+ }
+
+ strncpy(haddr, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ haddr[args->iov[0].iov_len] = '\0';
+
+ if (inet_pton(af, haddr, tmpaddr) != 1) {
+ simple_response(sess, IRPD_GETHOST_ERROR,
+ "Invalid address");
+ goto untimely;
+ }
+
+ ho = gethostbyaddr_p(tmpaddr, addrlen, af, netdata);
+ send_hostent(sess, ho);
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+
+/*
+ * static void
+ * irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETHOSTENT verb
+ */
+static void
+irpd_gethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct hostent *ho;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ ho = gethostent_p(netdata);
+
+ send_hostent(sess, ho);
+}
+
+/*
+ * static void
+ * irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the SETHOSTENT verb
+ */
+static void
+irpd_sethostent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct hostent *ho;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ho, sess, IRPD_GETHOST_ERROR);
+
+ sethostent_p(1, netdata); /* always stayopen */
+ simple_response(sess, IRPD_GETHOST_SETOK, "ok");
+}
+
+#ifdef WANT_IRS_PW
+/*
+ * static void
+ * send_pwent(struct ctl_sess *sess, struct passwd *pw);
+ * Send PW over the wire, or, if PW is NULL, a "No such
+ * user" response.
+ */
+static void
+send_pwent(struct ctl_sess *sess, struct passwd *pw) {
+ if (pw == NULL) {
+ simple_response(sess, IRPD_GETUSER_NONE,
+ "No such user");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_pw(pw, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall pw\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETUSER_OK, "User found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETPWNAM verb
+ */
+static void
+irpd_getpwnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct passwd *pw;
+ char username[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "GETPWNAM username");
+ } else {
+ if (args->iov[0].iov_len >= sizeof username) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Name too long");
+ } else {
+ strncpy(username, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ username[args->iov[0].iov_len] = '\0';
+
+ pw = getpwnam_p(username, netdata);
+ send_pwent(sess, pw);
+ }
+ }
+
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETPWUID verb.
+ */
+static void
+irpd_getpwuid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct passwd *pw;
+ char userid[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "GETPWUID uid");
+ } else {
+ if (args->iov[0].iov_len >= sizeof userid) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Name too long");
+ } else {
+ strncpy(userid, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ userid[args->iov[0].iov_len] = '\0';
+
+ if (!ALLDIGITS(userid)) {
+ simple_response(sess, IRPD_GETUSER_ERROR,
+ "Not a uid");
+ } else {
+ uid_t uid;
+ long lval;
+
+ lval = strtol(userid, 0, 10);
+ uid = (uid_t)lval;
+ if ((long)uid != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETUSER_ERROR,
+ "Not a valid uid");
+ goto untimely;
+ }
+
+ pw = getpwuid_p(uid, netdata);
+ send_pwent(sess, pw);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implemtnation of the GETPWENT verb.
+ */
+static void
+irpd_getpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct passwd *pw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ pw = getpwent_p(netdata);
+ send_pwent(sess, pw);
+}
+
+/*
+ * static void
+ * irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implemtnation of the SETPWENT verb.
+ */
+static void
+irpd_setpwent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct passwd *pw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pw, sess, IRPD_GETUSER_ERROR);
+
+ setpwent_p(netdata);
+ simple_response(sess, IRPD_GETUSER_SETOK, "ok");
+}
+#endif /* WANT_IRS_PW */
+
+/*
+ * static void
+ * send_nwent(struct ctl_sess *sess, struct nwent *ne);
+ * Sends a nwent structure over the wire, or "No such
+ * network" if NE is NULL.
+ */
+static void
+send_nwent(struct ctl_sess *sess, struct nwent *nw) {
+ if (nw == NULL) {
+ simple_response(sess, IRPD_GETNET_NONE, "No such net");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_nw(nw, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall nw\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETNET_OK, "Network found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * send_netent(struct ctl_sess *sess, struct netent *ne);
+ * Sends a NETENT structure over the wire, or "No such
+ * Network" error if NE is NULL.
+ */
+static void
+send_netent(struct ctl_sess *sess, struct netent *ne) {
+ if (ne == NULL) {
+ simple_response(sess, IRPD_GETNET_NONE, "No such net");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_ne(ne, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall ne\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETNET_OK, "Network found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of GETNETBYNAME verb.
+ */
+static void
+irpd_getnetbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct netent *ne;
+ struct nwent *nw;
+ char netname[MAXNETNAMELEN];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "GETNETBYNAME name");
+ } else {
+ if (args->iov[0].iov_len >= sizeof netname) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Name too long");
+ } else {
+ strncpy(netname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ netname[args->iov[0].iov_len] = '\0';
+
+ ne = getnetbyname_p(netname, netdata);
+
+ /* The public interface only gives us a struct
+ netent, and we need a struct nwent that irs uses
+ internally, so we go dig it out ourselves. Yuk
+ */
+ nw = NULL;
+ if (ne != NULL) {
+ /* Puke. */
+ INSIST(netdata->nw_last == ne);
+ nw = netdata->nww_last;
+ }
+
+ send_nwent(sess, nw);
+ }
+ }
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ */
+static void
+irpd_getnetbyaddr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct netent *ne;
+ struct nwent *nw;
+ char haddr[MAXHOSTNAMELEN];
+ long tmpaddr;
+ struct arg_s *args;
+ int i;
+ int af;
+ int addrlen;
+ int bits;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETUSER_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "GETNETBYADDR addr afamily");
+ } else {
+ if (args->iov[0].iov_len >= sizeof haddr) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Address too long");
+ } else {
+ strncpy(haddr, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ haddr[args->iov[1].iov_len] = '\0';
+ if (strcasecmp(haddr, "af_inet") == 0) {
+ af = AF_INET;
+ addrlen = NS_INADDRSZ;
+ } else if (strcasecmp(haddr, "af_inet6") == 0) {
+ af = AF_INET6;
+ addrlen = NS_IN6ADDRSZ;
+
+ /* XXX the interface we use(getnetbyaddr)
+ * can't handle AF_INET6, so for now we
+ * bail.
+ */
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "AF_INET6 unsupported");
+ goto untimely;
+ } else {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Unknown address family");
+ goto untimely;
+ }
+
+ strncpy(haddr, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ haddr[args->iov[0].iov_len] = '\0';
+
+ bits = inet_net_pton(af, haddr,
+ &tmpaddr, sizeof tmpaddr);
+ if (bits < 0) {
+ simple_response(sess, IRPD_GETNET_ERROR,
+ "Invalid address");
+ goto untimely;
+ }
+
+ ne = getnetbyaddr_p(tmpaddr, af, netdata);
+
+ /* The public interface only gives us a struct
+ netent, and we need a struct nwent that irs uses
+ internally, so we go dig it out ourselves. Yuk
+ */
+ nw = NULL;
+ if (ne != NULL) {
+ /* Puke puke */
+ INSIST(netdata->nw_last == ne);
+ nw = netdata->nww_last;
+ }
+
+ send_nwent(sess, nw);
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+
+/*
+ * static void
+ * irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETNETENT verb.
+ */
+static void
+irpd_getnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct netent *ne;
+ struct nwent *nw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR);
+
+ ne = getnetent_p(netdata);
+ nw = NULL;
+ if (ne != NULL) {
+ /* triple puke */
+ INSIST(netdata->nw_last == ne);
+ nw = netdata->nww_last;
+ }
+ send_nwent(sess, nw);
+}
+
+/*
+ * static void
+ * irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the SETNETENT verb.
+ */
+static void
+irpd_setnetent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct netent *ne;
+ struct nwent *nw;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, nw, sess, IRPD_GETNET_ERROR);
+
+ setnetent_p(1, netdata); /* always stayopen */
+ simple_response(sess, IRPD_GETNET_SETOK, "ok");
+}
+
+#ifdef WANT_IRS_GR
+/*
+ * static void
+ * send_grent(struct ctl_sess *sess, struct group *gr);
+ * Marshall GR and send as body of response. If GR is NULL
+ * then a "No such group" response is sent instead.
+ */
+static void
+send_grent(struct ctl_sess *sess, struct group *gr) {
+ if (gr == NULL) {
+ simple_response(sess, IRPD_GETGROUP_NONE,
+ "No such user");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_gr(gr, &b->buff, &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall gr\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETGROUP_OK, "Group found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETGRNAM verb.
+ */
+static void
+irpd_getgrnam(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct group *gr;
+ char groupname[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "GETGRNAM groupname");
+ } else {
+ if (args->iov[0].iov_len >= sizeof groupname) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Name too long");
+ } else {
+ strncpy(groupname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ groupname[args->iov[0].iov_len] = '\0';
+
+ gr = getgrnam_p(groupname, netdata);
+ send_grent(sess, gr);
+ }
+ }
+
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implentation of the GETGRGID verb.
+ */
+static void
+irpd_getgrgid(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct group *gr;
+ char groupid[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "GETGRUID gid");
+ } else {
+ if (args->iov[0].iov_len >= sizeof groupid) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Name too long");
+ } else {
+ strncpy(groupid, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ groupid[args->iov[0].iov_len] = '\0';
+
+ if (!ALLDIGITS(groupid)) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Not a gid");
+ } else {
+ gid_t gid;
+ long lval;
+
+ lval = strtol(groupid, 0, 10);
+ gid = (gid_t)lval;
+ if ((long)gid != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETGROUP_ERROR,
+ "Not a valid gid");
+ goto untimely;
+ }
+
+ gr = getgrgid_p(gid, netdata);
+ send_grent(sess, gr);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the GETGRENT verb.
+ */
+static void
+irpd_getgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct group *gr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ gr = getgrent_p(netdata);
+ send_grent(sess, gr);
+}
+
+/*
+ * static void
+ * irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Implementation of the SETGRENT verb.
+ */
+static void
+irpd_setgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct group *gr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, gr, sess, IRPD_GETGROUP_ERROR);
+
+ setgrent_p(netdata);
+ simple_response(sess, IRPD_GETGROUP_SETOK, "ok");
+}
+#endif /* WANT_IRS_GR */
+
+static void
+send_servent(struct ctl_sess *sess, struct servent *serv) {
+ if (serv == NULL) {
+ simple_response(sess, IRPD_GETSERVICE_NONE,
+ "No such service");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_sv(serv, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall servent\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETSERVICE_OK, "Service found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+static void
+irpd_getservbyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct servent *serv;
+ char servicename[64];
+ char protoname[10];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "GETSERVNAM servicename protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof servicename) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid service name");
+ } else if (args->iov[1].iov_len >= sizeof protoname) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid protocol name");
+ } else {
+ strncpy(servicename, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ servicename[args->iov[0].iov_len] = '\0';
+
+ strncpy(protoname, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ protoname[args->iov[1].iov_len] = '\0';
+
+ serv = getservbyname_p(servicename, protoname,
+ netdata);
+ send_servent(sess, serv);
+ }
+ }
+
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETSERVBYPORT verb.
+ */
+static void
+irpd_getservbyport(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct servent *sv;
+ char portnum[64];
+ char protoname[10];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "GETSERVBYPORT port protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof portnum) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid port");
+ } else if (args->iov[1].iov_len > sizeof protoname - 1) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Invalid protocol");
+ } else {
+ strncpy(portnum, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ portnum[args->iov[0].iov_len] = '\0';
+
+ strncpy(protoname, args->iov[1].iov_base,
+ args->iov[1].iov_len);
+ protoname[args->iov[1].iov_len] = '\0';
+
+ if (!ALLDIGITS(portnum)) {
+ simple_response(sess, IRPD_GETSERVICE_ERROR,
+ "Not a port number");
+ } else {
+ short port;
+ long lval;
+
+ lval = strtol(portnum, 0, 10);
+ port = (short)lval;
+ if ((long)port != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETSERVICE_ERROR,
+ "Not a valid port");
+ goto untimely;
+ }
+ port = htons(port);
+
+ sv = getservbyport_p(port, protoname, netdata);
+ send_servent(sess, sv);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETSERVENT verb.
+ */
+static void
+irpd_getservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct servent *sv;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ sv = getservent_p(netdata);
+ send_servent(sess, sv);
+}
+
+/*
+ * static void
+ * irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the SETSERVENT verb.
+ */
+static void
+irpd_setservent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct servent *sv;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, sv, sess, IRPD_GETSERVICE_ERROR);
+
+ setservent_p(1, netdata); /* always stay open */
+ simple_response(sess, IRPD_GETSERVICE_SETOK, "ok");
+}
+
+/*
+ * static void
+ * send_prent(struct ctl_sess *sess, struct protoent *pr);
+ * Send the PR structure over the wire. If PR is NULL, then
+ * the response "No such protocol" is sent instead.
+ */
+static void
+send_prent(struct ctl_sess *sess, struct protoent *pr) {
+ if (pr == NULL) {
+ simple_response(sess, IRPD_GETPROTO_NONE,
+ "No such protocol");
+ } else {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_pr(pr, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall pr\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETPROTO_OK, "Protocol found", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+ }
+}
+
+/*
+ * static void
+ * irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETPROTOBYNAME verb.
+ */
+static void
+irpd_getprotobyname(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct protoent *pr;
+ char protoname[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "GETPROTOBYNAME protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof protoname) {
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "Name too long");
+ } else {
+ strncpy(protoname, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ protoname[args->iov[0].iov_len] = '\0';
+
+ pr = getprotobyname_p(protoname, netdata);
+ send_prent(sess, pr);
+ }
+ }
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getprotobynumber(struct ctl_sctx *ctx,
+ * struct ctl_sess *sess, const struct ctl_verb *verb,
+ * const char *rest, u_int respflags, void *respctx,
+ * void *uctx);
+ * Handle the GETPROTOBYNUMBER verb.
+ */
+static void
+irpd_getprotobynumber(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct protoent *pr;
+ char protonum[64];
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "GETPROTOBYNUMBER protocol");
+ } else {
+ if (args->iov[0].iov_len >= sizeof protonum) {
+ simple_response(sess, IRPD_GETGROUP_ERROR,
+ "Name too long");
+ } else {
+ strncpy(protonum, args->iov[0].iov_base,
+ args->iov[0].iov_len);
+ protonum[args->iov[0].iov_len] = '\0';
+
+ if (!ALLDIGITS(protonum)) {
+ simple_response(sess, IRPD_GETPROTO_ERROR,
+ "Not a protocol number");
+ } else {
+ int proto;
+ long lval;
+
+ lval = strtol(protonum, 0, 10);
+ proto = (int)lval;
+ if ((long)proto != lval) {
+ /* value was too big */
+ simple_response(sess,
+ IRPD_GETPROTO_ERROR,
+ "Not a valid proto");
+ goto untimely;
+ }
+
+ pr = getprotobynumber_p(proto, netdata);
+ send_prent(sess, pr);
+ }
+ }
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETPROTOENT verb.
+ */
+static void
+irpd_getprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct protoent *pr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ pr = getprotoent_p(netdata);
+ send_prent(sess, pr);
+}
+
+/*
+ * static void
+ * irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the SETPROTOENT verb.
+ */
+static void
+irpd_setprotoent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct protoent *pr;
+ size_t need;
+ size_t need_total = 0;
+ struct response_buff *b;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, pr, sess, IRPD_GETPROTO_ERROR);
+
+ setprotoent_p(1, netdata); /* always stay open */
+ simple_response(sess, IRPD_GETPROTO_SETOK, "ok");
+}
+
+/*
+ * static void
+ * send_pwent(struct ctl_sess *sess, struct passwd *pw);
+ * Send PW over the wire, or, if PW is NULL, a "No such
+ * user" response.
+ */
+static void
+send_ngent(struct ctl_sess *sess, char *host, char *user, char *domain) {
+ struct response_buff *b = newbuffer(0);
+
+ if (irp_marshall_ng(host, user, domain, &b->buff,
+ &b->bufflen) != 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "Internal error");
+ logger(ctl_warning, "Cant marshall ng\n");
+ return;
+ }
+
+ strcat(b->buff, "\r\n");
+
+ ctl_response(sess, IRPD_GETNETGR_OK, "Netgroup entry", 0, 0,
+ response_done, b, b->buff, strlen(b->buff));
+}
+
+/*
+ * static void
+ * irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the GETNETGRENT verb.
+ */
+static void
+irpd_getnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ char netgroupname[64];
+ struct response_buff *b = NULL;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ if (rest != NULL && strlen(rest) > 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "GETNETGRENT");
+ } else {
+ char *host, *user, *domain;
+
+ if (getnetgrent_p(&host, &user, &domain, netdata) == 1) {
+ send_ngent(sess, host, user, domain);
+ } else {
+ simple_response(sess, IRPD_GETNETGR_NOMORE,
+ "No more");
+ }
+ }
+}
+
+/*
+ * static void
+ * irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the INNETGR verb.
+ */
+static void
+irpd_innetgr(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct response_buff *b;
+ size_t need;
+ struct net_data *netdata = get_net_data(sess);
+ char *host;
+ char *user;
+ char *domain;
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 3) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "INNETGR netgroup ngentry");
+ } else {
+ char *grptmp = memget(args->iov[0].iov_len + 1);
+ char *ngtmp = memget(args->iov[1].iov_len + 1);
+
+ strncpy(grptmp, args->iov[0].iov_base, args->iov[0].iov_len);
+ strncpy(ngtmp, args->iov[1].iov_base, args->iov[1].iov_len);
+
+ grptmp[args->iov[0].iov_len] = '\0';
+ ngtmp[args->iov[1].iov_len] = '\0';
+
+ if (irp_unmarshall_ng(&host, &user, &domain, ngtmp) != 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "ngentry must be (host,user,domain)");
+ } else {
+ if (innetgr_p(grptmp, host, user, domain,
+ netdata) == 1) {
+ simple_response(sess, IRPD_GETNETGR_MATCHES,
+ "INNETGR matches");
+ } else {
+ simple_response(sess, IRPD_GETNETGR_NOMATCH,
+ "INNETGR does not match");
+ }
+ }
+
+ memput(grptmp, args->iov[0].iov_len + 1);
+ memput(ngtmp, args->iov[1].iov_len + 1);
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the SETNETGRENT verb.
+ */
+static void
+irpd_setnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ args = split_string(rest);
+ if (args->iovlen != 2) { /* len includes NULL at end */
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "setnetgrent netgroup");
+ } else {
+ setnetgrent_p(rest, netdata);
+ simple_response(sess, IRPD_GETNETGR_SETOK,
+ "setnetgrent ok");
+ }
+
+ untimely:
+ free_args(args);
+}
+
+/*
+ * static void
+ * irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the ENDNETGRENT verb.
+ */
+static void
+irpd_endnetgrent(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct arg_s *args;
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ ND_INIT(netdata, ng, sess, IRPD_GETNETGR_ERROR);
+
+ if (rest != NULL && strlen (rest) > 0) {
+ simple_response(sess, IRPD_GETNETGR_ERROR,
+ "endnetgrent netgroup");
+ } else {
+ endnetgrent_p(netdata);
+ simple_response(sess, IRPD_GETNETGR_SETOK,
+ "endnetgrent ok");
+ }
+}
+
+/*
+ * static void
+ * irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *param)
+ * Callback for when QUIT respnse is sent out.
+ */
+static void
+irpd_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *param) {
+ struct net_data *netdata = get_net_data(sess);
+
+ INSIST(netdata != NULL);
+
+ net_data_destroy(netdata);
+}
+
+/*
+ * static void
+ * irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the QUIT verb.
+ */
+static void
+irpd_quit(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ ctl_response(sess, irpd_quit_ok, "See ya!", CTL_EXIT, NULL,
+ 0 , NULL, NULL, 0);
+}
+
+/*
+ * static void
+ * irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle the HELP verb.
+ */
+static void
+irpd_help(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ /* XXX should make this do something better (like include required
+ * arguments.
+ */
+ ctl_sendhelp(sess, 231);
+}
+
+/*
+ * static void
+ * irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle a new connection.
+ */
+static void
+irpd_accept(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct sockaddr *sa = respctx;
+ char raddr[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
+ int reject = 1;
+ int response;
+ char *respmsg = NULL;
+
+ if (sa->sa_family == AF_UNIX) {
+ syslog (LOG_INFO, "New AF_UNIX connection");
+ reject = 0;
+ } else if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = respctx;
+ static long localhost;
+ static long zero;
+
+ if (localhost == 0) {
+ /* yes, this could be done with simple arithmetic... */
+ inet_pton(AF_INET, "127.0.0.1", &localhost);
+ }
+
+ inet_ntop(AF_INET, &sin->sin_addr, raddr, sizeof raddr);
+
+ /* we reject INET connections that are not from the local
+ * machine.
+ */
+ if (sin->sin_addr.s_addr == zero ||
+ sin->sin_addr.s_addr == localhost) {
+ reject = 0;
+ syslog(LOG_INFO, "New connection from %s", raddr);
+ } else {
+ syslog(LOG_INFO, "New connection from %s (reject)",
+ raddr);
+ respmsg = "Connections from off host not permitted";
+ }
+ } else if (sa->sa_family == AF_INET6) {
+ /* XXX should do something intelligent here. */
+ respmsg = "IPv6 connections not implemented yet.";
+ syslog(LOG_ERR, "Cannot handle AF_INET6 connections yet");
+ } else {
+ syslog (LOG_ERR, "Unknown peer type: %d", sa->sa_family);
+ respmsg = "What are you???";
+ }
+
+ if (reject) {
+ response = IRPD_NOT_WELCOME_CODE;
+ if (respmsg == NULL) {
+ respmsg = "Go away!";
+ }
+ /* XXX can we be sure that stacked up commands will not be
+ * processed before the control connection is closed???
+ */
+ } else {
+ void *ctx = make_cli_ctx();
+
+ if (ctx == NULL) {
+ response = IRPD_NOT_WELCOME_CODE;
+ respmsg = "Internal error (client context)";
+ } else {
+ response = IRPD_WELCOME_CODE;
+ if (respmsg == NULL) {
+ respmsg = "Welcome to IRPD (v 1)";
+ }
+ ctl_setcsctx(sess, ctx);
+ }
+ }
+ ctl_response(sess, response, respmsg, (reject ? CTL_EXIT : 0), NULL,
+ 0, NULL, NULL, 0);
+}
+
+/*
+ * static void
+ * irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ * const struct ctl_verb *verb, const char *rest,
+ * u_int respflags, void *respctx, void *uctx);
+ * Handle a dropped connection.
+ */
+static void
+irpd_abort(struct ctl_sctx *ctx, struct ctl_sess *sess,
+ const struct ctl_verb *verb, const char *rest,
+ u_int respflags, void *respctx, void *uctx)
+{
+ struct net_data *netdata = get_net_data(sess);
+
+ if (netdata != NULL)
+ net_data_destroy(netdata);
+}
+
+/*
+ * void
+ * response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *uap)
+ * UAP is the response_buffer passed through to
+ * ctl_response.
+ */
+static void
+response_done(struct ctl_sctx *ctx, struct ctl_sess *sess, void *uap) {
+ release_buffer(uap);
+}
+
+/*
+ * static void
+ * logger(enum ctl_severity sev, const char *fmt, ...);
+ * Logging routine called by the ctl_* functions. For now we
+ * just spit everything to stderr.
+ */
+
+static void
+logger(enum ctl_severity sev, const char *fmt, ...) {
+ char buffer[1024];
+ va_list ap;
+ int level;
+
+ if (sev == ctl_debug)
+ return;
+
+ if (sev == ctl_warning)
+ level = LOG_WARNING;
+ else if (sev == ctl_error)
+ level = LOG_ERR;
+ else {
+ syslog(LOG_CRIT, "Invalid severity: %d", (int)sev);
+ exit(1);
+ }
+
+ va_start(ap, fmt);
+
+#if 0
+ fprintf(stderr, "irpd: ");
+ vfprintf(stderr, fmt, ap);
+#else
+ if (vsprintf(buffer, fmt, ap) > (sizeof (buffer) - 1)) {
+ syslog(LOG_CRIT, "Buffer overrun in logger");
+ abort();
+ }
+ syslog(level, "%s", buffer);
+#endif
+ va_end(ap);
+}
+
+/*
+ * static struct response_buff *
+ * newbuffer(u_int length);
+ * Create a structure to hold an allocated buffer. We do
+ * this so we can get the size to deallocate later.
+ * Returns:
+ * Pointer to the structure
+ */
+static struct response_buff *
+newbuffer(u_int length) {
+ struct response_buff *h;
+
+ h = memget(sizeof *h);
+ if (h == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ h->buff = NULL;
+ h->bufflen = length;
+
+ if (length > 0) {
+ h->buff = memget(h->bufflen);
+ if (h->buff == NULL) {
+ memput(h, sizeof *h);
+ errno = ENOMEM;
+ return (NULL);
+ }
+ memset(h->buff, 0, h->bufflen);
+ }
+
+ return (h);
+}
+
+/*
+ * static void
+ * release_buffer(struct response_buff *b);
+ * Free up a buffer allocated with newbuffer.
+ */
+static void
+release_buffer(struct response_buff *b) {
+ memset(b->buff, 0, b->bufflen);
+ memput(b->buff, b->bufflen);
+
+ memset(b, 0, sizeof *b);
+ memput(b, sizeof *b);
+}
+
+/*
+ * static struct arg_s *
+ * split_string(const char *string);
+ * Create an array of iovecs(last one having NULL fields)
+ * pointing into STRING at the non-whitespace sections. The
+ * iovecs are stashed inside a structure so we can get the
+ * size back later at deallocation time. Iovecs are used to avoid
+ * modifying the argument with added nulls.
+ * Returns:
+ * Pointer to the wrapper structure. Must be given to free_args()
+ * when done
+ */
+static struct arg_s *
+split_string(const char *string) {
+ struct iovec *iovs;
+ const char *p;
+ int i, c, iswh;
+ struct arg_s *a;
+
+ /* count + 1 of the number of runs of non-whitespace. */
+ for (iswh = 1, i = 1, p = string ; p != NULL && *p ; p++) {
+ if (iswh && !isspace(*p)) {
+ iswh = 0;
+ i++;
+ } else if (!iswh && isspace(*p)) {
+ iswh = 1;
+ }
+ }
+
+ iovs = memget(sizeof (struct iovec) * i);
+ if (iovs == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ a = memget(sizeof *a);
+ if (a == NULL) {
+ errno = ENOMEM;
+ memput(iovs, sizeof (struct iovec) * i);
+ return (NULL);
+ }
+ a->iov = iovs;
+ a->iovlen = i;
+
+ for (c = 0, p = string ; p != NULL && *p ; c++) {
+ while (isspace(*p)) {
+ p++;
+ }
+
+ if (*p == '\0')
+ break;
+
+ iovs[c].iov_base = (void *)p;
+
+ while (*p && !isspace(*p)) {
+ p++;
+ }
+ iovs[c].iov_len = p - (char *)iovs[c].iov_base;
+ }
+ INSIST(c == i - 1);
+ iovs[c].iov_base = NULL;
+ iovs[c].iov_len = 0;
+
+ return (a);
+}
+
+/*
+ * static void
+ * free_args(struct arg_s *args);
+ * Free up the argument structure created with
+ * split_string().
+ */
+
+static void
+free_args(struct arg_s *args) {
+ memput(args->iov, sizeof (struct iovec) * args->iovlen);
+ memput(args, sizeof *args);
+}
+
+static struct client_ctx *
+make_cli_ctx(void) {
+ struct client_ctx *p = memget (sizeof *p);
+
+ if (p == NULL)
+ return (NULL);
+
+ p->net_data = net_data_create(conffile);
+
+ return (p);
+}
+
+static void
+release_cli_ctx(struct client_ctx *ctx) {
+ INSIST(ctx != NULL);
+ INSIST(ctx->net_data != NULL);
+
+ net_data_destroy(ctx->net_data);
+ memput(ctx, sizeof *ctx);
+}
+
+static struct net_data *
+get_net_data(struct ctl_sess *sess) {
+ struct client_ctx *ctx = ctl_getcsctx(sess);
+
+ INSIST(ctx != NULL);
+ INSIST(ctx->net_data != NULL);
+
+ return (ctx->net_data);
+}
OpenPOWER on IntegriCloud