1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * 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 5.6 (Berkeley) 06/01/90"; 11 #endif /* not lint */ 12 13 /* 14 * $Source: /mit/kerberos/src/appl/bsd/RCS/kcmd.c,v $ 15 * $Header: kcmd.c,v 4.16 89/05/17 10:54:31 jtkohl Exp $ 16 * 17 * static char *rcsid_kcmd_c = 18 * "$Header: kcmd.c,v 4.16 89/05/17 10:54:31 jtkohl Exp $"; 19 */ 20 21 #include <sys/param.h> 22 #include <sys/file.h> 23 #include <sys/signal.h> 24 #include <sys/socket.h> 25 #include <sys/stat.h> 26 27 #include <netinet/in.h> 28 29 #include <netdb.h> 30 #include <errno.h> 31 #include <kerberosIV/des.h> 32 #include <kerberosIV/krb.h> 33 #include <kerberosIV/kparse.h> 34 #include <pwd.h> 35 #include <stdio.h> 36 #include <ctype.h> 37 38 #ifndef MAXHOSTNAMELEN 39 #define MAXHOSTNAMELEN 64 40 #endif 41 42 extern errno; 43 char *index(), *malloc(), *krb_realmofhost(); 44 45 #define START_PORT 5120 /* arbitrary */ 46 47 kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm, 48 cred, schedule, msg_data, laddr, faddr, authopts) 49 int *sock; 50 char **ahost; 51 u_short rport; 52 char *locuser, *remuser, *cmd; 53 int *fd2p; 54 KTEXT ticket; 55 char *service; 56 char *realm; 57 CREDENTIALS *cred; 58 Key_schedule schedule; 59 MSG_DAT *msg_data; 60 struct sockaddr_in *laddr, *faddr; 61 long authopts; 62 { 63 int s, timo = 1, pid; 64 long oldmask; 65 struct sockaddr_in sin, from; 66 char c; 67 #ifdef ATHENA_COMPAT 68 int lport = IPPORT_RESERVED - 1; 69 #else 70 int lport = START_PORT; 71 #endif ATHENA_COMPAT 72 struct hostent *hp; 73 int rc; 74 char *host_save; 75 int status; 76 77 pid = getpid(); 78 hp = gethostbyname(*ahost); 79 if (hp == 0) { 80 /* fprintf(stderr, "%s: unknown host\n", *ahost); */ 81 return (-1); 82 } 83 84 host_save = malloc(strlen(hp->h_name) + 1); 85 strcpy(host_save, hp->h_name); 86 *ahost = host_save; 87 88 /* If realm is null, look up from table */ 89 if ((realm == NULL) || (realm[0] == '\0')) { 90 realm = krb_realmofhost(host_save); 91 } 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 /* defined(ultrix) || defined(sun) */ 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(0); 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 goto bad2; 186 } 187 } 188 /* 189 * Kerberos-authenticated service. Don't have to send locuser, 190 * since its already in the ticket, and we'll extract it on 191 * the other side. 192 */ 193 /* (void) write(s, locuser, strlen(locuser)+1); */ 194 195 /* set up the needed stuff for mutual auth, but only if necessary */ 196 if (authopts & KOPT_DO_MUTUAL) { 197 int sin_len; 198 *faddr = sin; 199 200 sin_len = sizeof (struct sockaddr_in); 201 if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) { 202 perror("kcmd(getsockname)"); 203 status = -1; 204 goto bad2; 205 } 206 } 207 if ((status = krb_sendauth(authopts, s, ticket, service, *ahost, 208 realm, (unsigned long) getpid(), msg_data, 209 cred, schedule, 210 laddr, 211 faddr, 212 "KCMDV0.1")) != KSUCCESS) 213 goto bad2; 214 215 (void) write(s, remuser, strlen(remuser)+1); 216 (void) write(s, cmd, strlen(cmd)+1); 217 218 if ((rc=read(s, &c, 1)) != 1) { 219 if (rc==-1) { 220 perror(*ahost); 221 } else { 222 fprintf(stderr,"kcmd: bad connection with remote host\n"); 223 } 224 status = -1; 225 goto bad2; 226 } 227 if (c != 0) { 228 while (read(s, &c, 1) == 1) { 229 (void) write(2, &c, 1); 230 if (c == '\n') 231 break; 232 } 233 status = -1; 234 goto bad2; 235 } 236 sigsetmask(oldmask); 237 *sock = s; 238 return (KSUCCESS); 239 bad2: 240 if (lport) 241 (void) close(*fd2p); 242 bad: 243 (void) close(s); 244 sigsetmask(oldmask); 245 return (status); 246 } 247 248 getport(alport) 249 int *alport; 250 { 251 struct sockaddr_in sin; 252 int s; 253 254 sin.sin_family = AF_INET; 255 sin.sin_addr.s_addr = INADDR_ANY; 256 s = socket(AF_INET, SOCK_STREAM, 0); 257 if (s < 0) 258 return (-1); 259 for (;;) { 260 sin.sin_port = htons((u_short)*alport); 261 if (bind(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0) 262 return (s); 263 if (errno != EADDRINUSE) { 264 (void) close(s); 265 return (-1); 266 } 267 (*alport)--; 268 #ifdef ATHENA_COMPAT 269 if (*alport == IPPORT_RESERVED/2) { 270 #else 271 if (*alport == IPPORT_RESERVED) { 272 #endif ATHENA_COMPAT 273 (void) close(s); 274 errno = EAGAIN; /* close */ 275 return (-1); 276 } 277 } 278 } 279 280