IRIX: Move src/sgistuff to platform/IRIX
[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 }