/* $OpenBSD: util.c,v 1.19 2009/10/27 23:59:22 deraadt Exp $ */ /* $NetBSD: util.c,v 1.2 1995/03/21 08:19:08 cgd Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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 #include #include "extern.h" static pid_t do_cmd_pid = -1; /* PID of subprocess during do_local_cmd() */ char * colon(char *cp) { for (; *cp; ++cp) { if (*cp == ':') return (cp); if (*cp == '/') return (0); } return (0); } void verifydir(char *cp) { struct stat stb; if (!stat(cp, &stb)) { if (S_ISDIR(stb.st_mode)) return; errno = ENOTDIR; } run_err("%s: %s", cp, strerror(errno)); exit(1); } int okname(char *cp0) { int c; char *cp; cp = cp0; do { c = *cp; if (c & 0200) goto bad; if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') goto bad; } while (*++cp); return (1); bad: warnx("%s: invalid user name", cp0); return (0); } BUF * allocbuf(BUF *bp, int fd, int blksize) { struct stat stb; size_t size; char *p; if (fstat(fd, &stb) < 0) { run_err("fstat: %s", strerror(errno)); return (0); } size = roundup(stb.st_blksize, blksize); if (size == 0) size = blksize; if (bp->cnt >= size) return (bp); if ((p = realloc(bp->buf, size)) == NULL) { free(bp->buf); bp->buf = NULL; bp->cnt = 0; run_err("%s", strerror(errno)); return (0); } memset(p, 0, size); bp->buf = p; bp->cnt = size; return (bp); } /* ARGSUSED */ void lostconn(int signo) { extern char *__progname; char buf[1024]; if (!iamremote) { strlcpy(buf, __progname, sizeof buf); strlcat(buf, ": lost connection\n", sizeof buf); write(STDERR_FILENO, buf, strlen(buf)); } _exit(1); } static void killchild(int signo) { if (do_cmd_pid > 1) { kill(do_cmd_pid, signo ? signo : SIGTERM); waitpid(do_cmd_pid, NULL, 0); } if (signo) _exit(1); exit(1); } int do_local_cmd(arglist *a, uid_t userid, gid_t groupid) { int status; pid_t pid; if (a->num == 0) errx(1, "do_local_cmd: no arguments"); if ((pid = fork()) == -1) err(1, "do_local_cmd: fork"); if (pid == 0) { setresgid(groupid, groupid, groupid); setgroups(1, &groupid); setresuid(userid, userid, userid); execvp(a->list[0], a->list); perror(a->list[0]); exit(1); } do_cmd_pid = pid; signal(SIGTERM, killchild); signal(SIGINT, killchild); signal(SIGHUP, killchild); while (waitpid(pid, &status, 0) == -1) if (errno != EINTR) err(1, "do_local_cmd: waitpid"); do_cmd_pid = -1; if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) return (-1); signal(SIGTERM, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGHUP, SIG_DFL); return (0); } /* function to assist building execv() arguments */ void addargs(arglist *args, char *fmt, ...) { va_list ap; char *cp; u_int nalloc; int r; va_start(ap, fmt); r = vasprintf(&cp, fmt, ap); va_end(ap); if (r == -1) errx(1, "addargs: argument too long"); nalloc = args->nalloc; if (args->list == NULL) { nalloc = 32; args->num = 0; } else if (args->num+2 >= nalloc) nalloc *= 2; if ((args->list = realloc(args->list, nalloc * sizeof(char *))) == NULL) errx(1, "addargs: realloc failed"); args->nalloc = nalloc; args->list[args->num++] = cp; args->list[args->num] = NULL; } void freeargs(arglist *args) { u_int i; if (args->list != NULL) { for (i = 0; i < args->num; i++) free(args->list[i]); free(args->list); args->nalloc = args->num = 0; args->list = NULL; } }