Libinfo-173.1.tar.gz
[apple/libinfo.git] / util.subproj / rcmdsh.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24 /* $OpenBSD: rcmdsh.c,v 1.4 1997/07/23 16:59:37 millert Exp $ */
25
26 /*
27 * This is an rcmd() replacement originally by
28 * Chris Siebenmann <cks@utcc.utoronto.ca>.
29 */
30
31 #if defined(LIBC_SCCS) && !defined(lint)
32 static char *rcsid = "$OpenBSD: rcmdsh.c,v 1.4 1997/07/23 16:59:37 millert Exp $";
33 #endif /* LIBC_SCCS and not lint */
34
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/wait.h>
38 #include <signal.h>
39 #include <errno.h>
40 #include <netdb.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <pwd.h>
44 #include <paths.h>
45 #include <unistd.h>
46 /*
47 * This is a replacement rcmd() function that uses the rsh(1)
48 * program in place of a direct rcmd(3) function call so as to
49 * avoid having to be root. Note that rport is ignored.
50 */
51 /* ARGSUSED */
52 int
53 rcmdsh(ahost, rport, locuser, remuser, cmd, rshprog)
54 char **ahost;
55 int rport;
56 const char *locuser, *remuser, *cmd;
57 char *rshprog;
58 {
59 struct hostent *hp;
60 int cpid, sp[2];
61 char *p;
62 struct passwd *pw;
63
64 /* What rsh/shell to use. */
65 if (rshprog == NULL)
66 rshprog = _PATH_RSH;
67
68 /* locuser must exist on this host. */
69 if ((pw = getpwnam(locuser)) == NULL) {
70 (void) fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser);
71 return(-1);
72 }
73
74 /* Validate remote hostname. */
75 if (strcmp(*ahost, "localhost") != 0) {
76 if ((hp = gethostbyname(*ahost)) == NULL) {
77 herror(*ahost);
78 return(-1);
79 }
80 *ahost = hp->h_name;
81 }
82
83 /* Get a socketpair we'll use for stdin and stdout. */
84 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) {
85 perror("rcmdsh: socketpair");
86 return(-1);
87 }
88
89 cpid = fork();
90 if (cpid < 0) {
91 perror("rcmdsh: fork failed");
92 return(-1);
93 } else if (cpid == 0) {
94 /*
95 * Child. We use sp[1] to be stdin/stdout, and close sp[0].
96 */
97 (void) close(sp[0]);
98 if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) {
99 perror("rcmdsh: dup2 failed");
100 _exit(255);
101 }
102 /* Fork again to lose parent. */
103 cpid = fork();
104 if (cpid < 0) {
105 perror("rcmdsh: fork to lose parent failed");
106 _exit(255);
107 }
108 if (cpid > 0)
109 _exit(0);
110
111 /* In grandchild here. Become local user for rshprog. */
112 if (setuid(pw->pw_uid)) {
113 (void) fprintf(stderr, "rcmdsh: setuid(%u): %s\n",
114 pw->pw_uid, strerror(errno));
115 _exit(255);
116 }
117
118 /*
119 * If remote host is "localhost" and local and remote user
120 * are the same, avoid running remote shell for efficiency.
121 */
122 if (!strcmp(*ahost, "localhost") && !strcmp(locuser, remuser)) {
123 if (pw->pw_shell[0] == '\0')
124 rshprog = _PATH_BSHELL;
125 else
126 rshprog = pw->pw_shell;
127 p = strrchr(rshprog, '/');
128 execlp(rshprog, p ? p+1 : rshprog, "-c", cmd,
129 (char *) NULL);
130 } else {
131 p = strrchr(rshprog, '/');
132 execlp(rshprog, p ? p+1 : rshprog, *ahost, "-l",
133 remuser, cmd, (char *) NULL);
134 }
135 (void) fprintf(stderr, "rcmdsh: execlp %s failed: %s\n",
136 rshprog, strerror(errno));
137 _exit(255);
138 } else {
139 /* Parent. close sp[1], return sp[0]. */
140 (void) close(sp[1]);
141 /* Reap child. */
142 (void) wait(NULL);
143 }
144 return(sp[0]);
145 }