1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88"; 10 static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 08/19/93"; 11 #endif /* not lint */ 12 13 #include <sys/param.h> 14 #include <sys/file.h> 15 #include <sys/socket.h> 16 #include <sys/stat.h> 17 18 #include <netinet/in.h> 19 #include <arpa/inet.h> 20 21 #include <kerberosIV/des.h> 22 #include <kerberosIV/krb.h> 23 #include <kerberosIV/kparse.h> 24 25 #include <ctype.h> 26 #include <errno.h> 27 #include <netdb.h> 28 #include <pwd.h> 29 #include <signal.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include "krb.h" 36 37 #ifndef MAXHOSTNAMELEN 38 #define MAXHOSTNAMELEN 64 39 #endif 40 41 #define START_PORT 5120 /* arbitrary */ 42 43 int getport __P((int *)); 44 45 int 46 kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm, 47 cred, schedule, msg_data, laddr, faddr, authopts) 48 int *sock; 49 char **ahost; 50 u_short rport; 51 char *locuser, *remuser, *cmd; 52 int *fd2p; 53 KTEXT ticket; 54 char *service; 55 char *realm; 56 CREDENTIALS *cred; 57 Key_schedule schedule; 58 MSG_DAT *msg_data; 59 struct sockaddr_in *laddr, *faddr; 60 long authopts; 61 { 62 int s, timo = 1, pid; 63 long oldmask; 64 struct sockaddr_in sin, from; 65 char c; 66 #ifdef ATHENA_COMPAT 67 int lport = IPPORT_RESERVED - 1; 68 #else 69 int lport = START_PORT; 70 #endif 71 struct hostent *hp; 72 int rc; 73 char *host_save; 74 int status; 75 76 pid = getpid(); 77 hp = gethostbyname(*ahost); 78 if (hp == NULL) { 79 /* fprintf(stderr, "%s: unknown host\n", *ahost); */ 80 return (-1); 81 } 82 83 host_save = malloc(strlen(hp->h_name) + 1); 84 strcpy(host_save, hp->h_name); 85 *ahost = host_save; 86 87 #ifdef KERBEROS 88 /* If realm is null, look up from table */ 89 if (realm == NULL || realm[0] == '\0') 90 realm = krb_realmofhost(host_save); 91 #endif /* KERBEROS */ 92 93 oldmask = sigblock(sigmask(SIGURG)); 94 for (;;) { 95 s = getport(&lport); 96 if (s < 0) { 97 if (errno == EAGAIN) 98 fprintf(stderr, 99 "kcmd(socket): All ports in use\n"); 100 else 101 perror("kcmd: socket"); 102 sigsetmask(oldmask); 103 return (-1); 104 } 105 fcntl(s, F_SETOWN, pid); 106 sin.sin_family = hp->h_addrtype; 107 #if defined(ultrix) || defined(sun) 108 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 109 #else 110 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); 111 #endif 112 sin.sin_port = rport; 113 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 114 break; 115 (void) close(s); 116 if (errno == EADDRINUSE) { 117 lport--; 118 continue; 119 } 120 /* 121 * don't wait very long for Kerberos rcmd. 122 */ 123 if (errno == ECONNREFUSED && timo <= 4) { 124 /* sleep(timo); don't wait at all here */ 125 timo *= 2; 126 continue; 127 } 128 #if !(defined(ultrix) || defined(sun)) 129 if (hp->h_addr_list[1] != NULL) { 130 int oerrno = errno; 131 132 fprintf(stderr, 133 "kcmd: connect to address %s: ", 134 inet_ntoa(sin.sin_addr)); 135 errno = oerrno; 136 perror(NULL); 137 hp->h_addr_list++; 138 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, 139 hp->h_length); 140 fprintf(stderr, "Trying %s...\n", 141 inet_ntoa(sin.sin_addr)); 142 continue; 143 } 144 #endif /* !(defined(ultrix) || defined(sun)) */ 145 if (errno != ECONNREFUSED) 146 perror(hp->h_name); 147 sigsetmask(oldmask); 148 return (-1); 149 } 150 lport--; 151 if (fd2p == 0) { 152 write(s, "", 1); 153 lport = 0; 154 } else { 155 char num[8]; 156 int s2 = getport(&lport), s3; 157 int len = sizeof(from); 158 159 if (s2 < 0) { 160 status = -1; 161 goto bad; 162 } 163 listen(s2, 1); 164 (void) sprintf(num, "%d", lport); 165 if (write(s, num, strlen(num) + 1) != strlen(num) + 1) { 166 perror("kcmd(write): setting up stderr"); 167 (void) close(s2); 168 status = -1; 169 goto bad; 170 } 171 s3 = accept(s2, (struct sockaddr *)&from, &len); 172 (void) close(s2); 173 if (s3 < 0) { 174 perror("kcmd:accept"); 175 lport = 0; 176 status = -1; 177 goto bad; 178 } 179 *fd2p = s3; 180 from.sin_port = ntohs((u_short)from.sin_port); 181 if (from.sin_family != AF_INET || 182 from.sin_port >= IPPORT_RESERVED) { 183 fprintf(stderr, 184 "kcmd(socket): protocol failure in circuit setup.\n"); 185 status = -1; 186 goto bad2; 187 } 188 } 189 /* 190 * Kerberos-authenticated service. Don't have to send locuser, 191 * since its already in the ticket, and we'll extract it on 192 * the other side. 193 */ 194 /* (void) write(s, locuser, strlen(locuser)+1); */ 195 196 /* set up the needed stuff for mutual auth, but only if necessary */ 197 if (authopts & KOPT_DO_MUTUAL) { 198 int sin_len; 199 *faddr = sin; 200 201 sin_len = sizeof(struct sockaddr_in); 202 if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) { 203 perror("kcmd(getsockname)"); 204 status = -1; 205 goto bad2; 206 } 207 } 208 #ifdef KERBEROS 209 if ((status = krb_sendauth(authopts, s, ticket, service, *ahost, 210 realm, (unsigned long) getpid(), msg_data, 211 cred, schedule, 212 laddr, 213 faddr, 214 "KCMDV0.1")) != KSUCCESS) 215 goto bad2; 216 #endif /* KERBEROS */ 217 218 (void) write(s, remuser, strlen(remuser)+1); 219 (void) write(s, cmd, strlen(cmd)+1); 220 221 if ((rc = read(s, &c, 1)) != 1) { 222 if (rc == -1) 223 perror(*ahost); 224 else 225 fprintf(stderr,"kcmd: bad connection with remote host\n"); 226 status = -1; 227 goto bad2; 228 } 229 if (c != '\0') { 230 while (read(s, &c, 1) == 1) { 231 (void) write(2, &c, 1); 232 if (c == '\n') 233 break; 234 } 235 status = -1; 236 goto bad2; 237 } 238 sigsetmask(oldmask); 239 *sock = s; 240 return (KSUCCESS); 241 bad2: 242 if (lport) 243 (void) close(*fd2p); 244 bad: 245 (void) close(s); 246 sigsetmask(oldmask); 247 return (status); 248 } 249 250 int 251 getport(alport) 252 int *alport; 253 { 254 struct sockaddr_in sin; 255 int s; 256 257 sin.sin_family = AF_INET; 258 sin.sin_addr.s_addr = INADDR_ANY; 259 s = socket(AF_INET, SOCK_STREAM, 0); 260 if (s < 0) 261 return (-1); 262 for (;;) { 263 sin.sin_port = htons((u_short)*alport); 264 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 265 return (s); 266 if (errno != EADDRINUSE) { 267 (void) close(s); 268 return (-1); 269 } 270 (*alport)--; 271 #ifdef ATHENA_COMPAT 272 if (*alport == IPPORT_RESERVED/2) { 273 #else 274 if (*alport == IPPORT_RESERVED) { 275 #endif 276 (void) close(s); 277 errno = EAGAIN; /* close */ 278 return (-1); 279 } 280 } 281 } 282