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.1 (Berkeley) 06/06/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 /* If realm is null, look up from table */ 88 if (realm == NULL || realm[0] == '\0') 89 realm = krb_realmofhost(host_save); 90 91 oldmask = sigblock(sigmask(SIGURG)); 92 for (;;) { 93 s = getport(&lport); 94 if (s < 0) { 95 if (errno == EAGAIN) 96 fprintf(stderr, 97 "kcmd(socket): All ports in use\n"); 98 else 99 perror("kcmd: socket"); 100 sigsetmask(oldmask); 101 return (-1); 102 } 103 fcntl(s, F_SETOWN, pid); 104 sin.sin_family = hp->h_addrtype; 105 #if defined(ultrix) || defined(sun) 106 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); 107 #else 108 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); 109 #endif 110 sin.sin_port = rport; 111 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 112 break; 113 (void) close(s); 114 if (errno == EADDRINUSE) { 115 lport--; 116 continue; 117 } 118 /* 119 * don't wait very long for Kerberos rcmd. 120 */ 121 if (errno == ECONNREFUSED && timo <= 4) { 122 /* sleep(timo); don't wait at all here */ 123 timo *= 2; 124 continue; 125 } 126 #if !(defined(ultrix) || defined(sun)) 127 if (hp->h_addr_list[1] != NULL) { 128 int oerrno = errno; 129 130 fprintf(stderr, 131 "kcmd: connect to address %s: ", 132 inet_ntoa(sin.sin_addr)); 133 errno = oerrno; 134 perror(NULL); 135 hp->h_addr_list++; 136 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, 137 hp->h_length); 138 fprintf(stderr, "Trying %s...\n", 139 inet_ntoa(sin.sin_addr)); 140 continue; 141 } 142 #endif /* !(defined(ultrix) || defined(sun)) */ 143 if (errno != ECONNREFUSED) 144 perror(hp->h_name); 145 sigsetmask(oldmask); 146 return (-1); 147 } 148 lport--; 149 if (fd2p == 0) { 150 write(s, "", 1); 151 lport = 0; 152 } else { 153 char num[8]; 154 int s2 = getport(&lport), s3; 155 int len = sizeof(from); 156 157 if (s2 < 0) { 158 status = -1; 159 goto bad; 160 } 161 listen(s2, 1); 162 (void) sprintf(num, "%d", lport); 163 if (write(s, num, strlen(num) + 1) != strlen(num) + 1) { 164 perror("kcmd(write): setting up stderr"); 165 (void) close(s2); 166 status = -1; 167 goto bad; 168 } 169 s3 = accept(s2, (struct sockaddr *)&from, &len); 170 (void) close(s2); 171 if (s3 < 0) { 172 perror("kcmd:accept"); 173 lport = 0; 174 status = -1; 175 goto bad; 176 } 177 *fd2p = s3; 178 from.sin_port = ntohs((u_short)from.sin_port); 179 if (from.sin_family != AF_INET || 180 from.sin_port >= IPPORT_RESERVED) { 181 fprintf(stderr, 182 "kcmd(socket): protocol failure in circuit setup.\n"); 183 status = -1; 184 goto bad2; 185 } 186 } 187 /* 188 * Kerberos-authenticated service. Don't have to send locuser, 189 * since its already in the ticket, and we'll extract it on 190 * the other side. 191 */ 192 /* (void) write(s, locuser, strlen(locuser)+1); */ 193 194 /* set up the needed stuff for mutual auth, but only if necessary */ 195 if (authopts & KOPT_DO_MUTUAL) { 196 int sin_len; 197 *faddr = sin; 198 199 sin_len = sizeof(struct sockaddr_in); 200 if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) { 201 perror("kcmd(getsockname)"); 202 status = -1; 203 goto bad2; 204 } 205 } 206 if ((status = krb_sendauth(authopts, s, ticket, service, *ahost, 207 realm, (unsigned long) getpid(), msg_data, 208 cred, schedule, 209 laddr, 210 faddr, 211 "KCMDV0.1")) != KSUCCESS) 212 goto bad2; 213 214 (void) write(s, remuser, strlen(remuser)+1); 215 (void) write(s, cmd, strlen(cmd)+1); 216 217 if ((rc = read(s, &c, 1)) != 1) { 218 if (rc == -1) 219 perror(*ahost); 220 else 221 fprintf(stderr,"kcmd: bad connection with remote host\n"); 222 status = -1; 223 goto bad2; 224 } 225 if (c != '\0') { 226 while (read(s, &c, 1) == 1) { 227 (void) write(2, &c, 1); 228 if (c == '\n') 229 break; 230 } 231 status = -1; 232 goto bad2; 233 } 234 sigsetmask(oldmask); 235 *sock = s; 236 return (KSUCCESS); 237 bad2: 238 if (lport) 239 (void) close(*fd2p); 240 bad: 241 (void) close(s); 242 sigsetmask(oldmask); 243 return (status); 244 } 245 246 int 247 getport(alport) 248 int *alport; 249 { 250 struct sockaddr_in sin; 251 int s; 252 253 sin.sin_family = AF_INET; 254 sin.sin_addr.s_addr = INADDR_ANY; 255 s = socket(AF_INET, SOCK_STREAM, 0); 256 if (s < 0) 257 return (-1); 258 for (;;) { 259 sin.sin_port = htons((u_short)*alport); 260 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 261 return (s); 262 if (errno != EADDRINUSE) { 263 (void) close(s); 264 return (-1); 265 } 266 (*alport)--; 267 #ifdef ATHENA_COMPAT 268 if (*alport == IPPORT_RESERVED/2) { 269 #else 270 if (*alport == IPPORT_RESERVED) { 271 #endif 272 (void) close(s); 273 errno = EAGAIN; /* close */ 274 return (-1); 275 } 276 } 277 } 278