/* interact.c Text interactor for dhcp servers. */ /* * Copyright (c) 1998 The Internet Software Consortium. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of The Internet Software Consortium nor the names * of its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * This software was written for the Internet Software Consortium by * Ted Lemon in cooperation with Vixie Enterprises. * To learn more about the Internet Software Consortium, see * ``http://www.vix.com/isc''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. */ #ifndef lint static char copyright[] = "$Id: interact.c,v 1.1 1998/04/09 05:18:56 mellon Exp $ Copyright (c) 1998 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" int interact_initialized; int interact_fd; static struct interact_client *interact_clients; void interact_startup () { struct sockaddr_un name; static int once; int len; mode_t m; /* Only initialize interact once. */ if (interact_initialized) error ("attempted to reinitialize interact protocol"); interact_initialized = 1; /* Make a socket... */ interact_fd = socket (AF_UNIX, SOCK_STREAM, 0); if (interact_fd < 0) error ("unable to create interact socket: %m"); /* XXX for now... */ name.sun_family = PF_UNIX; strcpy (name.sun_path, "/var/run/dhcpctl"); #if defined (HAVE_SA_LEN) name.sun_len = #endif len = ((sizeof name) - (sizeof name.sun_path) + strlen (name.sun_path)); unlink (name.sun_path); /* interact socket should be accessible only by root. */ m = umask (0700); /* Bind to it... */ if (bind (interact_fd, (struct sockaddr *)&name, len) < 0) { warn ("can't bind to interact socket: %m"); close (interact_fd); umask (m); return; } umask (m); /* Listen for connections... */ if (listen (interact_fd, 1) < 0) { warn ("can't listen on interact socket: %m"); close (interact_fd); unlink (name.sun_path); return; } add_protocol ("interact", interact_fd, new_interact_connection, 0); } void new_interact_connection (proto) struct protocol *proto; { struct sockaddr_un name; int namelen; struct interact_client *tmp; int new_fd; int arg; tmp = (struct interact_client *)malloc (sizeof *tmp); if (!tmp) error ("Can't find memory for new client!"); memset (tmp, 0, sizeof *tmp); namelen = sizeof name; new_fd = accept (proto -> fd, (struct sockaddr *)&name, &namelen); if (new_fd < 0) { warn ("accept: %m"); free (tmp); return; } if ((arg = fcntl (new_fd, F_GETFL, 0)) < 0) { bad_flag: warn ("Can't set flags on new interactive client: %m"); close (new_fd); free (tmp); return; } arg |= O_NONBLOCK; if (fcntl (new_fd, F_SETFL, arg) < 0) goto bad_flag; tmp -> next = interact_clients; tmp -> fd = new_fd; interact_clients = tmp; tmp -> cur_node_actions = top_level_actions; tmp -> proto = add_protocol ("aclient", new_fd, interact_client_input, tmp); } void interact_client_input (proto) struct protocol *proto; { int status; char *eobuf; struct interact_client *client = proto -> local; status = read (proto -> fd, &client -> ibuf [client -> ibuflen], (sizeof client -> ibuf) - client -> ibuflen); if (status < 0) { warn ("interact_client_input: %m"); blow: close (proto -> fd); remove_protocol (proto); free (client); return; } /* EOF: get lost. */ if (status == 0) goto blow; client -> ibuflen += status; eobuf = memchr (client -> ibuf, '\n', client -> ibuflen); if (!eobuf) { if (client -> ibuflen == sizeof client -> ibuf) { warn ("interact_client_input: buffer overflow."); goto blow; } return; } /* NUL terminate and blow away newline. */ *eobuf = 0; if (!strcmp (client -> ibuf, "ls")) (*client -> cur_node_actions.ls) (client); else if (!strncmp (client -> ibuf, "print ", 6)) (*client -> cur_node_actions.print) (client, &client -> ibuf [6]); else if (!strncmp (client -> ibuf, "set ", 4)) (*client -> cur_node_actions.set) (client, &client -> ibuf [4]); else if (!strncmp (client -> ibuf, "rm ", 3)) (*client -> cur_node_actions.rm) (client, &client -> ibuf [3]); else if (!strcmp (client -> ibuf, "cd ..")) (*client -> cur_node_actions.cdup) (client); else if (!strncmp (client -> ibuf, "cd ", 3)) (*client -> cur_node_actions.cd) (client, &client -> ibuf [3]); else if (!strcmp (client -> ibuf, "exit")) { interact_client_write (client, "done.", 1); goto blow; } else interact_client_write (client, "invalid command", 1); /* In case the client wrote more than one command. */ if (client -> ibuflen -= eobuf - &client -> ibuf [0] + 1) memmove (client -> ibuf, eobuf, client -> ibuflen); } int interact_client_write (client, string, lastp) struct interact_client *client; char *string; int lastp; { static char *obuf; static int obufmax; char *bp; /* Unlikely to loop, but why not be sure? */ if (obufmax < strlen (string)) { if (obuf) free (obuf); obufmax = (strlen (string) + 1025) & ~1023; obuf = malloc (obufmax); if (!obuf) { warn ("interact_client_write: out of memory"); blow: close (client -> proto -> fd); remove_protocol (client -> proto); free (client); return 0; } } bp = obuf; if (!lastp) *bp++ = '-'; strcpy (bp, string); bp += strlen (bp); *bp++ = '\n'; if (write (client -> fd, obuf, bp - obuf) < 0) return 0; return 1; }