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