Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / platform / IRIX / rcmd.c
1 /*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 */
17
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21
22 #ifdef aiws /*AIX*/
23 #include <sys/types.h>
24 #define MAXHOSTNAMELEN 64 /* use BSD's, not sys/param's */
25 #define MAXPATHLEN 1024 /* from BSD */
26 #include <sys/ioctl.h> /* for SIOCSPGRP */
27 #endif
28 #include <stdio.h>
29 #include <ctype.h>
30 #include <pwd.h>
31 #include <sys/param.h>
32 #include <limits.h>
33 #include <sys/file.h>
34 #ifdef AFS_SUN5_ENV
35 #include <fcntl.h>
36 #endif
37 #include <unistd.h> /* select() prototype */
38 #include <sys/types.h> /* fd_set on older platforms */
39 #include <sys/time.h> /* struct timeval, select() prototype */
40 #ifndef FD_SET
41 # include <sys/select.h> /* fd_set on newer platforms */
42 #endif
43 #include <sys/signal.h>
44 #include <sys/socket.h>
45 #include <sys/stat.h>
46 #include <netinet/in.h>
47 #include <netdb.h>
48 #include <errno.h>
49 #if defined(AFS_HPUX_ENV)
50 /* HPUX uses a different call to set[res][gu]ids: */
51 #define seteuid(newEuid) setresuid(-1, (newEuid), -1)
52 #define setegid(newEgid) setresgid(-1, (newEgid), -1)
53 #endif /* defined(AFS_HPUX_ENV) */
54 #ifdef TCP_DEBUG
55 #include <sys/syslog.h>
56 # define DPRINTF(args) afs_dprintf args
57 afs_dprintf(args)
58 char *args;
59 {
60 char **argv;
61 char buf[BUFSIZ];
62 static char prefix[] = "rcmd: ";
63
64 argv = &args;
65 vsprintf(buf, argv[0], &argv[1]);
66 syslog(LOG_DEBUG, "%s %s\n", prefix, buf);
67 }
68 #else
69 # define DPRINTF(args)
70 #endif
71 #include <syslog.h>
72 static _checkhost();
73
74 #ifdef AFS_HPUX102_ENV
75 int
76 rmcd(ahost, rport, locuser, remuser, cmd, fd2p)
77 char **ahost;
78 int rport;
79 const char *locuser, *remuser, *cmd;
80 int *fd2p;
81 #else
82 #ifdef AFS_AIX32_ENV
83 rcmd(ahost, rport, locuser, remuser, cmd, fd2p, retry)
84 int retry;
85 #else
86 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
87 #endif
88 char **ahost;
89 u_short rport;
90 #if defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
91 const char *locuser, *remuser, *cmd;
92 #else
93 char *locuser, *remuser, *cmd;
94 #endif
95 int *fd2p;
96 #endif
97 {
98 int s, timo = 1, pid;
99 sigset_t oldset;
100 sigset_t sigBlock;
101 int someSignals[100];
102 struct servent *sp, *getservbyport();
103 struct sockaddr_in sin, from;
104 char c;
105 int lport = IPPORT_RESERVED - 1;
106 struct hostent *hp;
107 fd_set reads;
108
109 memset(someSignals, 0, sizeof(someSignals));
110 someSignals[0] = 1 << (SIGURG - 1);
111 sigBlock = *((sigset_t *) someSignals);
112
113 pid = getpid();
114 hp = gethostbyname(*ahost); /* CAUTION: this uses global static */
115 /* storage. ANY OTHER CALLS to gethostbyname (including from within
116 * syslog, eg) will trash the contents of hp. BE CAREFUL! */
117 if (hp == 0) {
118 herror(*ahost);
119 return (-1);
120 }
121 *ahost = hp->h_name;
122 /* was: syslog(LOG_ERR, "rcmd: host=%s, rport=%d, luser=%s,ruser=%s,cmd=%s,fd2p=%s\n", *ahost,rport,locuser,remuser,cmd,fd2p)
123 * but that trashes hp... */
124 sigprocmask(SIG_BLOCK, &sigBlock, &oldset);
125 for (;;) {
126 s = rresvport(&lport);
127 if (s < 0) {
128 if (errno == EAGAIN)
129 fprintf(stderr, "socket: All ports in use\n");
130 else
131 perror("rcmd: socket");
132 sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
133 return (-1);
134 }
135 #ifdef AFS_AIX32_ENV
136 #ifndef aiws
137 fcntl(s, F_SETOWN, pid);
138 #else
139 /* since AIX has no F_SETOWN, we just do the ioctl */
140 (void)ioctl(s, SIOCSPGRP, &pid);
141 #endif
142 #else
143 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV)
144 fcntl(s, F_SETOWN, pid);
145 #endif /* !defined(AIX) */
146 #endif
147 sin.sin_family = hp->h_addrtype;
148 #ifdef AFS_OSF_ENV
149 memcpy((caddr_t) & sin.sin_addr, hp->h_addr_list[0], hp->h_length);
150 #else
151 memcpy((caddr_t) & sin.sin_addr, hp->h_addr, hp->h_length);
152 #endif
153 sin.sin_port = rport;
154 /* attempt to remote authenticate first... */
155 sp = getservbyport((int)rport, "tcp");
156 if (sp) {
157 int ok = 0;
158
159 switch (ta_rauth(s, sp->s_name, sin.sin_addr)) {
160 case 0:
161 #ifndef AFS_SGI_ENV
162 fprintf(stderr, "No remote authentication\n");
163 #endif
164 close(s);
165 s = rresvport(&lport);
166 if (s < 0) {
167 if (errno == EAGAIN)
168 fprintf(stderr, "socket: All ports in use\n");
169 else
170 perror("rcmd: socket");
171 sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
172 return (-1);
173 }
174 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV)
175 fcntl(s, F_SETOWN, pid);
176 #endif /* !defined(AIX) */
177 break;
178 case 1:
179 ok = 1;
180 break;
181 case -1:
182 fprintf(stderr, "Login incorrect.");
183 exit(1);
184 break;
185 case -2:
186 fprintf(stderr, "internal failure, ta_rauth\n");
187 exit(errno);
188 break;
189 case -3:
190 fprintf(stderr, "Cannot connect to remote machine\n");
191 exit(errno);
192 break;
193 }
194
195 if (ok) {
196 break; /* from for loop */
197 }
198 }
199 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
200 break;
201 (void)close(s);
202 if (errno == EADDRINUSE) {
203 lport--;
204 continue;
205 }
206 if (errno == ECONNREFUSED && timo <= 16) {
207 #ifdef AFS_AIX32_ENV
208 if (!retry) {
209 return (-2);
210 }
211 #endif
212 sleep(timo);
213 timo *= 2;
214 continue;
215 }
216 if (hp->h_addr_list[1] != NULL) {
217 int oerrno = errno;
218
219 fprintf(stderr, "connect to address %s: ",
220 inet_ntoa(sin.sin_addr));
221 errno = oerrno;
222 perror(0);
223 hp->h_addr_list++;
224 memcpy((caddr_t) & sin.sin_addr, hp->h_addr_list[0],
225 hp->h_length);
226 fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr));
227 continue;
228 }
229 perror(hp->h_name);
230 sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
231 return (-1);
232 }
233 lport--;
234 if (fd2p == 0) {
235 write(s, "", 1);
236 lport = 0;
237 } else {
238 char num[8];
239 int s2 = rresvport(&lport), s3;
240 int len = sizeof(from);
241 int maxfd = -1;
242
243 if (s2 < 0)
244 goto bad;
245 listen(s2, 1);
246 (void)sprintf(num, "%d", lport);
247 if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
248 perror("write: setting up stderr");
249 (void)close(s2);
250 goto bad;
251 }
252 FD_ZERO(&reads);
253 FD_SET(s, &reads);
254 if (maxfd < s)
255 maxfd = s;
256 FD_SET(s2, &reads);
257 if (maxfd < s2)
258 maxfd = s2;
259 errno = 0;
260 if (select(maxfd + 1, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) {
261 if (errno != 0)
262 perror("select: setting up stderr");
263 else
264 fprintf(stderr,
265 "select: protocol failure in circuit setup.\n");
266 (void)close(s2);
267 goto bad;
268 }
269 s3 = accept(s2, (struct sockaddr *)&from, &len);
270 (void)close(s2);
271 if (s3 < 0) {
272 perror("accept");
273 lport = 0;
274 goto bad;
275 }
276 *fd2p = s3;
277 from.sin_port = ntohs((u_short) from.sin_port);
278 if (from.sin_family != AF_INET || from.sin_port >= IPPORT_RESERVED
279 || from.sin_port < IPPORT_RESERVED / 2) {
280 fprintf(stderr, "socket: protocol failure in circuit setup.\n");
281 goto bad2;
282 }
283 }
284 (void)write(s, locuser, strlen(locuser) + 1);
285 (void)write(s, remuser, strlen(remuser) + 1);
286 (void)write(s, cmd, strlen(cmd) + 1);
287 errno = 0;
288 if (read(s, &c, 1) < 0) {
289 perror(*ahost);
290 goto bad2;
291 }
292 if (c != 0) {
293 #ifdef AFS_OSF_ENV
294 /*
295 * Two different protocols seem to be used;
296 * one prepends a "message" byte with a "small"
297 * number; the other one just sends the message
298 */
299 if (isalnum(c))
300 (void)write(2, &c, 1);
301
302 #endif
303 while (read(s, &c, 1) == 1) {
304 (void)write(2, &c, 1);
305 if (c == '\n')
306 break;
307 }
308 goto bad2;
309 }
310 sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
311 return (s);
312 bad2:
313 if (lport)
314 (void)close(*fd2p);
315 bad:
316 (void)close(s);
317 sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
318 return (-1);
319 }
320
321 #ifndef AFS_AIX32_ENV
322 rresvport(alport)
323 int *alport;
324 {
325 struct sockaddr_in sin;
326 int s;
327
328 sin.sin_family = AF_INET;
329 sin.sin_addr.s_addr = INADDR_ANY;
330 s = socket(AF_INET, SOCK_STREAM, 0);
331 if (s < 0)
332 return (-1);
333 for (;;) {
334 sin.sin_port = htons((u_short) * alport);
335 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
336 return (s);
337 if (errno != EADDRINUSE) {
338 (void)close(s);
339 return (-1);
340 }
341 (*alport)--;
342 if (*alport == IPPORT_RESERVED / 2) {
343 (void)close(s);
344 errno = EAGAIN; /* close */
345 return (-1);
346 }
347 }
348 }
349 #endif
350
351 int _check_rhosts_file = 1;
352
353 #if defined(AFS_HPUX102_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
354 ruserok(rhost, superuser, ruser, luser)
355 const char *rhost;
356 int superuser;
357 const char *ruser, *luser;
358 #else
359 ruserok(rhost, superuser, ruser, luser)
360 int superuser;
361 char *rhost;
362 char *ruser, *luser;
363 #endif
364 {
365 FILE *hostf;
366 char fhost[MAXHOSTNAMELEN];
367 int first = 1;
368 char *sp, *p;
369 int baselen = -1;
370 int suid, sgid;
371 int group_list_size = -1;
372 gid_t groups[NGROUPS_MAX];
373 sp = rhost;
374 p = fhost;
375 while (*sp) {
376 if (*sp == '.') {
377 if (baselen == -1)
378 baselen = sp - rhost;
379 *p++ = *sp++;
380 } else {
381 *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
382 }
383 }
384 *p = '\0';
385 hostf = superuser ? (FILE *) 0 : fopen("/etc/hosts.equiv", "r");
386 again:
387 if (hostf) {
388 if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
389 (void)fclose(hostf);
390 #ifdef AFS_OSF_ENV
391 if (first == 0) {
392 (void)seteuid(suid);
393 (void)setegid(sgid);
394 if (group_list_size >= 0)
395 (void)setgroups(group_list_size, groups);
396 }
397 #endif
398 return (0);
399 }
400 (void)fclose(hostf);
401 }
402 if (first == 1 && (_check_rhosts_file || superuser)) {
403 struct stat sbuf;
404 struct passwd *pwd, *getpwnam();
405 char pbuf[MAXPATHLEN];
406
407 first = 0;
408 suid = geteuid();
409 sgid = getegid();
410 group_list_size = getgroups(NGROUPS_MAX, groups);
411 if ((pwd = getpwnam(luser)) == NULL)
412 return (-1);
413 if (setegid(pwd->pw_gid) >= 0)
414 (void)initgroups(luser, pwd->pw_gid);
415 (void)seteuid(pwd->pw_uid);
416 (void)strcpy(pbuf, pwd->pw_dir);
417 (void)strcat(pbuf, "/.rhosts");
418 if ((hostf = fopen(pbuf, "r")) == NULL)
419 goto bad;
420 /*
421 * if owned by someone other than user or root or if
422 * writable by anyone but the owner, quit
423 */
424 if (fstat(fileno(hostf), &sbuf) || sbuf.st_uid
425 && sbuf.st_uid != pwd->pw_uid || sbuf.st_mode & 022) {
426 fclose(hostf);
427 goto bad;
428 }
429 goto again;
430 }
431 bad:
432 if (first == 0) {
433 (void)seteuid(suid);
434 (void)setegid(sgid);
435 if (group_list_size >= 0)
436 (void)setgroups(group_list_size, groups);
437 }
438 return (-1);
439 }
440
441 /* don't make static, used by lpd(8) */
442 _validuser(hostf, rhost, luser, ruser, baselen)
443 char *rhost, *luser, *ruser;
444 FILE *hostf;
445 int baselen;
446 {
447 char *user;
448 char ahost[MAXHOSTNAMELEN * 4];
449 char *p;
450 #ifdef AFS_AIX32_ENV
451 #include <arpa/nameser.h>
452 int hostmatch, usermatch;
453 char domain[MAXDNAME], *dp;
454
455 dp = NULL;
456 if (getdomainname(domain, sizeof(domain)) == 0)
457 dp = domain;
458 #endif
459 while (fgets(ahost, sizeof(ahost), hostf)) {
460 #ifdef AFS_AIX32_ENV
461 hostmatch = usermatch = 0;
462 p = ahost;
463 if (*p == '#' || *p == '\n') /* ignore comments and blanks */
464 continue;
465 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
466 p++;
467 if (*p == ' ' || *p == '\t') {
468 *p++ = '\0';
469 while (*p == ' ' || *p == '\t')
470 p++;
471 user = p;
472 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
473 p++;
474 } else
475 user = p;
476 *p = '\0';
477 /*
478 * + - anything goes
479 * +@<name> - group <name> allowed
480 * -@<name> - group <name> disallowed
481 * -<name> - host <name> disallowed
482 */
483 if (ahost[0] == '+' && ahost[1] == 0)
484 hostmatch = 1;
485 else if (ahost[0] == '+' && ahost[1] == '@')
486 hostmatch = innetgr(ahost + 2, rhost, NULL, dp);
487 else if (ahost[0] == '-' && ahost[1] == '@') {
488 if (innetgr(ahost + 2, rhost, NULL, dp))
489 return (-1);
490 } else if (ahost[0] == '-') {
491 if (_checkhost(rhost, ahost + 1, baselen))
492 return (-1);
493 } else
494 hostmatch = _checkhost(rhost, ahost, baselen);
495 if (user[0]) {
496 if (user[0] == '+' && user[1] == 0)
497 usermatch = 1;
498 else if (user[0] == '+' && user[1] == '@')
499 usermatch = innetgr(user + 2, NULL, ruser, dp);
500 else if (user[0] == '-' && user[1] == '@') {
501 if (hostmatch && innetgr(user + 2, NULL, ruser, dp))
502 return (-1);
503 } else if (user[0] == '-') {
504 if (hostmatch && !strcmp(user + 1, ruser))
505 return (-1);
506 } else
507 usermatch = !strcmp(user, ruser);
508 } else
509 usermatch = !strcmp(ruser, luser);
510 if (hostmatch && usermatch)
511 return (0);
512 #else
513 p = ahost;
514 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
515 *p = isupper(*p) ? tolower(*p) : *p;
516 p++;
517 }
518 if (*p == ' ' || *p == '\t') {
519 *p++ = '\0';
520 while (*p == ' ' || *p == '\t')
521 p++;
522 user = p;
523 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
524 p++;
525 } else
526 user = p;
527 *p = '\0';
528 if (_checkhost(rhost, ahost, baselen)
529 && !strcmp(ruser, *user ? user : luser)) {
530 return (0);
531 }
532 #endif
533 }
534 return (-1);
535 }
536
537 static
538 _checkhost(rhost, lhost, len)
539 char *rhost, *lhost;
540 int len;
541 {
542 static char ldomain[MAXHOSTNAMELEN + 1];
543 static char *domainp = NULL;
544 static int nodomain = 0;
545 char *cp;
546
547 #ifdef AFS_AIX32_ENV
548 struct hostent *hp;
549 long addr;
550
551 /*
552 * check for ip address and do a lookup to convert to hostname
553 */
554 if (isinet_addr(lhost) && (addr = inet_addr(lhost)) != -1
555 && (hp = gethostbyaddr(&addr, sizeof(addr), AF_INET)))
556 lhost = hp->h_name;
557
558 #endif
559 if (len == -1) {
560 #ifdef AFS_AIX32_ENV
561 /* see if hostname from file has a domain name */
562 for (cp = lhost; *cp; ++cp) {
563 if (*cp == '.') {
564 len = cp - lhost;
565 break;
566 }
567 }
568 #endif
569 return (!strcmp(rhost, lhost));
570 }
571 if (strncmp(rhost, lhost, len))
572 return (0);
573 if (!strcmp(rhost, lhost))
574 return (1);
575 #ifdef AFS_AIX32_ENV
576 if (*(lhost + len) != '\0' && *(rhost + len) != '\0')
577 #else
578 if (*(lhost + len) != '\0')
579 #endif
580 return (0);
581 if (nodomain)
582 return (0);
583 if (!domainp) {
584 if (gethostname(ldomain, sizeof(ldomain)) == -1) {
585 nodomain = 1;
586 return (0);
587 }
588 ldomain[MAXHOSTNAMELEN] = '\0';
589 if ((domainp = strchr(ldomain, '.')) == NULL) {
590 nodomain = 1;
591 return (0);
592 }
593 for (cp = ++domainp; *cp; ++cp)
594 if (isupper(*cp))
595 *cp = tolower(*cp);
596 }
597 return (!strcmp(domainp, rhost + len + 1));
598 }