Remove DUX/OSF code
[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         memcpy((caddr_t) & sin.sin_addr, hp->h_addr, hp->h_length);
149         sin.sin_port = rport;
150         /* attempt to remote authenticate first... */
151         sp = getservbyport((int)rport, "tcp");
152         if (sp) {
153             int ok = 0;
154
155             switch (ta_rauth(s, sp->s_name, sin.sin_addr)) {
156             case 0:
157 #ifndef AFS_SGI_ENV
158                 fprintf(stderr, "No remote authentication\n");
159 #endif
160                 close(s);
161                 s = rresvport(&lport);
162                 if (s < 0) {
163                     if (errno == EAGAIN)
164                         fprintf(stderr, "socket: All ports in use\n");
165                     else
166                         perror("rcmd: socket");
167                     sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
168                     return (-1);
169                 }
170 #if !defined(AFS_AIX_ENV) && !defined(AFS_HPUX_ENV)
171                 fcntl(s, F_SETOWN, pid);
172 #endif /* !defined(AIX) */
173                 break;
174             case 1:
175                 ok = 1;
176                 break;
177             case -1:
178                 fprintf(stderr, "Login incorrect.");
179                 exit(1);
180                 break;
181             case -2:
182                 fprintf(stderr, "internal failure, ta_rauth\n");
183                 exit(errno);
184                 break;
185             case -3:
186                 fprintf(stderr, "Cannot connect to remote machine\n");
187                 exit(errno);
188                 break;
189             }
190
191             if (ok) {
192                 break;          /* from for loop */
193             }
194         }
195         if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
196             break;
197         (void)close(s);
198         if (errno == EADDRINUSE) {
199             lport--;
200             continue;
201         }
202         if (errno == ECONNREFUSED && timo <= 16) {
203 #ifdef  AFS_AIX32_ENV
204             if (!retry) {
205                 return (-2);
206             }
207 #endif
208             sleep(timo);
209             timo *= 2;
210             continue;
211         }
212         if (hp->h_addr_list[1] != NULL) {
213             int oerrno = errno;
214
215             fprintf(stderr, "connect to address %s: ",
216                     inet_ntoa(sin.sin_addr));
217             errno = oerrno;
218             perror(0);
219             hp->h_addr_list++;
220             memcpy((caddr_t) & sin.sin_addr, hp->h_addr_list[0],
221                    hp->h_length);
222             fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr));
223             continue;
224         }
225         perror(hp->h_name);
226         sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
227         return (-1);
228     }
229     lport--;
230     if (fd2p == 0) {
231         write(s, "", 1);
232         lport = 0;
233     } else {
234         char num[8];
235         int s2 = rresvport(&lport), s3;
236         int len = sizeof(from);
237         int maxfd = -1;
238
239         if (s2 < 0)
240             goto bad;
241         listen(s2, 1);
242         (void)sprintf(num, "%d", lport);
243         if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
244             perror("write: setting up stderr");
245             (void)close(s2);
246             goto bad;
247         }
248         FD_ZERO(&reads);
249         FD_SET(s, &reads);
250         if (maxfd < s)
251             maxfd = s;
252         FD_SET(s2, &reads);
253         if (maxfd < s2)
254             maxfd = s2;
255         errno = 0;
256         if (select(maxfd + 1, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) {
257             if (errno != 0)
258                 perror("select: setting up stderr");
259             else
260                 fprintf(stderr,
261                         "select: protocol failure in circuit setup.\n");
262             (void)close(s2);
263             goto bad;
264         }
265         s3 = accept(s2, (struct sockaddr *)&from, &len);
266         (void)close(s2);
267         if (s3 < 0) {
268             perror("accept");
269             lport = 0;
270             goto bad;
271         }
272         *fd2p = s3;
273         from.sin_port = ntohs((u_short) from.sin_port);
274         if (from.sin_family != AF_INET || from.sin_port >= IPPORT_RESERVED
275             || from.sin_port < IPPORT_RESERVED / 2) {
276             fprintf(stderr, "socket: protocol failure in circuit setup.\n");
277             goto bad2;
278         }
279     }
280     (void)write(s, locuser, strlen(locuser) + 1);
281     (void)write(s, remuser, strlen(remuser) + 1);
282     (void)write(s, cmd, strlen(cmd) + 1);
283     errno = 0;
284     if (read(s, &c, 1) < 0) {
285         perror(*ahost);
286         goto bad2;
287     }
288     if (c != 0) {
289         while (read(s, &c, 1) == 1) {
290             (void)write(2, &c, 1);
291             if (c == '\n')
292                 break;
293         }
294         goto bad2;
295     }
296     sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
297     return (s);
298   bad2:
299     if (lport)
300         (void)close(*fd2p);
301   bad:
302     (void)close(s);
303     sigprocmask(SIG_SETMASK, &oldset, (sigset_t *) 0);
304     return (-1);
305 }
306
307 #ifndef AFS_AIX32_ENV
308 rresvport(alport)
309      int *alport;
310 {
311     struct sockaddr_in sin;
312     int s;
313
314     sin.sin_family = AF_INET;
315     sin.sin_addr.s_addr = INADDR_ANY;
316     s = socket(AF_INET, SOCK_STREAM, 0);
317     if (s < 0)
318         return (-1);
319     for (;;) {
320         sin.sin_port = htons((u_short) * alport);
321         if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
322             return (s);
323         if (errno != EADDRINUSE) {
324             (void)close(s);
325             return (-1);
326         }
327         (*alport)--;
328         if (*alport == IPPORT_RESERVED / 2) {
329             (void)close(s);
330             errno = EAGAIN;     /* close */
331             return (-1);
332         }
333     }
334 }
335 #endif
336
337 int _check_rhosts_file = 1;
338
339 #if defined(AFS_HPUX102_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
340 ruserok(rhost, superuser, ruser, luser)
341      const char *rhost;
342      int superuser;
343      const char *ruser, *luser;
344 #else
345 ruserok(rhost, superuser, ruser, luser)
346      int superuser;
347      char *rhost;
348      char *ruser, *luser;
349 #endif
350 {
351     FILE *hostf;
352     char fhost[MAXHOSTNAMELEN];
353     int first = 1;
354     char *sp, *p;
355     int baselen = -1;
356     int suid, sgid;
357     int group_list_size = -1;
358     gid_t groups[NGROUPS_MAX];
359     sp = rhost;
360     p = fhost;
361     while (*sp) {
362         if (*sp == '.') {
363             if (baselen == -1)
364                 baselen = sp - rhost;
365             *p++ = *sp++;
366         } else {
367             *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
368         }
369     }
370     *p = '\0';
371     hostf = superuser ? (FILE *) 0 : fopen("/etc/hosts.equiv", "r");
372   again:
373     if (hostf) {
374         if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
375             (void)fclose(hostf);
376             return (0);
377         }
378         (void)fclose(hostf);
379     }
380     if (first == 1 && (_check_rhosts_file || superuser)) {
381         struct stat sbuf;
382         struct passwd *pwd, *getpwnam();
383         char pbuf[MAXPATHLEN];
384
385         first = 0;
386         suid = geteuid();
387         sgid = getegid();
388         group_list_size = getgroups(NGROUPS_MAX, groups);
389         if ((pwd = getpwnam(luser)) == NULL)
390             return (-1);
391         if (setegid(pwd->pw_gid) >= 0)
392             (void)initgroups(luser, pwd->pw_gid);
393         (void)seteuid(pwd->pw_uid);
394         (void)strcpy(pbuf, pwd->pw_dir);
395         (void)strcat(pbuf, "/.rhosts");
396         if ((hostf = fopen(pbuf, "r")) == NULL)
397             goto bad;
398         /*
399          * if owned by someone other than user or root or if
400          * writable by anyone but the owner, quit
401          */
402         if (fstat(fileno(hostf), &sbuf) || sbuf.st_uid
403             && sbuf.st_uid != pwd->pw_uid || sbuf.st_mode & 022) {
404             fclose(hostf);
405             goto bad;
406         }
407         goto again;
408     }
409   bad:
410     if (first == 0) {
411         (void)seteuid(suid);
412         (void)setegid(sgid);
413         if (group_list_size >= 0)
414             (void)setgroups(group_list_size, groups);
415     }
416     return (-1);
417 }
418
419 /* don't make static, used by lpd(8) */
420 _validuser(hostf, rhost, luser, ruser, baselen)
421      char *rhost, *luser, *ruser;
422      FILE *hostf;
423      int baselen;
424 {
425     char *user;
426     char ahost[MAXHOSTNAMELEN * 4];
427     char *p;
428 #ifdef  AFS_AIX32_ENV
429 #include <arpa/nameser.h>
430     int hostmatch, usermatch;
431     char domain[MAXDNAME], *dp;
432
433     dp = NULL;
434     if (getdomainname(domain, sizeof(domain)) == 0)
435         dp = domain;
436 #endif
437     while (fgets(ahost, sizeof(ahost), hostf)) {
438 #ifdef  AFS_AIX32_ENV
439         hostmatch = usermatch = 0;
440         p = ahost;
441         if (*p == '#' || *p == '\n')    /* ignore comments and blanks */
442             continue;
443         while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
444             p++;
445         if (*p == ' ' || *p == '\t') {
446             *p++ = '\0';
447             while (*p == ' ' || *p == '\t')
448                 p++;
449             user = p;
450             while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
451                 p++;
452         } else
453             user = p;
454         *p = '\0';
455         /*
456          *  + - anything goes
457          *  +@<name> - group <name> allowed
458          *  -@<name> - group <name> disallowed
459          *  -<name> - host <name> disallowed
460          */
461         if (ahost[0] == '+' && ahost[1] == 0)
462             hostmatch = 1;
463         else if (ahost[0] == '+' && ahost[1] == '@')
464             hostmatch = innetgr(ahost + 2, rhost, NULL, dp);
465         else if (ahost[0] == '-' && ahost[1] == '@') {
466             if (innetgr(ahost + 2, rhost, NULL, dp))
467                 return (-1);
468         } else if (ahost[0] == '-') {
469             if (_checkhost(rhost, ahost + 1, baselen))
470                 return (-1);
471         } else
472             hostmatch = _checkhost(rhost, ahost, baselen);
473         if (user[0]) {
474             if (user[0] == '+' && user[1] == 0)
475                 usermatch = 1;
476             else if (user[0] == '+' && user[1] == '@')
477                 usermatch = innetgr(user + 2, NULL, ruser, dp);
478             else if (user[0] == '-' && user[1] == '@') {
479                 if (hostmatch && innetgr(user + 2, NULL, ruser, dp))
480                     return (-1);
481             } else if (user[0] == '-') {
482                 if (hostmatch && !strcmp(user + 1, ruser))
483                     return (-1);
484             } else
485                 usermatch = !strcmp(user, ruser);
486         } else
487             usermatch = !strcmp(ruser, luser);
488         if (hostmatch && usermatch)
489             return (0);
490 #else
491         p = ahost;
492         while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
493             *p = isupper(*p) ? tolower(*p) : *p;
494             p++;
495         }
496         if (*p == ' ' || *p == '\t') {
497             *p++ = '\0';
498             while (*p == ' ' || *p == '\t')
499                 p++;
500             user = p;
501             while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
502                 p++;
503         } else
504             user = p;
505         *p = '\0';
506         if (_checkhost(rhost, ahost, baselen)
507             && !strcmp(ruser, *user ? user : luser)) {
508             return (0);
509         }
510 #endif
511     }
512     return (-1);
513 }
514
515 static
516 _checkhost(rhost, lhost, len)
517      char *rhost, *lhost;
518      int len;
519 {
520     static char ldomain[MAXHOSTNAMELEN + 1];
521     static char *domainp = NULL;
522     static int nodomain = 0;
523     char *cp;
524
525 #ifdef  AFS_AIX32_ENV
526     struct hostent *hp;
527     long addr;
528
529     /*
530      * check for ip address and do a lookup to convert to hostname
531      */
532     if (isinet_addr(lhost) && (addr = inet_addr(lhost)) != -1
533         && (hp = gethostbyaddr(&addr, sizeof(addr), AF_INET)))
534         lhost = hp->h_name;
535
536 #endif
537     if (len == -1) {
538 #ifdef  AFS_AIX32_ENV
539         /* see if hostname from file has a domain name */
540         for (cp = lhost; *cp; ++cp) {
541             if (*cp == '.') {
542                 len = cp - lhost;
543                 break;
544             }
545         }
546 #endif
547         return (!strcmp(rhost, lhost));
548     }
549     if (strncmp(rhost, lhost, len))
550         return (0);
551     if (!strcmp(rhost, lhost))
552         return (1);
553 #ifdef  AFS_AIX32_ENV
554     if (*(lhost + len) != '\0' && *(rhost + len) != '\0')
555 #else
556     if (*(lhost + len) != '\0')
557 #endif
558         return (0);
559     if (nodomain)
560         return (0);
561     if (!domainp) {
562         if (gethostname(ldomain, sizeof(ldomain)) == -1) {
563             nodomain = 1;
564             return (0);
565         }
566         ldomain[MAXHOSTNAMELEN] = '\0';
567         if ((domainp = strchr(ldomain, '.')) == NULL) {
568             nodomain = 1;
569             return (0);
570         }
571         for (cp = ++domainp; *cp; ++cp)
572             if (isupper(*cp))
573                 *cp = tolower(*cp);
574     }
575     return (!strcmp(domainp, rhost + len + 1));
576 }