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