/*****************************************************************************\ * Copyright (c) 2004 Pelle Johansson. * * All rights reserved. * * * * This file is part of the moftpd package. Use and distribution of * * this software is governed by the terms in the file LICENCE, which * * should have come with this package. * \*****************************************************************************/ /* $moftpd: admin.c 1251 2005-03-06 22:24:29Z morth $ */ #ifndef _SYSTEM_H #include "system.h" #endif #include "utf8fs/memory.h" const char *sockPath = VARDIR "/run/" PACKAGE_NAME ".acct"; int debug = 0; void usage (void) { fprintf (stderr, "Usage: %s [-f ] list\n", getprogname ()); fprintf (stderr, " %s [-f ] msg \n", getprogname ()); fprintf (stderr, " %s [-f ] msgall \n", getprogname ()); fprintf (stderr, " %s [-f ] abort []\n", getprogname ()); fprintf (stderr, " %s [-f ] disconnect []\n", getprogname ()); fprintf (stderr, " %s [-f ] discabort []\n", getprogname ()); fprintf (stderr, " %s [-f ] reload\n", getprogname ()); exit(1); } int parse_options (int argc, char ***argv) { int ch; if (getenv("MOFTP_SOCKET")) { sockPath = tstring (getenv ("MOFTP_SOCKET")); if(!sockPath) { perror ("tstring"); return -1; } } while((ch = getopt(argc, *argv, "f:")) != -1) { switch(ch) { case 'f': sockPath = tstring (optarg); if(!sockPath) { perror ("tstring"); return -1; } break; default: usage (); } } *argv += optind; return argc - optind; } const char *combine_args (char *argv[], int nargs) { int l = -1, i; char *res, *rp; for (i = 0; i < nargs; i++) l += strlen (argv[i]) + 1; if (l <= 0) return ""; rp = res = talloc (l); if (!res) { perror ("talloc"); return NULL; } for (i = 0; i < nargs; i++) { #ifdef HAVE_STPCPY rp = stpcpy (rp, argv[i]); #else strcpy (rp, argv[i]); rp += strlen (rp); #endif *rp++ = ' '; } *--rp = 0; return res; } int accounter (int sock, const char *format, ...) { va_list ap; char *str, *sp; int res; #ifdef HAVE_VASPRINTF int doFree; #endif va_start (ap, format); #ifdef HAVE_VASPRINTF vasprintf (&str, format, ap); doFree = 1; #else str = talloc (4097); if (str) vsnprintf (str, 4096, format, ap); #endif va_end (ap); if (!str) { str = tstring (format); #ifdef HAVE_VASPRINTF doFree = 0; #endif } while ((sp = strchr (str, '\n')) && *(sp + 1)) *sp = '?'; res = write (sock, str, strlen (str)); #ifdef HAVE_VASPRINTF if (doFree) free (str); #endif if (res < 0) return -1; return 0; } int ok_message (int sock, const char *type, int id, const char *message) { int l; char buf[4096], *bp; if (id != -1) l = accounter (sock, "%s %d %s\n", type, id, message); else l = accounter (sock, "%s %s", type, message); if (l) { perror ("accounter"); return 1; } l = read (sock, buf, sizeof (buf) - 1); if (l < 0) { perror ("read"); return 1; } buf[l] = 0; bp = strchr (buf, '\n'); if (bp) *bp = 0; if (!strcmp (buf, "OK")) return 0; if (!strcmp (buf, "INVALID")) fprintf (stderr, "Invalid connection id.\n"); else fprintf (stderr, "Unknown error.\n"); return 1; } int main (int argc, char *argv[]) { int sock; struct sockaddr_un addr; int bl, l, i; char buf[4096], *bp, *nbp; const char *msg; setprogname (argv[0]); argc = parse_options (argc, &argv); if (argc < 0) return 1; if (!argc) usage (); sock = socket (PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { perror ("socket"); return 1; } addr.sun_family = AF_UNIX; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN addr.sun_len = sizeof (addr); #endif strncpy (addr.sun_path, sockPath, sizeof (addr.sun_path) - 1); addr.sun_path[sizeof (addr.sun_path) - 1] = 0; if (connect (sock, (struct sockaddr*)&addr, sizeof (addr))) { perror ("connect"); return 1; } if (!strcasecmp (argv[0], "LIST")) { if (argc != 1) usage (); if (accounter (sock, "LIST\n")) { perror ("accounter"); return 1; } bl = l = 0; while (bl > 0 || (l = read (sock, buf + bl, sizeof (buf) - bl)) > 0) { if (l > 0) bl += l; nbp = memchr (buf, '\n', bl); if (nbp) *nbp++ = 0; if (!strcmp (buf, "END")) break; printf ("%s\n", buf); if (!nbp) break; bl -= nbp - buf; memmove (buf, nbp, bl); l = 0; } } else if (!strcasecmp (argv[0], "MSG")) { if (argc < 3 || !*argv[1]) usage (); i = strtol (argv[1], &bp, 0); if (*bp) usage (); msg = combine_args (argv + 2, argc - 2); if (!msg) return 1; if (!*msg) { fprintf (stderr, "No message given.\n"); return 1; } if (ok_message (sock, "MSG", i, msg)) return 1; } else if (!strcasecmp (argv[0], "MSGALL")) { if (argc < 2) usage (); msg = combine_args (argv + 1, argc - 1); if (!msg) return 1; if (!*msg) { fprintf (stderr, "No message given.\n"); return 1; } if (ok_message (sock, "MSGALL", -1, msg)) return 1; } else if (!strcasecmp (argv[0], "ABORT")) { if (argc < 2 || !*argv[1]) usage (); i = strtol (argv[1], &bp, 0); if (*bp) usage (); msg = combine_args (argv + 2, argc - 2); if (!msg) return 1; if (ok_message (sock, "ABORT", i, msg)) return 1; } else if (!strcasecmp (argv[0], "DISCONNECT")) { if (argc < 2 || !*argv[1]) usage (); i = strtol (argv[1], &bp, 0); if (*bp) usage (); msg = combine_args (argv + 2, argc - 2); if (!msg) return 1; if (ok_message (sock, "DISCONNECT", i, msg)) return 1; } else if (!strcasecmp (argv[0], "DISCABORT")) { if (argc < 2 || !*argv[1]) usage (); i = strtol (argv[1], &bp, 0); if (*bp) usage (); msg = combine_args (argv + 2, argc - 2); if (!msg) return 1; if (ok_message (sock, "DISCABORT", i, msg)) return 1; } else if (!strcasecmp (argv[0], "RELOAD")) { if (argc != 1) usage (); if (accounter (sock, "RELOAD\n")) { perror ("accounter"); return 1; } printf ("Configuration reloading.\n"); } else usage (); close (sock); return 0; }