]> git.ipfire.org Git - thirdparty/glibc.git/blame - inet/rcmd.c
rcmd.c: Fix indentation in last commit
[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
28f540f4 58#include <sys/param.h>
cd68221f 59#include <sys/poll.h>
28f540f4
RM
60#include <sys/socket.h>
61#include <sys/stat.h>
62
63#include <netinet/in.h>
64#include <arpa/inet.h>
65
e4cf5070 66#include <alloca.h>
28f540f4
RM
67#include <signal.h>
68#include <fcntl.h>
69#include <netdb.h>
70#include <unistd.h>
71#include <pwd.h>
72#include <errno.h>
73#include <stdio.h>
2706ee38 74#include <stdio_ext.h>
28f540f4
RM
75#include <ctype.h>
76#include <string.h>
4360eafd 77#include <libintl.h>
c62603bf 78#include <stdlib.h>
520ec963 79#include <wchar.h>
e76afb7b 80#include <sys/uio.h>
a992f506 81#include <sigsetops.h>
2ed26bca 82#include <shlib-compat.h>
88677348 83#include <set-freeres.h>
28f540f4 84
d68171ed 85
d9fee042 86int __ivaliduser (FILE *, uint32_t, const char *, const char *);
3846463e
UD
87static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
88 const char *, const char *, const char *);
2d29aba9
UD
89static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
90 int superuser, const char *ruser,
91 const char *luser, const char *rhost);
92static int ruserok_sa (struct sockaddr *ra, size_t ralen,
93 int superuser, const char *ruser,
94 const char *luser);
95int iruserok_af (const void *raddr, int superuser, const char *ruser,
96 const char *luser, sa_family_t af);
d9fee042 97int iruserok (uint32_t raddr, int superuser, const char *ruser,
70e22d49 98 const char *luser);
85c165be 99
e2ec9b4d
RM
100libc_hidden_proto (iruserok_af)
101
88677348 102static char *ahostbuf;
28f540f4
RM
103
104int
41075ae3
JM
105rcmd_af (char **ahost, u_short rport, const char *locuser, const char *remuser,
106 const char *cmd, int *fd2p, sa_family_t af)
28f540f4 107{
2d29aba9 108 char paddr[INET6_ADDRSTRLEN];
2d29aba9 109 struct addrinfo hints, *res, *ai;
6cc8844f
UD
110 union
111 {
eb286115
SE
112 struct sockaddr sa;
113 struct sockaddr_storage ss;
114 struct sockaddr_in sin;
115 struct sockaddr_in6 sin6;
6cc8844f 116 } from;
cd68221f 117 struct pollfd pfd[2];
a992f506
ZW
118 sigset_t mask, omask;
119
28f540f4 120 pid_t pid;
2d29aba9 121 int s, lport, timo, error;
28f540f4 122 char c;
2d29aba9
UD
123 int refused;
124 char num[8];
6ac52e83 125 ssize_t n;
2d29aba9 126
f1143750 127 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
2d29aba9
UD
128 {
129 __set_errno (EAFNOSUPPORT);
130 return -1;
131 }
28f540f4 132
50304ef0 133 pid = __getpid();
e4cf5070 134
2d29aba9
UD
135 memset(&hints, '\0', sizeof(hints));
136 hints.ai_flags = AI_CANONNAME;
137 hints.ai_family = af;
138 hints.ai_socktype = SOCK_STREAM;
4aebaa6b 139 (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
2d29aba9
UD
140 error = getaddrinfo(*ahost, num, &hints, &res);
141 if (error) {
df6f8969 142 if (error == EAI_NONAME && *ahost != NULL)
8a259a23 143 __fxprintf(NULL, "%s: Unknown host\n", *ahost);
df6f8969
UD
144 else
145 __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
df6f8969
UD
146 gai_strerror(error));
147
312be3f9 148 return -1;
2d29aba9 149 }
e4cf5070 150
cd68221f
UD
151 pfd[0].events = POLLIN;
152 pfd[1].events = POLLIN;
153
2d29aba9 154 if (res->ai_canonname){
c877418f 155 free (ahostbuf);
ae65d4f3 156 ahostbuf = __strdup (res->ai_canonname);
c877418f 157 if (ahostbuf == NULL) {
7eeb05a3 158 freeaddrinfo (res);
8a259a23 159 __fxprintf(NULL, "%s",
df6f8969
UD
160 _("rcmd: Cannot allocate memory\n"));
161 return -1;
c877418f 162 }
2d29aba9 163 *ahost = ahostbuf;
c877418f 164 } else
2d29aba9
UD
165 *ahost = NULL;
166 ai = res;
167 refused = 0;
a992f506
ZW
168 __sigemptyset(&mask);
169 __sigaddset(&mask, SIGURG);
170 __sigprocmask (SIG_BLOCK, &mask, &omask);
28f540f4 171 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
51028f34
UD
172 char errbuf[200];
173
2d29aba9 174 s = rresvport_af(&lport, ai->ai_family);
28f540f4 175 if (s < 0) {
df6f8969 176 if (errno == EAGAIN)
8a259a23 177 __fxprintf(NULL, "%s", _("\
df6f8969
UD
178rcmd: socket: All ports in use\n"));
179 else
8a259a23 180 __fxprintf(NULL, "rcmd: socket: %m\n");
df6f8969 181
a992f506 182 __sigprocmask (SIG_SETMASK, &omask, 0);
2d29aba9 183 freeaddrinfo(res);
d705269e 184 return -1;
28f540f4 185 }
50304ef0 186 __fcntl(s, F_SETOWN, pid);
2d29aba9 187 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
28f540f4 188 break;
50304ef0 189 (void)__close(s);
28f540f4
RM
190 if (errno == EADDRINUSE) {
191 lport--;
192 continue;
193 }
2d29aba9
UD
194 if (errno == ECONNREFUSED)
195 refused = 1;
196 if (ai->ai_next != NULL) {
28f540f4 197 int oerrno = errno;
51028f34 198 char *buf = NULL;
28f540f4 199
2d29aba9
UD
200 getnameinfo(ai->ai_addr, ai->ai_addrlen,
201 paddr, sizeof(paddr),
202 NULL, 0,
203 NI_NUMERICHOST);
51028f34 204
383bd1c5
UD
205 if (__asprintf (&buf, _("connect to address %s: "),
206 paddr) >= 0)
207 {
8a259a23 208 __fxprintf(NULL, "%s", buf);
383bd1c5
UD
209 free (buf);
210 }
c4029823 211 __set_errno (oerrno);
28f540f4 212 perror(0);
2d29aba9
UD
213 ai = ai->ai_next;
214 getnameinfo(ai->ai_addr, ai->ai_addrlen,
215 paddr, sizeof(paddr),
216 NULL, 0,
217 NI_NUMERICHOST);
383bd1c5
UD
218 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
219 {
8a259a23 220 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
221 free (buf);
222 }
2d29aba9
UD
223 continue;
224 }
225 if (refused && timo <= 16) {
4aebaa6b 226 (void)__sleep(timo);
2d29aba9
UD
227 timo *= 2;
228 ai = res;
229 refused = 0;
28f540f4
RM
230 continue;
231 }
2d29aba9 232 freeaddrinfo(res);
8a259a23 233 (void)__fxprintf(NULL, "%s: %s\n", *ahost,
df6f8969 234 __strerror_r(errno, errbuf, sizeof (errbuf)));
a992f506 235 __sigprocmask (SIG_SETMASK, &omask, 0);
d705269e 236 return -1;
28f540f4
RM
237 }
238 lport--;
239 if (fd2p == 0) {
50304ef0 240 __write(s, "", 1);
28f540f4
RM
241 lport = 0;
242 } else {
243 char num[8];
2d29aba9 244 int s2 = rresvport_af(&lport, ai->ai_family), s3;
1c3f65c2 245 socklen_t len = ai->ai_addrlen;
28f540f4
RM
246
247 if (s2 < 0)
248 goto bad;
b2bffca2 249 __listen(s2, 1);
50304ef0 250 (void)__snprintf(num, sizeof(num), "%d", lport);
c3301189 251 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
51028f34
UD
252 char *buf = NULL;
253
383bd1c5
UD
254 if (__asprintf (&buf, _("\
255rcmd: write (setting up stderr): %m\n")) >= 0)
256 {
8a259a23 257 __fxprintf(NULL, "%s", buf);
383bd1c5
UD
258 free (buf);
259 }
50304ef0 260 (void)__close(s2);
28f540f4
RM
261 goto bad;
262 }
cd68221f
UD
263 pfd[0].fd = s;
264 pfd[1].fd = s2;
c4029823 265 __set_errno (0);
cd68221f 266 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
51028f34
UD
267 char *buf = NULL;
268
383bd1c5
UD
269 if ((errno != 0
270 && __asprintf(&buf, _("\
271rcmd: poll (setting up stderr): %m\n")) >= 0)
272 || (errno == 0
273 && __asprintf(&buf, _("\
274poll: protocol failure in circuit setup\n")) >= 0))
275 {
8a259a23 276 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
277 free (buf);
278 }
50304ef0 279 (void)__close(s2);
28f540f4
RM
280 goto bad;
281 }
6cc8844f
UD
282 s3 = TEMP_FAILURE_RETRY (accept(s2, &from.sa, &len));
283 switch (from.sa.sa_family) {
2d29aba9 284 case AF_INET:
6cc8844f 285 rport = ntohs(from.sin.sin_port);
2d29aba9
UD
286 break;
287 case AF_INET6:
6cc8844f 288 rport = ntohs(from.sin6.sin6_port);
2d29aba9
UD
289 break;
290 default:
291 rport = 0;
292 break;
293 }
50304ef0 294 (void)__close(s2);
28f540f4 295 if (s3 < 0) {
8a259a23 296 (void)__fxprintf(NULL, "rcmd: accept: %m\n");
28f540f4
RM
297 lport = 0;
298 goto bad;
299 }
300 *fd2p = s3;
2d29aba9
UD
301
302 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
51028f34
UD
303 char *buf = NULL;
304
383bd1c5
UD
305 if (__asprintf(&buf, _("\
306socket: protocol failure in circuit setup\n")) >= 0)
307 {
8a259a23 308 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
309 free (buf);
310 }
28f540f4
RM
311 goto bad2;
312 }
313 }
e76afb7b
UD
314 struct iovec iov[3] =
315 {
316 [0] = { .iov_base = (void *) locuser,
317 .iov_len = strlen (locuser) + 1 },
318 [1] = { .iov_base = (void *) remuser,
319 .iov_len = strlen (remuser) + 1 },
320 [2] = { .iov_base = (void *) cmd,
321 .iov_len = strlen (cmd) + 1 }
322 };
323 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
324 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
6ac52e83 325 if (n != 1) {
51028f34
UD
326 char *buf = NULL;
327
383bd1c5
UD
328 if ((n == 0
329 && __asprintf(&buf, _("rcmd: %s: short read"),
330 *ahost) >= 0)
331 || (n != 0
332 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
333 {
8a259a23 334 __fxprintf (NULL, "%s", buf);
383bd1c5
UD
335 free (buf);
336 }
28f540f4
RM
337 goto bad2;
338 }
339 if (c != 0) {
50304ef0
UD
340 while (__read(s, &c, 1) == 1) {
341 (void)__write(STDERR_FILENO, &c, 1);
28f540f4
RM
342 if (c == '\n')
343 break;
344 }
345 goto bad2;
346 }
a992f506 347 __sigprocmask (SIG_SETMASK, &omask, 0);
2d29aba9 348 freeaddrinfo(res);
d705269e 349 return s;
28f540f4
RM
350bad2:
351 if (lport)
50304ef0 352 (void)__close(*fd2p);
28f540f4 353bad:
50304ef0 354 (void)__close(s);
a992f506 355 __sigprocmask (SIG_SETMASK, &omask, 0);
2d29aba9 356 freeaddrinfo(res);
d705269e 357 return -1;
28f540f4 358}
a585ba22 359libc_hidden_def (rcmd_af)
28f540f4
RM
360
361int
41075ae3
JM
362rcmd (char **ahost, u_short rport, const char *locuser, const char *remuser,
363 const char *cmd, int *fd2p)
2d29aba9
UD
364{
365 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
366}
367
368int
9d46370c 369rresvport_af (int *alport, sa_family_t family)
28f540f4 370{
eb286115
SE
371 union {
372 struct sockaddr generic;
373 struct sockaddr_in in;
374 struct sockaddr_in6 in6;
375 } ss;
28f540f4 376 int s;
2d29aba9 377 size_t len;
3846463e 378 uint16_t *sport;
28f540f4 379
2d29aba9
UD
380 switch(family){
381 case AF_INET:
382 len = sizeof(struct sockaddr_in);
eb286115 383 sport = &ss.in.sin_port;
2d29aba9
UD
384 break;
385 case AF_INET6:
386 len = sizeof(struct sockaddr_in6);
eb286115 387 sport = &ss.in6.sin6_port;
2d29aba9
UD
388 break;
389 default:
390 __set_errno (EAFNOSUPPORT);
391 return -1;
392 }
b8129a41 393 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
4aebaa6b 394 s = __socket(family, SOCK_STREAM, 0);
28f540f4 395 if (s < 0)
d705269e 396 return -1;
2d29aba9
UD
397
398 memset (&ss, '\0', sizeof(ss));
399#ifdef SALEN
eb286115 400 ss.generic.__ss_len = len;
2d29aba9 401#endif
eb286115 402 ss.generic.sa_family = family;
2d29aba9 403
54e1cabc
UD
404 /* Ignore invalid values. */
405 if (*alport < IPPORT_RESERVED / 2)
406 *alport = IPPORT_RESERVED / 2;
407 else if (*alport >= IPPORT_RESERVED)
408 *alport = IPPORT_RESERVED - 1;
409
410 int start = *alport;
411 do {
a8322b4f 412 *sport = htons((uint16_t) *alport);
eb286115 413 if (__bind(s, &ss.generic, len) >= 0)
d705269e 414 return s;
28f540f4 415 if (errno != EADDRINUSE) {
50304ef0 416 (void)__close(s);
d705269e 417 return -1;
28f540f4 418 }
54e1cabc
UD
419 if ((*alport)-- == IPPORT_RESERVED/2)
420 *alport = IPPORT_RESERVED - 1;
421 } while (*alport != start);
2d29aba9
UD
422 (void)__close(s);
423 __set_errno (EAGAIN);
424 return -1;
425}
a585ba22 426libc_hidden_def (rresvport_af)
2d29aba9
UD
427
428int
9d46370c 429rresvport (int *alport)
2d29aba9
UD
430{
431 return rresvport_af(alport, AF_INET);
28f540f4
RM
432}
433
434int __check_rhosts_file = 1;
435char *__rcmd_errstr;
436
2d29aba9 437int
41075ae3
JM
438ruserok_af (const char *rhost, int superuser, const char *ruser,
439 const char *luser, sa_family_t af)
2d29aba9
UD
440{
441 struct addrinfo hints, *res, *res0;
442 int gai;
443 int ret;
444
445 memset (&hints, '\0', sizeof(hints));
446 hints.ai_family = af;
447 gai = getaddrinfo(rhost, NULL, &hints, &res0);
448 if (gai)
449 return -1;
450 ret = -1;
451 for (res=res0; res; res=res->ai_next)
452 if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
453 superuser, ruser, luser, rhost) == 0){
454 ret = 0;
455 break;
456 }
457 freeaddrinfo(res0);
458 return (ret);
459}
a585ba22
RM
460libc_hidden_def (ruserok_af)
461
28f540f4 462int
41075ae3
JM
463ruserok (const char *rhost, int superuser, const char *ruser,
464 const char *luser)
28f540f4 465{
2d29aba9 466 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
28f540f4
RM
467}
468
cb343854
UD
469/* Extremely paranoid file open function. */
470static FILE *
3846463e 471iruserfopen (const char *file, uid_t okuser)
cb343854 472{
52a5fe70 473 struct __stat64_t64 st;
cb343854
UD
474 char *cp = NULL;
475 FILE *res = NULL;
476
477 /* If not a regular file, if owned by someone other than user or
478 root, if writeable by anyone but the owner, or if hardlinked
479 anywhere, quit. */
52a5fe70 480 if (__lstat64_time64 (file, &st))
cb343854
UD
481 cp = _("lstat failed");
482 else if (!S_ISREG (st.st_mode))
483 cp = _("not regular file");
484 else
485 {
312be3f9 486 res = fopen (file, "rce");
cb343854
UD
487 if (!res)
488 cp = _("cannot open");
52a5fe70 489 else if (__fstat64_time64 (fileno (res), &st) < 0)
cb343854
UD
490 cp = _("fstat failed");
491 else if (st.st_uid && st.st_uid != okuser)
492 cp = _("bad owner");
493 else if (st.st_mode & (S_IWGRP|S_IWOTH))
494 cp = _("writeable by other than owner");
495 else if (st.st_nlink > 1)
496 cp = _("hard linked somewhere");
497 }
498
499 /* If there were any problems, quit. */
500 if (cp != NULL)
501 {
502 __rcmd_errstr = cp;
503 if (res)
504 fclose (res);
505 return NULL;
506 }
507
2706ee38
UD
508 /* No threads use this stream. */
509 __fsetlocking (res, FSETLOCKING_BYCALLER);
510
cb343854
UD
511 return res;
512}
513
28f540f4
RM
514/*
515 * New .rhosts strategy: We are passed an ip address. We spin through
516 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
517 * has ip addresses, we don't have to trust a nameserver. When it
518 * contains hostnames, we spin through the list of addresses the nameserver
519 * gives us and look for a match.
520 *
521 * Returns 0 if ok, -1 if not ok.
522 */
85c165be 523static int
41075ae3
JM
524ruserok2_sa (struct sockaddr *ra, size_t ralen, int superuser,
525 const char *ruser, const char *luser, const char *rhost)
28f540f4 526{
d1e9545e 527 FILE *hostf = NULL;
4dba81ea 528 int isbad = -1;
28f540f4 529
cb343854
UD
530 if (!superuser)
531 hostf = iruserfopen (_PATH_HEQUIV, 0);
532
533 if (hostf)
534 {
2d29aba9 535 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
cb343854
UD
536 fclose (hostf);
537
538 if (!isbad)
539 return 0;
540 }
541
542 if (__check_rhosts_file || superuser)
543 {
544 char *pbuf;
545 struct passwd pwdbuf, *pwd;
546 size_t dirlen;
547 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
548 char *buffer = __alloca (buflen);
549 uid_t uid;
550
1d863dc0
UD
551 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
552 || pwd == NULL)
d705269e 553 return -1;
cb343854
UD
554
555 dirlen = strlen (pwd->pw_dir);
556 pbuf = alloca (dirlen + sizeof "/.rhosts");
557 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
558 "/.rhosts", sizeof "/.rhosts");
559
560 /* Change effective uid while reading .rhosts. If root and
561 reading an NFS mounted file system, can't read files that
562 are protected read/write owner only. */
50304ef0 563 uid = __geteuid ();
1629adf2 564 if (seteuid (pwd->pw_uid) < 0)
589cccc8 565 return -1;
1629adf2 566
cb343854
UD
567 hostf = iruserfopen (pbuf, pwd->pw_uid);
568
569 if (hostf != NULL)
570 {
312be3f9
UD
571 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
572 fclose (hostf);
cb343854
UD
573 }
574
1629adf2 575 if (seteuid (uid) < 0)
589cccc8 576 return -1;
cb343854
UD
577 return isbad;
578 }
579 return -1;
28f540f4 580}
2d29aba9
UD
581/*
582 * ruserok_sa() is now discussed on ipng, so
583 * currently disabled for external use
584 */
41075ae3
JM
585static int
586ruserok_sa (struct sockaddr *ra, size_t ralen, int superuser,
587 const char *ruser, const char *luser)
2d29aba9 588{
3846463e 589 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
2d29aba9 590}
28f540f4 591
85c165be
UD
592/* This is the exported version. */
593int
41075ae3
JM
594iruserok_af (const void *raddr, int superuser, const char *ruser,
595 const char *luser, sa_family_t af)
2d29aba9 596{
eb286115
SE
597 union {
598 struct sockaddr generic;
599 struct sockaddr_in in;
600 struct sockaddr_in6 in6;
601 } ra;
2d29aba9
UD
602 size_t ralen;
603
604 memset (&ra, '\0', sizeof(ra));
605 switch (af){
606 case AF_INET:
eb286115
SE
607 ra.in.sin_family = AF_INET;
608 memcpy (&ra.in.sin_addr, raddr, sizeof(struct in_addr));
2d29aba9
UD
609 ralen = sizeof(struct sockaddr_in);
610 break;
611 case AF_INET6:
eb286115
SE
612 ra.in6.sin6_family = AF_INET6;
613 memcpy (&ra.in6.sin6_addr, raddr, sizeof(struct in6_addr));
2d29aba9
UD
614 ralen = sizeof(struct sockaddr_in6);
615 break;
616 default:
617 return 0;
618 }
eb286115 619 return ruserok_sa (&ra.generic, ralen, superuser, ruser, luser);
2d29aba9 620}
e2ec9b4d
RM
621libc_hidden_def (iruserok_af)
622
2d29aba9 623int
d9fee042 624iruserok (uint32_t raddr, int superuser, const char *ruser, const char *luser)
85c165be 625{
2d29aba9 626 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
85c165be
UD
627}
628
2ed26bca
FW
629#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_37)
630/* Previously used by lpd. Current lpd versions have their own copy. */
631int attribute_compat_text_section
d9fee042 632__ivaliduser (FILE *hostf, uint32_t raddr, const char *luser,
41075ae3 633 const char *ruser)
28f540f4 634{
2d29aba9
UD
635 struct sockaddr_in ra;
636 memset(&ra, '\0', sizeof(ra));
637 ra.sin_family = AF_INET;
638 ra.sin_addr.s_addr = raddr;
639 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
640 luser, ruser, "-");
28f540f4 641}
2ed26bca
FW
642compat_symbol (libc, __ivaliduser, __ivaliduser, GLIBC_2_0);
643#endif
85c165be
UD
644
645/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
28f540f4 646static int
3846463e
UD
647__checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
648 const char *rhost)
28f540f4 649{
2d29aba9 650 struct addrinfo hints, *res0, *res;
2d29aba9
UD
651 char raddr[INET6_ADDRSTRLEN];
652 int match;
85c165be 653 int negate=1; /* Multiply return with this to get -1 instead of 1 */
85c165be
UD
654
655 /* Check nis netgroup. */
656 if (strncmp ("+@", lhost, 2) == 0)
657 return innetgr (&lhost[2], rhost, NULL, NULL);
658
659 if (strncmp ("-@", lhost, 2) == 0)
660 return -innetgr (&lhost[2], rhost, NULL, NULL);
661
662 /* -host */
663 if (strncmp ("-", lhost,1) == 0) {
664 negate = -1;
665 lhost++;
666 } else if (strcmp ("+",lhost) == 0) {
667 return 1; /* asking for trouble, but ok.. */
668 }
28f540f4
RM
669
670 /* Try for raw ip address first. */
2d29aba9
UD
671 /* XXX */
672 if (getnameinfo(ra, ralen,
673 raddr, sizeof(raddr), NULL, 0,
30f1226b
UD
674 NI_NUMERICHOST) == 0
675 && strcmp(raddr, lhost) == 0)
676 return negate;
28f540f4
RM
677
678 /* Better be a hostname. */
2d29aba9
UD
679 match = 0;
680 memset(&hints, '\0', sizeof(hints));
681 hints.ai_family = ra->sa_family;
682 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
683 /* Spin through ip addresses. */
3846463e
UD
684 for (res = res0; res; res = res->ai_next)
685 {
686 if (res->ai_family == ra->sa_family
687 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
688 {
689 match = 1;
690 break;
691 }
692 }
693 freeaddrinfo (res0);
2d29aba9 694 }
3846463e 695 return negate * match;
85c165be
UD
696}
697
698/* Returns 1 on positive match, 0 on no match, -1 on negative match. */
699static int
3846463e 700__icheckuser (const char *luser, const char *ruser)
85c165be
UD
701{
702 /*
703 luser is user entry from .rhosts/hosts.equiv file
704 ruser is user id on remote host
705 */
85c165be
UD
706
707 /* [-+]@netgroup */
708 if (strncmp ("+@", luser, 2) == 0)
709 return innetgr (&luser[2], NULL, ruser, NULL);
710
711 if (strncmp ("-@", luser,2) == 0)
712 return -innetgr (&luser[2], NULL, ruser, NULL);
713
714 /* -user */
715 if (strncmp ("-", luser, 1) == 0)
716 return -(strcmp (&luser[1], ruser) == 0);
717
718 /* + */
719 if (strcmp ("+", luser) == 0)
720 return 1;
721
722 /* simple string match */
723 return strcmp (ruser, luser) == 0;
724}
725
726/*
727 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
728 */
729static int
3846463e 730__isempty (char *p)
85c165be
UD
731{
732 while (*p && isspace (*p)) {
733 ++p;
734 }
735
736 return (*p == '\0' || *p == '#') ? 1 : 0 ;
737}
738
739/*
740 * Returns 0 if positive match, -1 if _not_ ok.
741 */
742static int
41075ae3
JM
743__validuser2_sa (FILE *hostf, struct sockaddr *ra, size_t ralen,
744 const char *luser, const char *ruser, const char *rhost)
85c165be 745{
2e09a79a
JM
746 const char *user;
747 char *p;
85c165be
UD
748 int hcheck, ucheck;
749 char *buf = NULL;
750 size_t bufsize = 0;
24f25de6 751 int retval = -1;
85c165be
UD
752
753 while (__getline (&buf, &bufsize, hostf) > 0) {
754 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
312be3f9 755 p = buf;
85c165be
UD
756
757 /* Skip empty or comment lines */
758 if (__isempty (p)) {
759 continue;
760 }
761
85c165be 762 for (;*p && !isspace(*p); ++p) {
4caef86c 763 *p = _tolower (*p);
85c165be
UD
764 }
765
766 /* Next we want to find the permitted name for the remote user. */
767 if (*p == ' ' || *p == '\t') {
768 /* <nul> terminate hostname and skip spaces */
769 for (*p++='\0'; *p && isspace (*p); ++p);
770
771 user = p; /* this is the user's name */
772 while (*p && !isspace (*p))
773 ++p; /* find end of user's name */
774 } else
775 user = p;
776
777 *p = '\0'; /* <nul> terminate username (+host?) */
778
779 /* buf -> host(?) ; user -> username(?) */
8b59c733
CD
780 if (*buf == '\0')
781 break;
782 if (*user == '\0')
783 user = luser;
784
785 /* First check the user part. In a naive implementation we
786 would check the host part first, then the user. However,
787 if we check the user first and reject the entry we will
788 have saved doing any host lookups to normalize the comparison
789 and that likely saves several DNS queries. Therefore we
790 check the user first. */
791 ucheck = __icheckuser (user, ruser);
792
793 /* Either we found the user, or we didn't and this is a
794 negative host check. We must do the negative host lookup
795 in order to preserve the semantics of stopping on this line
796 before processing others. */
797 if (ucheck != 0 || *buf == '-') {
798
799 /* Next check host part. */
800 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
801
802 /* Negative '-host user(?)' match? */
803 if (hcheck < 0)
804 break;
85c165be 805
8b59c733
CD
806 /* Positive 'host user' match? */
807 if (hcheck > 0 && ucheck > 0) {
24f25de6
UD
808 retval = 0;
809 break;
810 }
85c165be 811
8b59c733
CD
812 /* Negative 'host -user' match? */
813 if (hcheck > 0 && ucheck < 0)
814 break;
85c165be 815
8b59c733 816 /* Neither, go on looking for match. */
85c165be
UD
817 }
818 }
819
72e6cdfa 820 free (buf);
24f25de6
UD
821
822 return retval;
28f540f4 823}
88677348
AZN
824
825weak_alias (ahostbuf, __libc_rcmd_freemem_ptr)