rcmdsh.c revision 94789
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: head/lib/libc/net/rcmdsh.c 94789 2002-04-15 18:45:20Z ume $"); 3885342Simp 3986214Sru#include <sys/types.h> 4086214Sru#include <sys/socket.h> 4186214Sru#include <sys/wait.h> 4285342Simp 4386214Sru#include <errno.h> 4486214Sru#include <netdb.h> 4586214Sru#include <paths.h> 4686214Sru#include <pwd.h> 4786214Sru#include <stdio.h> 4886214Sru#include <string.h> 4986214Sru#include <unistd.h> 5086214Sru 5185342Simp#ifndef _PATH_RSH 5286214Sru#define _PATH_RSH "/usr/bin/rsh" 5385342Simp#endif 5485342Simp 5585342Simp/* 5685342Simp * This is a replacement rcmd() function that uses the rsh(1) 5785342Simp * program in place of a direct rcmd(3) function call so as to 5885342Simp * avoid having to be root. Note that rport is ignored. 5985342Simp */ 6085342Simpint 6185342Simprcmdsh(ahost, rport, locuser, remuser, cmd, rshprog) 6285342Simp char **ahost; 6394789Sume int rport; 6486214Sru const char *locuser, *remuser, *cmd, *rshprog; 6585342Simp{ 6694789Sume struct addrinfo hints, *res; 6794789Sume int cpid, sp[2], error; 6885342Simp char *p; 6985342Simp struct passwd *pw; 7094789Sume char num[8]; 7194789Sume static char hbuf[NI_MAXHOST]; 7285342Simp 7385342Simp /* What rsh/shell to use. */ 7485342Simp if (rshprog == NULL) 7585342Simp rshprog = _PATH_RSH; 7685342Simp 7785342Simp /* locuser must exist on this host. */ 7885342Simp if ((pw = getpwnam(locuser)) == NULL) { 7986214Sru (void)fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser); 8086214Sru return (-1); 8185342Simp } 8285342Simp 8385342Simp /* Validate remote hostname. */ 8485342Simp if (strcmp(*ahost, "localhost") != 0) { 8594789Sume memset(&hints, 0, sizeof(hints)); 8694789Sume hints.ai_flags = AI_CANONNAME; 8794789Sume hints.ai_family = PF_UNSPEC; 8894789Sume hints.ai_socktype = SOCK_STREAM; 8994789Sume (void)snprintf(num, sizeof(num), "%d", ntohs(rport)); 9094789Sume error = getaddrinfo(*ahost, num, &hints, &res); 9194789Sume if (error) { 9294789Sume fprintf(stderr, "rcmdsh: getaddrinfo: %s\n", 9394789Sume gai_strerror(error)); 9486214Sru return (-1); 9585342Simp } 9694789Sume if (res->ai_canonname) { 9794789Sume strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1); 9894789Sume hbuf[sizeof(hbuf) - 1] = '\0'; 9994789Sume *ahost = hbuf; 10094789Sume } 10194789Sume freeaddrinfo(res); 10285342Simp } 10385342Simp 10485342Simp /* Get a socketpair we'll use for stdin and stdout. */ 10586214Sru if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) { 10685342Simp perror("rcmdsh: socketpair"); 10786214Sru return (-1); 10885342Simp } 10985342Simp 11085342Simp cpid = fork(); 11186214Sru if (cpid == -1) { 11285342Simp perror("rcmdsh: fork failed"); 11386214Sru return (-1); 11485342Simp } else if (cpid == 0) { 11585342Simp /* 11685342Simp * Child. We use sp[1] to be stdin/stdout, and close sp[0]. 11785342Simp */ 11886214Sru (void)close(sp[0]); 11986214Sru if (dup2(sp[1], 0) == -1 || dup2(0, 1) == -1) { 12085342Simp perror("rcmdsh: dup2 failed"); 12185342Simp _exit(255); 12285342Simp } 12385342Simp /* Fork again to lose parent. */ 12485342Simp cpid = fork(); 12586214Sru if (cpid == -1) { 12685342Simp perror("rcmdsh: fork to lose parent failed"); 12785342Simp _exit(255); 12885342Simp } 12985342Simp if (cpid > 0) 13085342Simp _exit(0); 13185342Simp 13285342Simp /* In grandchild here. Become local user for rshprog. */ 13386214Sru if (setuid(pw->pw_uid) == -1) { 13486214Sru (void)fprintf(stderr, "rcmdsh: setuid(%u): %s\n", 13586214Sru pw->pw_uid, strerror(errno)); 13685342Simp _exit(255); 13785342Simp } 13885342Simp 13985342Simp /* 14086214Sru * If remote host is "localhost" and local and remote users 14185342Simp * are the same, avoid running remote shell for efficiency. 14285342Simp */ 14386214Sru if (strcmp(*ahost, "localhost") == 0 && 14486214Sru strcmp(locuser, remuser) == 0) { 14585342Simp if (pw->pw_shell[0] == '\0') 14685342Simp rshprog = _PATH_BSHELL; 14785342Simp else 14885342Simp rshprog = pw->pw_shell; 14985342Simp p = strrchr(rshprog, '/'); 15086214Sru execlp(rshprog, p ? p + 1 : rshprog, "-c", cmd, 15186214Sru (char *)NULL); 15285342Simp } else { 15385342Simp p = strrchr(rshprog, '/'); 15486214Sru execlp(rshprog, p ? p + 1 : rshprog, *ahost, "-l", 15586214Sru remuser, cmd, (char *)NULL); 15685342Simp } 15786214Sru (void)fprintf(stderr, "rcmdsh: execlp %s failed: %s\n", 15886214Sru rshprog, strerror(errno)); 15985342Simp _exit(255); 16085342Simp } else { 16185342Simp /* Parent. close sp[1], return sp[0]. */ 16286214Sru (void)close(sp[1]); 16385342Simp /* Reap child. */ 16486214Sru (void)wait(NULL); 16586214Sru return (sp[0]); 16685342Simp } 16785342Simp /* NOTREACHED */ 16885342Simp} 169