]> git.ipfire.org Git - thirdparty/glibc.git/blame - inet/rcmd.c
Clean up internal fopen uses
[thirdparty/glibc.git] / inet / rcmd.c
CommitLineData
2d29aba9
UD
1/*
2 * Copyright (C) 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
28f540f4
RM
29/*
30 * Copyright (c) 1983, 1993, 1994
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
28f540f4
RM
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58#if defined(LIBC_SCCS) && !defined(lint)
59static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
60#endif /* LIBC_SCCS and not lint */
61
62#include <sys/param.h>
cd68221f 63#include <sys/poll.h>
28f540f4
RM
64#include <sys/socket.h>
65#include <sys/stat.h>
66
67#include <netinet/in.h>
68#include <arpa/inet.h>
69
e4cf5070 70#include <alloca.h>
28f540f4
RM
71#include <signal.h>
72#include <fcntl.h>
73#include <netdb.h>
74#include <unistd.h>
75#include <pwd.h>
76#include <errno.h>
77#include <stdio.h>
2706ee38 78#include <stdio_ext.h>
28f540f4
RM
79#include <ctype.h>
80#include <string.h>
4360eafd 81#include <libintl.h>
c62603bf 82#include <stdlib.h>
520ec963 83#include <wchar.h>
e76afb7b 84#include <sys/uio.h>
28f540f4 85
d68171ed 86
3846463e
UD
87int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
88static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
89 const char *, const char *, const char *);
2d29aba9
UD
90static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
91 int superuser, const char *ruser,
92 const char *luser, const char *rhost);
93static int ruserok_sa (struct sockaddr *ra, size_t ralen,
94 int superuser, const char *ruser,
95 const char *luser);
96int iruserok_af (const void *raddr, int superuser, const char *ruser,
97 const char *luser, sa_family_t af);
70e22d49
UD
98int iruserok (u_int32_t raddr, int superuser, const char *ruser,
99 const char *luser);
85c165be 100
e2ec9b4d
RM
101libc_hidden_proto (iruserok_af)
102
c877418f 103libc_freeres_ptr(static char *ahostbuf);
28f540f4
RM
104
105int
2d29aba9 106rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
28f540f4
RM
107 char **ahost;
108 u_short rport;
109 const char *locuser, *remuser, *cmd;
110 int *fd2p;
2d29aba9 111 sa_family_t af;
28f540f4 112{
2d29aba9 113 char paddr[INET6_ADDRSTRLEN];
2d29aba9 114 struct addrinfo hints, *res, *ai;
6cc8844f
UD
115 union
116 {
117 struct sockaddr sa;
118 struct sockaddr_storage ss;
119 struct sockaddr_in sin;
120 struct sockaddr_in6 sin6;
121 } from;
cd68221f 122 struct pollfd pfd[2];
c224a18a 123 int32_t oldmask;
28f540f4 124 pid_t pid;
2d29aba9 125 int s, lport, timo, error;
28f540f4 126 char c;
2d29aba9
UD
127 int refused;
128 char num[8];
6ac52e83 129 ssize_t n;
2d29aba9 130
f1143750 131 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
2d29aba9
UD
132 {
133 __set_errno (EAFNOSUPPORT);
134 return -1;
135 }
28f540f4 136
50304ef0 137 pid = __getpid();
e4cf5070 138
2d29aba9
UD
139 memset(&hints, '\0', sizeof(hints));
140 hints.ai_flags = AI_CANONNAME;
141 hints.ai_family = af;
142 hints.ai_socktype = SOCK_STREAM;
4aebaa6b 143 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
2d29aba9
UD
144 error = getaddrinfo(*ahost, num, &hints, &res);
145 if (error) {
df6f8969 146 if (error == EAI_NONAME && *ahost != NULL)
8a259a23 147 __fxprintf(NULL, "%s: Unknown host\n", *ahost);
df6f8969
UD
148 else
149 __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
df6f8969
UD
150 gai_strerror(error));
151
312be3f9 152 return -1;
2d29aba9 153 }
e4cf5070 154
cd68221f
UD
155 pfd[0].events = POLLIN;
156 pfd[1].events = POLLIN;
157
2d29aba9 158 if (res->ai_canonname){
c877418f
RM
159 free (ahostbuf);
160 ahostbuf = strdup (res->ai_canonname);
161 if (ahostbuf == NULL) {
8a259a23 162 __fxprintf(NULL, "%s",
df6f8969
UD
163 _("rcmd: Cannot allocate memory\n"));
164 return -1;
c877418f 165 }
2d29aba9 166 *ahost = ahostbuf;
c877418f 167 } else
2d29aba9
UD
168 *ahost = NULL;
169 ai = res;
170 refused = 0;
50304ef0 171 oldmask = __sigblock(sigmask(SIGURG));
28f540f4 172 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
51028f34
UD
173 char errbuf[200];
174
2d29aba9 175 s = rresvport_af(&lport, ai->ai_family);
28f540f4 176 if (s < 0) {
df6f8969 177 if (errno == EAGAIN)
8a259a23 178 __fxprintf(NULL, "%s", _("\
df6f8969
UD
179rcmd: socket: All ports in use\n"));
180 else
8a259a23 181 __fxprintf(NULL, "rcmd: socket: %m\n");
df6f8969 182
50304ef0 183 __sigsetmask(oldmask);
2d29aba9 184 freeaddrinfo(res);
d705269e 185 return -1;
28f540f4 186 }
50304ef0 187 __fcntl(s, F_SETOWN, pid);
2d29aba9 188 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
28f540f4 189 break;
50304ef0 190 (void)__close(s);
28f540f4
RM
191 if (errno == EADDRINUSE) {
192 lport--;
193 continue;
194 }
2d29aba9
UD
195 if (errno == ECONNREFUSED)
196 refused = 1;
197 if (ai->ai_next != NULL) {
28f540f4 198 int oerrno = errno;
51028f34 199 char *buf = NULL;
28f540f4 200
2d29aba9
UD
201 getnameinfo(ai->ai_addr, ai->ai_addrlen,
202 paddr, sizeof(paddr),
203 NULL, 0,
204 NI_NUMERICHOST);
51028f34 205
383bd1c5
UD
206 if (__asprintf (&buf, _("connect to address %s: "),
207 paddr) >= 0)
208 {
8a259a23 209 __fxprintf(NULL, "%s", buf);
383bd1c5
UD
210 free (buf);
211 }
c4029823 212 __set_errno (oerrno);
28f540f4 213 perror(0);
2d29aba9
UD
214 ai = ai->ai_next;
215 getnameinfo(ai->ai_addr, ai->ai_addrlen,
216 paddr, sizeof(paddr),
217 NULL, 0,
218 NI_NUMERICHOST);
383bd1c5
UD
219 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
220 {
8a259a23 221 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
222 free (buf);
223 }
2d29aba9
UD
224 continue;
225 }
226 if (refused && timo <= 16) {
4aebaa6b 227 (void)__sleep(timo);
2d29aba9
UD
228 timo *= 2;
229 ai = res;
230 refused = 0;
28f540f4
RM
231 continue;
232 }
2d29aba9 233 freeaddrinfo(res);
8a259a23 234 (void)__fxprintf(NULL, "%s: %s\n", *ahost,
df6f8969 235 __strerror_r(errno, errbuf, sizeof (errbuf)));
50304ef0 236 __sigsetmask(oldmask);
d705269e 237 return -1;
28f540f4
RM
238 }
239 lport--;
240 if (fd2p == 0) {
50304ef0 241 __write(s, "", 1);
28f540f4
RM
242 lport = 0;
243 } else {
244 char num[8];
2d29aba9 245 int s2 = rresvport_af(&lport, ai->ai_family), s3;
1c3f65c2 246 socklen_t len = ai->ai_addrlen;
28f540f4
RM
247
248 if (s2 < 0)
249 goto bad;
b2bffca2 250 __listen(s2, 1);
50304ef0 251 (void)__snprintf(num, sizeof(num), "%d", lport);
c3301189 252 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
51028f34
UD
253 char *buf = NULL;
254
383bd1c5
UD
255 if (__asprintf (&buf, _("\
256rcmd: write (setting up stderr): %m\n")) >= 0)
257 {
8a259a23 258 __fxprintf(NULL, "%s", buf);
383bd1c5
UD
259 free (buf);
260 }
50304ef0 261 (void)__close(s2);
28f540f4
RM
262 goto bad;
263 }
cd68221f
UD
264 pfd[0].fd = s;
265 pfd[1].fd = s2;
c4029823 266 __set_errno (0);
cd68221f 267 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
51028f34
UD
268 char *buf = NULL;
269
383bd1c5
UD
270 if ((errno != 0
271 && __asprintf(&buf, _("\
272rcmd: poll (setting up stderr): %m\n")) >= 0)
273 || (errno == 0
274 && __asprintf(&buf, _("\
275poll: protocol failure in circuit setup\n")) >= 0))
276 {
8a259a23 277 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
278 free (buf);
279 }
50304ef0 280 (void)__close(s2);
28f540f4
RM
281 goto bad;
282 }
6cc8844f
UD
283 s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
284 switch (from.sa.sa_family) {
2d29aba9 285 case AF_INET:
6cc8844f 286 rport = ntohs(from.sin.sin_port);
2d29aba9
UD
287 break;
288 case AF_INET6:
6cc8844f 289 rport = ntohs(from.sin6.sin6_port);
2d29aba9
UD
290 break;
291 default:
292 rport = 0;
293 break;
294 }
50304ef0 295 (void)__close(s2);
28f540f4 296 if (s3 < 0) {
8a259a23 297 (void)__fxprintf(NULL, "rcmd: accept: %m\n");
28f540f4
RM
298 lport = 0;
299 goto bad;
300 }
301 *fd2p = s3;
2d29aba9
UD
302
303 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
51028f34
UD
304 char *buf = NULL;
305
383bd1c5
UD
306 if (__asprintf(&buf, _("\
307socket: protocol failure in circuit setup\n")) >= 0)
308 {
8a259a23 309 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
310 free (buf);
311 }
28f540f4
RM
312 goto bad2;
313 }
314 }
e76afb7b
UD
315 struct iovec iov[3] =
316 {
317 [0] = { .iov_base = (void *) locuser,
318 .iov_len = strlen (locuser) + 1 },
319 [1] = { .iov_base = (void *) remuser,
320 .iov_len = strlen (remuser) + 1 },
321 [2] = { .iov_base = (void *) cmd,
322 .iov_len = strlen (cmd) + 1 }
323 };
324 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
325 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
6ac52e83 326 if (n != 1) {
51028f34
UD
327 char *buf = NULL;
328
383bd1c5
UD
329 if ((n == 0
330 && __asprintf(&buf, _("rcmd: %s: short read"),
331 *ahost) >= 0)
332 || (n != 0
333 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
334 {
8a259a23 335 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
336 free (buf);
337 }
28f540f4
RM
338 goto bad2;
339 }
340 if (c != 0) {
50304ef0
UD
341 while (__read(s, &c, 1) == 1) {
342 (void)__write(STDERR_FILENO, &c, 1);
28f540f4
RM
343 if (c == '\n')
344 break;
345 }
346 goto bad2;
347 }
50304ef0 348 __sigsetmask(oldmask);
2d29aba9 349 freeaddrinfo(res);
d705269e 350 return s;
28f540f4
RM
351bad2:
352 if (lport)
50304ef0 353 (void)__close(*fd2p);
28f540f4 354bad:
50304ef0
UD
355 (void)__close(s);
356 __sigsetmask(oldmask);
2d29aba9 357 freeaddrinfo(res);
d705269e 358 return -1;
28f540f4 359}
a585ba22 360libc_hidden_def (rcmd_af)
28f540f4
RM
361
362int
2d29aba9
UD
363rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
364 char **ahost;
365 u_short rport;
366 const char *locuser, *remuser, *cmd;
367 int *fd2p;
368{
369 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
370}
371
372int
373rresvport_af(alport, family)
28f540f4 374 int *alport;
2d29aba9 375 sa_family_t family;
28f540f4 376{
2d29aba9 377 struct sockaddr_storage ss;
28f540f4 378 int s;
2d29aba9 379 size_t len;
3846463e 380 uint16_t *sport;
28f540f4 381
2d29aba9
UD
382 switch(family){
383 case AF_INET:
384 len = sizeof(struct sockaddr_in);
385 sport = &((struct sockaddr_in *)&ss)->sin_port;
386 break;
387 case AF_INET6:
388 len = sizeof(struct sockaddr_in6);
389 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
390 break;
391 default:
392 __set_errno (EAFNOSUPPORT);
393 return -1;
394 }
4aebaa6b 395 s = __socket(family, SOCK_STREAM, 0);
28f540f4 396 if (s < 0)
d705269e 397 return -1;
2d29aba9
UD
398
399 memset (&ss, '\0', sizeof(ss));
400#ifdef SALEN
401 ss.__ss_len = len;
402#endif
d1ce5f2a 403 ss.ss_family = family;
2d29aba9 404
54e1cabc
UD
405 /* Ignore invalid values. */
406 if (*alport < IPPORT_RESERVED / 2)
407 *alport = IPPORT_RESERVED / 2;
408 else if (*alport >= IPPORT_RESERVED)
409 *alport = IPPORT_RESERVED - 1;
410
411 int start = *alport;
412 do {
a8322b4f 413 *sport = htons((uint16_t) *alport);
b2bffca2 414 if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
d705269e 415 return s;
28f540f4 416 if (errno != EADDRINUSE) {
50304ef0 417 (void)__close(s);
d705269e 418 return -1;
28f540f4 419 }
54e1cabc
UD
420 if ((*alport)-- == IPPORT_RESERVED/2)
421 *alport = IPPORT_RESERVED - 1;
422 } while (*alport != start);
2d29aba9
UD
423 (void)__close(s);
424 __set_errno (EAGAIN);
425 return -1;
426}
a585ba22 427libc_hidden_def (rresvport_af)
2d29aba9
UD
428
429int
430rresvport(alport)
431 int *alport;
432{
433 return rresvport_af(alport, AF_INET);
28f540f4
RM
434}
435
436int __check_rhosts_file = 1;
437char *__rcmd_errstr;
438
2d29aba9
UD
439int
440ruserok_af(rhost, superuser, ruser, luser, af)
441 const char *rhost, *ruser, *luser;
442 int superuser;
443 sa_family_t af;
444{
445 struct addrinfo hints, *res, *res0;
446 int gai;
447 int ret;
448
449 memset (&hints, '\0', sizeof(hints));
450 hints.ai_family = af;
451 gai = getaddrinfo(rhost, NULL, &hints, &res0);
452 if (gai)
453 return -1;
454 ret = -1;
455 for (res=res0; res; res=res->ai_next)
456 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
457 superuser, ruser, luser, rhost) == 0){
458 ret = 0;
459 break;
460 }
461 freeaddrinfo(res0);
462 return (ret);
463}
a585ba22
RM
464libc_hidden_def (ruserok_af)
465
28f540f4
RM
466int
467ruserok(rhost, superuser, ruser, luser)
468 const char *rhost, *ruser, *luser;
469 int superuser;
470{
2d29aba9 471 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
28f540f4
RM
472}
473
cb343854
UD
474/* Extremely paranoid file open function. */
475static FILE *
3846463e 476iruserfopen (const char *file, uid_t okuser)
cb343854 477{
8edf6e0d 478 struct stat64 st;
cb343854
UD
479 char *cp = NULL;
480 FILE *res = NULL;
481
482 /* If not a regular file, if owned by someone other than user or
483 root, if writeable by anyone but the owner, or if hardlinked
484 anywhere, quit. */
8edf6e0d 485 if (__lxstat64 (_STAT_VER, file, &st))
cb343854
UD
486 cp = _("lstat failed");
487 else if (!S_ISREG (st.st_mode))
488 cp = _("not regular file");
489 else
490 {
312be3f9 491 res = fopen (file, "rce");
cb343854
UD
492 if (!res)
493 cp = _("cannot open");
8edf6e0d 494 else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
cb343854
UD
495 cp = _("fstat failed");
496 else if (st.st_uid && st.st_uid != okuser)
497 cp = _("bad owner");
498 else if (st.st_mode & (S_IWGRP|S_IWOTH))
499 cp = _("writeable by other than owner");
500 else if (st.st_nlink > 1)
501 cp = _("hard linked somewhere");
502 }
503
504 /* If there were any problems, quit. */
505 if (cp != NULL)
506 {
507 __rcmd_errstr = cp;
508 if (res)
509 fclose (res);
510 return NULL;
511 }
512
2706ee38
UD
513 /* No threads use this stream. */
514 __fsetlocking (res, FSETLOCKING_BYCALLER);
515
cb343854
UD
516 return res;
517}
518
28f540f4
RM
519/*
520 * New .rhosts strategy: We are passed an ip address. We spin through
521 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
522 * has ip addresses, we don't have to trust a nameserver. When it
523 * contains hostnames, we spin through the list of addresses the nameserver
524 * gives us and look for a match.
525 *
526 * Returns 0 if ok, -1 if not ok.
527 */
85c165be 528static int
2d29aba9
UD
529ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
530 struct sockaddr *ra;
531 size_t ralen;
cb343854 532 int superuser;
85c165be 533 const char *ruser, *luser, *rhost;
28f540f4 534{
d1e9545e 535 FILE *hostf = NULL;
4dba81ea 536 int isbad = -1;
28f540f4 537
cb343854
UD
538 if (!superuser)
539 hostf = iruserfopen (_PATH_HEQUIV, 0);
540
541 if (hostf)
542 {
2d29aba9 543 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
cb343854
UD
544 fclose (hostf);
545
546 if (!isbad)
547 return 0;
548 }
549
550 if (__check_rhosts_file || superuser)
551 {
552 char *pbuf;
553 struct passwd pwdbuf, *pwd;
554 size_t dirlen;
555 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
556 char *buffer = __alloca (buflen);
557 uid_t uid;
558
1d863dc0
UD
559 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
560 || pwd == NULL)
d705269e 561 return -1;
cb343854
UD
562
563 dirlen = strlen (pwd->pw_dir);
564 pbuf = alloca (dirlen + sizeof "/.rhosts");
565 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
566 "/.rhosts", sizeof "/.rhosts");
567
568 /* Change effective uid while reading .rhosts. If root and
569 reading an NFS mounted file system, can't read files that
570 are protected read/write owner only. */
50304ef0 571 uid = __geteuid ();
cb343854
UD
572 seteuid (pwd->pw_uid);
573 hostf = iruserfopen (pbuf, pwd->pw_uid);
574
575 if (hostf != NULL)
576 {
312be3f9
UD
577 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
578 fclose (hostf);
cb343854
UD
579 }
580
581 seteuid (uid);
582 return isbad;
583 }
584 return -1;
28f540f4 585}
2d29aba9
UD
586/*
587 * ruserok_sa() is now discussed on ipng, so
588 * currently disabled for external use
589 */
590static int ruserok_sa(ra, ralen, superuser, ruser, luser)
591 struct sockaddr *ra;
592 size_t ralen;
593 int superuser;
594 const char *ruser, *luser;
595{
3846463e 596 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
2d29aba9 597}
28f540f4 598
85c165be
UD
599/* This is the exported version. */
600int
2d29aba9
UD
601iruserok_af (raddr, superuser, ruser, luser, af)
602 const void *raddr;
603 int superuser;
604 const char *ruser, *luser;
605 sa_family_t af;
606{
607 struct sockaddr_storage ra;
608 size_t ralen;
609
610 memset (&ra, '\0', sizeof(ra));
611 switch (af){
612 case AF_INET:
6cc8844f 613 ra.ss_family = AF_INET;
2d29aba9
UD
614 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
615 sizeof(struct in_addr));
616 ralen = sizeof(struct sockaddr_in);
617 break;
618 case AF_INET6:
6cc8844f 619 ra.ss_family = AF_INET6;
2d29aba9 620 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
312be3f9 621 sizeof(struct in6_addr));
2d29aba9
UD
622 ralen = sizeof(struct sockaddr_in6);
623 break;
624 default:
625 return 0;
626 }
627 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
628}
e2ec9b4d
RM
629libc_hidden_def (iruserok_af)
630
2d29aba9 631int
85c165be
UD
632iruserok (raddr, superuser, ruser, luser)
633 u_int32_t raddr;
634 int superuser;
635 const char *ruser, *luser;
636{
2d29aba9 637 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
85c165be
UD
638}
639
28f540f4
RM
640/*
641 * XXX
642 * Don't make static, used by lpd(8).
643 *
85c165be
UD
644 * This function is not used anymore. It is only present because lpd(8)
645 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
646 * argument. This means that netgroups won't work in .rhost/hosts.equiv
647 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
648 * or PAM.
28f540f4
RM
649 * Returns 0 if ok, -1 if not ok.
650 */
651int
652__ivaliduser(hostf, raddr, luser, ruser)
653 FILE *hostf;
c224a18a 654 u_int32_t raddr;
28f540f4
RM
655 const char *luser, *ruser;
656{
2d29aba9
UD
657 struct sockaddr_in ra;
658 memset(&ra, '\0', sizeof(ra));
659 ra.sin_family = AF_INET;
660 ra.sin_addr.s_addr = raddr;
661 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
662 luser, ruser, "-");
28f540f4
RM
663}
664
85c165be
UD
665
666/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
28f540f4 667static int
dfd2257a 668internal_function
3846463e
UD
669__checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
670 const char *rhost)
28f540f4 671{
2d29aba9 672 struct addrinfo hints, *res0, *res;
2d29aba9
UD
673 char raddr[INET6_ADDRSTRLEN];
674 int match;
85c165be 675 int negate=1; /* Multiply return with this to get -1 instead of 1 */
85c165be
UD
676
677 /* Check nis netgroup. */
678 if (strncmp ("+@", lhost, 2) == 0)
679 return innetgr (&lhost[2], rhost, NULL, NULL);
680
681 if (strncmp ("-@", lhost, 2) == 0)
682 return -innetgr (&lhost[2], rhost, NULL, NULL);
683
684 /* -host */
685 if (strncmp ("-", lhost,1) == 0) {
686 negate = -1;
687 lhost++;
688 } else if (strcmp ("+",lhost) == 0) {
689 return 1; /* asking for trouble, but ok.. */
690 }
28f540f4
RM
691
692 /* Try for raw ip address first. */
2d29aba9
UD
693 /* XXX */
694 if (getnameinfo(ra, ralen,
695 raddr, sizeof(raddr), NULL, 0,
30f1226b
UD
696 NI_NUMERICHOST) == 0
697 && strcmp(raddr, lhost) == 0)
698 return negate;
28f540f4
RM
699
700 /* Better be a hostname. */
2d29aba9
UD
701 match = 0;
702 memset(&hints, '\0', sizeof(hints));
703 hints.ai_family = ra->sa_family;
704 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
705 /* Spin through ip addresses. */
3846463e
UD
706 for (res = res0; res; res = res->ai_next)
707 {
708 if (res->ai_family == ra->sa_family
709 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
710 {
711 match = 1;
712 break;
713 }
714 }
715 freeaddrinfo (res0);
2d29aba9 716 }
3846463e 717 return negate * match;
85c165be
UD
718}
719
720/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
721static int
722internal_function
3846463e 723__icheckuser (const char *luser, const char *ruser)
85c165be
UD
724{
725 /*
726 luser is user entry from .rhosts/hosts.equiv file
727 ruser is user id on remote host
728 */
85c165be
UD
729
730 /* [-+]@netgroup */
731 if (strncmp ("+@", luser, 2) == 0)
732 return innetgr (&luser[2], NULL, ruser, NULL);
733
734 if (strncmp ("-@", luser,2) == 0)
735 return -innetgr (&luser[2], NULL, ruser, NULL);
736
737 /* -user */
738 if (strncmp ("-", luser, 1) == 0)
739 return -(strcmp (&luser[1], ruser) == 0);
740
741 /* + */
742 if (strcmp ("+", luser) == 0)
743 return 1;
744
745 /* simple string match */
746 return strcmp (ruser, luser) == 0;
747}
748
749/*
750 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
751 */
752static int
3846463e 753__isempty (char *p)
85c165be
UD
754{
755 while (*p && isspace (*p)) {
756 ++p;
757 }
758
759 return (*p == '\0' || *p == '#') ? 1 : 0 ;
760}
761
762/*
763 * Returns 0 if positive match, -1 if _not_ ok.
764 */
765static int
2d29aba9 766__validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
85c165be 767 FILE *hostf;
2d29aba9
UD
768 struct sockaddr *ra;
769 size_t ralen;
85c165be
UD
770 const char *luser, *ruser, *rhost;
771{
772 register const char *user;
773 register char *p;
774 int hcheck, ucheck;
775 char *buf = NULL;
776 size_t bufsize = 0;
24f25de6 777 int retval = -1;
85c165be
UD
778
779 while (__getline (&buf, &bufsize, hostf) > 0) {
780 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
312be3f9 781 p = buf;
85c165be
UD
782
783 /* Skip empty or comment lines */
784 if (__isempty (p)) {
785 continue;
786 }
787
85c165be 788 for (;*p && !isspace(*p); ++p) {
4caef86c 789 *p = _tolower (*p);
85c165be
UD
790 }
791
792 /* Next we want to find the permitted name for the remote user. */
793 if (*p == ' ' || *p == '\t') {
794 /* <nul> terminate hostname and skip spaces */
795 for (*p++='\0'; *p && isspace (*p); ++p);
796
797 user = p; /* this is the user's name */
798 while (*p && !isspace (*p))
799 ++p; /* find end of user's name */
800 } else
801 user = p;
802
803 *p = '\0'; /* <nul> terminate username (+host?) */
804
805 /* buf -> host(?) ; user -> username(?) */
806
807 /* First check host part */
2d29aba9 808 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
85c165be
UD
809
810 if (hcheck < 0)
24f25de6 811 break;
85c165be
UD
812
813 if (hcheck) {
814 /* Then check user part */
815 if (! (*user))
816 user = luser;
817
818 ucheck = __icheckuser (user, ruser);
819
820 /* Positive 'host user' match? */
24f25de6
UD
821 if (ucheck > 0) {
822 retval = 0;
823 break;
824 }
85c165be
UD
825
826 /* Negative 'host -user' match? */
827 if (ucheck < 0)
24f25de6 828 break;
85c165be
UD
829
830 /* Neither, go on looking for match */
831 }
832 }
833
72e6cdfa 834 free (buf);
24f25de6
UD
835
836 return retval;
28f540f4 837}