/* * Copyright (c) 2007 Hypertriton, Inc. * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 AUTHOR 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. */ #include #include #include #include #include #include #include #include #include #include #include #include "machctld.h" #include "prog.h" #include "pathnames.h" #include "mkpath.h" static char * parse_path(NS_Command *cmd, const char *key) { char *path = NS_CommandString(cmd, key); if (path[0] == '/' || strstr(path, "..") != NULL) { AG_SetError("%s: bad program path: `%s'", key, path); return (NULL); } return (path); } static char * parse_name(NS_Command *cmd, const char *key) { char *name = NS_CommandString(cmd, key); const char *p; for (p = &key[0]; *p != '\0'; p++) { if (*p == '/' || *p == '.' || *p == ' ') { AG_SetError("%s: bad name: %s", key, name); return (NULL); } } if ((p - &key[0]) > RCSINFO_NAME_MAX) { AG_SetError("%s: name too large", key); return (NULL); } return (name); } static char * parse_msg(NS_Command *cmd, const char *key) { char *name = NS_CommandString(cmd, key); const char *p; for (p = &key[0]; *p != '\0'; p++) { if (!isprint(*p)) { AG_SetError("%s: non-printable character", key); return (NULL); } } if ((p - &key[0]) > RCSINFO_MSG_MAX) { AG_SetError("%s: name too large", key); return (NULL); } return (name); } static size_t parse_size(NS_Command *cmd, const char *key) { long lval; if (NS_CommandLong(cmd, key, &lval) == -1) return (0); /* Agar signatures are at least 8 bytes. */ if (lval < 8) { AG_SetError("%s: data file is too small (%lu)", key, lval); return (0); } return ((size_t)lval); } int prog_commit(NS_Server *ns, NS_Command *cmd, void *p) { char buf[BUFSIZ]; char filepath[MAXPATHLEN]; char *progname, *objname, *objtype; size_t nread = 0, size; int fd; if ((progname = parse_path(cmd, "prog-name")) == NULL || (size = parse_size(cmd, "prog-size")) == 0) { return (-1); } if (mkpath(progname, 0755) == -1) { return (-1); } Strlcpy(filepath, progname, sizeof(filepath)); Strlcat(filepath, "/", sizeof(filepath)); Strlcat(filepath, progname, sizeof(filepath)); Strlcat(filepath, ".Prog", sizeof(filepath)); if ((fd = open(filepath, O_CREAT|O_WRONLY|O_EXCL, 0644)) == -1) { AG_SetError("%s: %s", filepath, strerror(errno)); NS_Log(NS_ERR, "%s", AG_GetError()); return (-1); } NS_Log(NS_INFO, "Importing %s (%lu bytes)", filepath, (u_long)size); NS_Message(ns, 0, "Go ahead"); while (nread < size) { size_t csize, rv; if ((csize = (size - nread)) > sizeof(buf)) csize = sizeof(buf); if ((rv = fread(buf, 1, csize, stdin)) < csize) { AG_SetError("incomplete chunk"); goto fail; } if (write(fd, buf, rv) < rv) { AG_SetError("write error"); goto fail; } nread += rv; } close(fd); NS_Message(ns, 0, "Program OK"); return (0); fail: close(fd); NS_Message(ns, 1, "Import failed (%s)", AG_GetError()); NS_Log(NS_ERR, "Import failed: %s: %s", filepath, AG_GetError()); return (-1); } int prog_fetch(NS_Server *ns, NS_Command *cmd, void *p) { char buf[BUFSIZ]; char filepath[MAXPATHLEN]; char *dirpath, *progname; off_t len; ssize_t rv; int fd; if ((progname = parse_name(cmd, "prog-name")) == NULL) { return (-1); } Strlcpy(filepath, progname, sizeof(filepath)); Strlcat(filepath, "/", sizeof(filepath)); Strlcat(filepath, progname, sizeof(filepath)); Strlcat(filepath, ".Prog", sizeof(filepath)); NS_Log(NS_INFO, "Sending program %s", filepath); if ((fd = open(filepath, O_RDONLY|O_EXCL)) == -1) { AG_SetError("%s: %s", filepath, strerror(errno)); NS_Log(NS_ERR, "%s", AG_GetError()); return (-1); } if ((len = lseek(fd, 0, SEEK_END)) == -1) { AG_SetError("%s: cannot seek end", filepath); goto fail_com; } if (lseek(fd, 0, SEEK_SET) == -1) { AG_SetError("%s: cannot seek set", filepath); goto fail_com; } NS_BeginData(ns, (size_t)len); while ((rv = read(fd, buf, sizeof(buf))) > 0) { if (NS_Data(ns, buf, rv) < rv) { AG_SetError("%s: error writing to socket", filepath); goto fail_bin; } } if (rv < 0) { AG_SetError("%s: read error", filepath); goto fail_bin; } close(fd); NS_EndData(ns); return (0); fail_bin: NS_Log(NS_ERR, "%s", AG_GetError()); NS_EndData(ns); fail_com: close(fd); return (-1); } int prog_list(NS_Server *ns, NS_Command *cmd, void *p) { struct stat sb; struct dirent *dent; DIR *dir; if ((dir = opendir(_PATH_DATA)) == NULL) { AG_SetError("%s: %s", _PATH_DATA, strerror(errno)); NS_Log(NS_CRIT, "%s", AG_GetError()); return (-1); } NS_BeginList(ns); while ((dent = readdir(dir)) != NULL) { if (dent->d_name[0] == '.' || stat(dent->d_name, &sb) == -1) { continue; } if ((sb.st_mode & S_IFDIR) == S_IFDIR) { NS_ListString(ns, "%s:%lu", dent->d_name, (unsigned long)sb.st_size); } } closedir(dir); NS_EndList(ns); return (0); }