186214Sru/* $OpenBSD: rcmdsh.c,v 1.5 1998/04/25 16:23:58 millert Exp $ */ 285342Simp 385342Simp/* 494757Snectar * Copyright (c) 2001, MagniComp 594757Snectar * All rights reserved. 694757Snectar * 794757Snectar * Redistribution and use in source and binary forms, with or without 894757Snectar * modification, are permitted provided that the following conditions 994757Snectar * are met: 1094757Snectar * 1. Redistributions of source code must retain the above copyright 1194757Snectar * notice, this list of conditions and the following disclaimer. 1294757Snectar * 2. Redistributions in binary form must reproduce the above copyright 1394757Snectar * notice, this list of conditions and the following disclaimer in 1494757Snectar * the documentation and/or other materials provided with the distribution. 1594757Snectar * 3. Neither the name of the MagniComp nor the names of its contributors may 1694757Snectar * be used to endorse or promote products derived from this software 1794757Snectar * without specific prior written permission. 1894757Snectar * 1994757Snectar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2094757Snectar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2194757Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2294757Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR 2394757Snectar * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2494757Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2594757Snectar * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2694757Snectar * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2794757Snectar * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 2894757Snectar * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2994757Snectar */ 3094757Snectar 3194757Snectar/* 3286214Sru * This is an rcmd() replacement originally by 3385342Simp * Chris Siebenmann <cks@utcc.utoronto.ca>. 3485342Simp */ 3585342Simp 3686214Sru#include <sys/cdefs.h> 3786214Sru__FBSDID("$FreeBSD$"); 3885342Simp 3986214Sru#include <sys/types.h> 4086214Sru#include <sys/socket.h> 4186214Sru#include <sys/wait.h> 42111618Snectar#include <arpa/inet.h> 4385342Simp 4486214Sru#include <errno.h> 4586214Sru#include <netdb.h> 4686214Sru#include <paths.h> 4786214Sru#include <pwd.h> 4886214Sru#include <stdio.h> 4986214Sru#include <string.h> 5086214Sru#include <unistd.h> 5186214Sru 5285342Simp#ifndef _PATH_RSH 5386214Sru#define _PATH_RSH "/usr/bin/rsh" 5485342Simp#endif 5585342Simp 5685342Simp/* 5785342Simp * This is a replacement rcmd() function that uses the rsh(1) 5885342Simp * program in place of a direct rcmd(3) function call so as to 5985342Simp * avoid having to be root. Note that rport is ignored. 6085342Simp */ 6185342Simpint 6285342Simprcmdsh(ahost, rport, locuser, remuser, cmd, rshprog) 6385342Simp char **ahost; 6494789Sume int rport; 6586214Sru const char *locuser, *remuser, *cmd, *rshprog; 6685342Simp{ 6794789Sume struct addrinfo hints, *res; 6894789Sume int cpid, sp[2], error; 6985342Simp char *p; 7085342Simp struct passwd *pw; 7194789Sume char num[8]; 7294789Sume static char hbuf[NI_MAXHOST]; 7385342Simp 7485342Simp /* What rsh/shell to use. */ 7585342Simp if (rshprog == NULL) 7685342Simp rshprog = _PATH_RSH; 7785342Simp 7885342Simp /* locuser must exist on this host. */ 7985342Simp if ((pw = getpwnam(locuser)) == NULL) { 8086214Sru (void)fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser); 8186214Sru return (-1); 8285342Simp } 8385342Simp 8485342Simp /* Validate remote hostname. */ 8585342Simp if (strcmp(*ahost, "localhost") != 0) { 8694789Sume memset(&hints, 0, sizeof(hints)); 8794789Sume hints.ai_flags = AI_CANONNAME; 8894789Sume hints.ai_family = PF_UNSPEC; 8994789Sume hints.ai_socktype = SOCK_STREAM; 90111618Snectar (void)snprintf(num, sizeof(num), "%u", 91111618Snectar (unsigned int)ntohs(rport)); 9294789Sume error = getaddrinfo(*ahost, num, &hints, &res); 9394789Sume if (error) { 9494789Sume fprintf(stderr, "rcmdsh: getaddrinfo: %s\n", 9594789Sume gai_strerror(error)); 9686214Sru return (-1); 9785342Simp } 9894789Sume if (res->ai_canonname) { 9994789Sume strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1); 10094789Sume hbuf[sizeof(hbuf) - 1] = '\0'; 10194789Sume *ahost = hbuf; 10294789Sume } 10394789Sume freeaddrinfo(res); 10485342Simp } 10585342Simp 10685342Simp /* Get a socketpair we'll use for stdin and stdout. */ 10786214Sru if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { 10885342Simp perror("rcmdsh: socketpair"); 10986214Sru return (-1); 11085342Simp } 11185342Simp 11285342Simp cpid = fork(); 11386214Sru if (cpid == -1) { 11485342Simp perror("rcmdsh: fork failed"); 11586214Sru return (-1); 11685342Simp } else if (cpid == 0) { 11785342Simp /* 11885342Simp * Child. We use sp[1] to be stdin/stdout, and close sp[0]. 11985342Simp */ 12086214Sru (void)close(sp[0]); 12186214Sru if (dup2(sp[1], 0) == -1 || dup2(0, 1) == -1) { 12285342Simp perror("rcmdsh: dup2 failed"); 12385342Simp _exit(255); 12485342Simp } 12585342Simp /* Fork again to lose parent. */ 12685342Simp cpid = fork(); 12786214Sru if (cpid == -1) { 12885342Simp perror("rcmdsh: fork to lose parent failed"); 12985342Simp _exit(255); 13085342Simp } 13185342Simp if (cpid > 0) 13285342Simp _exit(0); 13385342Simp 13485342Simp /* In grandchild here. Become local user for rshprog. */ 13586214Sru if (setuid(pw->pw_uid) == -1) { 13686214Sru (void)fprintf(stderr, "rcmdsh: setuid(%u): %s\n", 13786214Sru pw->pw_uid, strerror(errno)); 13885342Simp _exit(255); 13985342Simp } 14085342Simp 14185342Simp /* 14286214Sru * If remote host is "localhost" and local and remote users 14385342Simp * are the same, avoid running remote shell for efficiency. 14485342Simp */ 14586214Sru if (strcmp(*ahost, "localhost") == 0 && 14686214Sru strcmp(locuser, remuser) == 0) { 14785342Simp if (pw->pw_shell[0] == '\0') 14885342Simp rshprog = _PATH_BSHELL; 14985342Simp else 15085342Simp rshprog = pw->pw_shell; 15185342Simp p = strrchr(rshprog, '/'); 15286214Sru execlp(rshprog, p ? p + 1 : rshprog, "-c", cmd, 15386214Sru (char *)NULL); 15485342Simp } else { 15585342Simp p = strrchr(rshprog, '/'); 15686214Sru execlp(rshprog, p ? p + 1 : rshprog, *ahost, "-l", 15786214Sru remuser, cmd, (char *)NULL); 15885342Simp } 15986214Sru (void)fprintf(stderr, "rcmdsh: execlp %s failed: %s\n", 16086214Sru rshprog, strerror(errno)); 16185342Simp _exit(255); 16285342Simp } else { 16385342Simp /* Parent. close sp[1], return sp[0]. */ 16486214Sru (void)close(sp[1]); 16585342Simp /* Reap child. */ 16686214Sru (void)wait(NULL); 16786214Sru return (sp[0]); 16885342Simp } 16985342Simp /* NOTREACHED */ 17085342Simp} 171