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