summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authordwmalone <dwmalone@FreeBSD.org>2001-06-04 11:43:29 +0000
committerdwmalone <dwmalone@FreeBSD.org>2001-06-04 11:43:29 +0000
commit650fe0907f39b13780c222ec3a8a9fc7cf299884 (patch)
treee2f129c0c50f79ecd1aeab228c579d201b9d8732 /usr.sbin
parent69da75afd39e60a5671d98dc70bda3bcbc30b73b (diff)
downloadFreeBSD-src-650fe0907f39b13780c222ec3a8a9fc7cf299884.zip
FreeBSD-src-650fe0907f39b13780c222ec3a8a9fc7cf299884.tar.gz
This patch cleans up the ident stuff in inetd. The code which has
been patched so many times it was a bit of a mess. There are style, code and man page cleanups. The following are the functional changes: The RFC only permits the returning of 4 possible error codes, make sure we only return these (PR 27636). Use MAXLOGNAME to determine the longest usernames. Add a -i flag, which returns the uid instead of the username (this is from a PR 25787, which also contained alot of the cleanups in this patch). PR: 25787, 27636 Partially Submitted by: Arne.Dag.Fidjestol@idi.ntnu.no Reviewed by: Arne.Dag.Fidjestol@idi.ntnu.no, green MFC after: 3 weeks
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/inetd/builtins.c229
-rw-r--r--usr.sbin/inetd/inetd.837
-rw-r--r--usr.sbin/inetd/inetd.h2
3 files changed, 145 insertions, 123 deletions
diff --git a/usr.sbin/inetd/builtins.c b/usr.sbin/inetd/builtins.c
index 49cd12d..88435a0 100644
--- a/usr.sbin/inetd/builtins.c
+++ b/usr.sbin/inetd/builtins.c
@@ -306,15 +306,21 @@ echo_stream(s, sep) /* Echo service -- echo data back */
* support.
*/
+/* RFC 1413 says the following are the only errors you can return. */
+#define ID_INVALID "INVALID-PORT" /* Port number improperly specified. */
+#define ID_NOUSER "NO-USER" /* Port not in use/not identifable. */
+#define ID_HIDDEN "HIDDEN-USER" /* Hiden at user's request. */
+#define ID_UNKNOWN "UNKNOWN-ERROR" /* Everything else. */
+
/* ARGSUSED */
void
iderror(lport, fport, s, er) /* Generic ident_stream error-sending func */
- int lport, fport, s, er;
+ int lport, fport, s;
+ char *er;
{
char *p;
- asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport,
- er == -1 ? "HIDDEN-USER" : er ? strerror(er) : "UNKNOWN-ERROR");
+ asprintf(&p, "%d , %d : ERROR : %s\r\n", lport, fport, er);
if (p == NULL) {
syslog(LOG_ERR, "asprintf: %m");
exit(EX_OSERR);
@@ -345,13 +351,13 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
}, to;
struct passwd *pw = NULL;
fd_set fdset;
- char buf[BUFSIZE], *cp = NULL, *p, **av, *osname = NULL, garbage[7], e;
- char *fallback = NULL;
+ char buf[BUFSIZE], *p, **av, *osname = NULL, e;
+ char idbuf[MAXLOGNAME] = ""; /* Big enough to hold uid in decimal. */
socklen_t socklen;
ssize_t ssize;
size_t size, bufsiz;
- int c, fflag = 0, nflag = 0, rflag = 0, argc = 0, usedfallback = 0;
- int gflag = 0, Fflag = 0, getcredfail = 0, onreadlen;
+ int c, fflag = 0, nflag = 0, rflag = 0, argc = 0;
+ int gflag = 0, iflag = 0, Fflag = 0, getcredfail = 0, onreadlen;
u_short lport, fport;
inetd_setproctitle(sep->se_service, s);
@@ -373,10 +379,11 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
size_t i;
u_int32_t random;
- while ((c = getopt(argc, sep->se_argv, "d:fFgno:rt:")) != -1)
+ while ((c = getopt(argc, sep->se_argv, "d:fFgino:rt:")) != -1)
switch (c) {
case 'd':
- fallback = optarg;
+ if (!gflag)
+ strlcpy(idbuf, optarg, sizeof(idbuf));
break;
case 'f':
fflag = 1;
@@ -394,21 +401,22 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
* gives a more optimal way to reload the
* random number only when necessary.
*
- * I'm using base-36, so I need at least 6
- * bits; round it up to 8 bits to make it
- * easier.
+ * 32 bits from arc4random corrisponds to
+ * about 6 base-36 digits, so we reseed evey 6.
*/
- for (i = 0; i < sizeof(garbage) - 1; i++) {
- const char *const base36 =
+ for (i = 0; i < sizeof(idbuf) - 1; i++) {
+ static const char *const base36 =
"0123456789"
"abcdefghijklmnopqrstuvwxyz";
- if (i % (sizeof(random) * 8 / 8) == 0)
+ if (i % 6 == 0)
random = arc4random();
- garbage[i] =
- base36[(random & 0xff) % 36];
- random >>= 8;
+ idbuf[i] = base36[random % 36];
+ random /= 36;
}
- garbage[i] = '\0';
+ idbuf[i] = '\0';
+ break;
+ case 'i':
+ iflag = 1;
break;
case 'n':
nflag = 1;
@@ -423,6 +431,7 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
switch (sscanf(optarg, "%d.%d", &sec, &usec)) {
case 2:
tv.tv_usec = usec;
+ /* FALLTHROUGH */
case 1:
tv.tv_sec = sec;
break;
@@ -438,15 +447,10 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
}
if (osname == NULL) {
if (uname(&un) == -1)
- iderror(0, 0, s, errno);
+ iderror(0, 0, s, ID_UNKNOWN);
osname = un.sysname;
}
- socklen = sizeof(ss[0]);
- if (getsockname(s, (struct sockaddr *)&ss[0], &socklen) == -1)
- iderror(0, 0, s, errno);
- socklen = sizeof(ss[1]);
- if (getpeername(s, (struct sockaddr *)&ss[1], &socklen) == -1)
- iderror(0, 0, s, errno);
+
/*
* We're going to prepare for and execute reception of a
* packet of data from the user. The data is in the format
@@ -476,14 +480,14 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
break;
FD_SET(s, &fdset);
if (select(s + 1, &fdset, NULL, NULL, &tv) == -1)
- iderror(0, 0, s, errno);
+ iderror(0, 0, s, ID_UNKNOWN);
if (ioctl(s, FIONREAD, &onreadlen) == -1)
- iderror(0, 0, s, errno);
+ iderror(0, 0, s, ID_UNKNOWN);
if (onreadlen > bufsiz)
onreadlen = bufsiz;
ssize = read(s, &buf[size], (size_t)onreadlen);
if (ssize == -1)
- iderror(0, 0, s, errno);
+ iderror(0, 0, s, ID_UNKNOWN);
else if (ssize == 0)
break;
bufsiz -= ssize;
@@ -494,37 +498,38 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
buf[size] = '\0';
/* Read two characters, and check for a delimiting character */
if (sscanf(buf, "%hu , %hu%c", &lport, &fport, &e) != 3 || isdigit(e))
- iderror(0, 0, s, 0);
- if (gflag) {
- cp = garbage;
+ iderror(0, 0, s, ID_INVALID);
+
+ /* Send garbage? */
+ if (gflag)
goto printit;
- }
-
+
/*
* If not "real" (-r), send a HIDDEN-USER error for everything.
* If -d is used to set a fallback username, this is used to
* override it, and the fallback is returned instead.
*/
if (!rflag) {
- if (fallback == NULL)
- iderror(lport, fport, s, -1);
- else {
- cp = fallback;
- goto printit;
- }
+ if (*idbuf == '\0')
+ iderror(lport, fport, s, ID_HIDDEN);
+ goto printit;
}
-
+
/*
* We take the input and construct an array of two sockaddr_ins
* which contain the local address information and foreign
* address information, respectively, used to look up the
* credentials for the socket (which are returned by the
- * sysctl "net.inet.tcp.getcred" when we call it.) The
- * arrays have been filled in above via get{peer,sock}name(),
- * so right here we are only setting the ports.
+ * sysctl "net.inet.tcp.getcred" when we call it.)
*/
+ socklen = sizeof(ss[0]);
+ if (getsockname(s, (struct sockaddr *)&ss[0], &socklen) == -1)
+ iderror(lport, fport, s, ID_UNKNOWN);
+ socklen = sizeof(ss[1]);
+ if (getpeername(s, (struct sockaddr *)&ss[1], &socklen) == -1)
+ iderror(lport, fport, s, ID_UNKNOWN);
if (ss[0].ss_family != ss[1].ss_family)
- iderror(lport, fport, s, EINVAL);
+ iderror(lport, fport, s, ID_UNKNOWN);
size = sizeof(uc);
switch (ss[0].ss_family) {
case AF_INET:
@@ -552,48 +557,54 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
break;
}
if (getcredfail != 0) {
- if (fallback == NULL) /* Use a default, if asked to */
- iderror(lport, fport, s, getcredfail);
- usedfallback = 1;
- } else {
- /* Look up the pw to get the username */
- errno = 0;
- pw = getpwuid(uc.cr_uid);
+ if (*idbuf == '\0')
+ iderror(lport, fport, s,
+ getcredfail == ENOENT ? ID_NOUSER : ID_UNKNOWN);
+ goto printit;
}
- if (pw == NULL && !usedfallback) /* No such user... */
- iderror(lport, fport, s, errno != 0 ? errno : ENOENT);
+
+ /* Look up the pw to get the username and home directory*/
+ errno = 0;
+ pw = getpwuid(uc.cr_uid);
+ if (pw == NULL)
+ iderror(lport, fport, s, errno == 0 ? ID_NOUSER : ID_UNKNOWN);
+
+ if (iflag)
+ snprintf(idbuf, sizeof(idbuf), "%u", (unsigned)pw->pw_uid);
+ else
+ strlcpy(idbuf, pw->pw_name, sizeof(idbuf));
+
/*
* If enabled, we check for a file named ".noident" in the user's
* home directory. If found, we return HIDDEN-USER.
*/
- if (nflag && !usedfallback) {
+ if (nflag) {
if (asprintf(&p, "%s/.noident", pw->pw_dir) == -1)
- iderror(lport, fport, s, errno);
+ iderror(lport, fport, s, ID_UNKNOWN);
if (lstat(p, &sb) == 0) {
free(p);
- iderror(lport, fport, s, -1);
+ iderror(lport, fport, s, ID_HIDDEN);
}
free(p);
}
+
/*
* Here, if enabled, we read a user's ".fakeid" file in their
* home directory. It consists of a line containing the name
* they want.
*/
- if (fflag && !usedfallback) {
- FILE *fakeid = NULL;
+ if (fflag) {
int fakeid_fd;
- if (asprintf(&p, "%s/.fakeid", pw->pw_dir) == -1)
- iderror(lport, fport, s, errno);
/*
* Here we set ourself to effectively be the user, so we don't
* open any files we have no permission to open, especially
* symbolic links to sensitive root-owned files or devices.
*/
if (initgroups(pw->pw_name, pw->pw_gid) == -1)
- iderror(lport, fport, s, errno);
- seteuid(pw->pw_uid);
+ iderror(lport, fport, s, ID_UNKNOWN);
+ if (seteuid(pw->pw_uid) == -1)
+ iderror(lport, fport, s, ID_UNKNOWN);
/*
* We can't stat() here since that would be a race
* condition.
@@ -601,60 +612,58 @@ ident_stream(s, sep) /* Ident service (AKA "auth") */
* and if it's not a regular file, we close it and end up
* returning the user's real username.
*/
+ if (asprintf(&p, "%s/.fakeid", pw->pw_dir) == -1)
+ iderror(lport, fport, s, ID_UNKNOWN);
fakeid_fd = open(p, O_RDONLY | O_NONBLOCK);
free(p);
- if (fakeid_fd != -1 && fstat(fakeid_fd, &sb) != -1 &&
- S_ISREG(sb.st_mode) &&
- (fakeid = fdopen(fakeid_fd, "r")) != NULL) {
- buf[sizeof(buf) - 1] = '\0';
- if (fgets(buf, sizeof(buf), fakeid) == NULL) {
- cp = pw->pw_name;
- fclose(fakeid);
- goto printit;
- }
- /*
- * Usually, the file will have the desired identity
- * in the form "identity\n", so we use strcspn() to
- * end the string (which fgets() doesn't do.)
- */
- buf[strcspn(buf, "\r\n")] = '\0';
- cp = buf;
- /* Allow for beginning white space... */
- while (isspace(*cp))
- cp++;
- /* ...and ending white space. */
- cp[strcspn(cp, " \t")] = '\0';
- /* User names of >16 characters are invalid */
- if (strlen(cp) > 16)
- cp[16] = '\0';
- /*
- * If the name is a zero-length string or matches
- * the name of another user, it's invalid, so
- * we will return their real identity instead.
- */
-
- if (!*cp || (!Fflag && getpwnam(cp))) {
- errno = 0;
- pw = getpwuid(uc.cr_uid);
- if (pw == NULL)
- iderror(lport, fport, s,
- errno != 0 ? errno : ENOENT);
- cp = pw->pw_name;
+ if (fakeid_fd == -1 || fstat(fakeid_fd, &sb) == -1 ||
+ !S_ISREG(sb.st_mode))
+ goto fakeid_fail;
+
+ if ((ssize = read(fakeid_fd, buf, sizeof(buf) - 1)) < 0)
+ goto fakeid_fail;
+ buf[ssize] = '\0';
+
+ /*
+ * Usually, the file will have the desired identity
+ * in the form "identity\n". Allow for leading white
+ * space and trailing white space/end of line.
+ */
+ p = buf;
+ p += strspn(p, " \t");
+ p[strcspn(p, " \t\r\n")] = '\0';
+ if (strlen(p) > MAXLOGNAME - 1) /* Too long (including nul)? */
+ p[MAXLOGNAME - 1] = '\0';
+
+ /*
+ * If the name is a zero-length string or matches it
+ * the id or name of another user (unless permitted by -F)
+ * then it is invalid.
+ */
+ if (*p == '\0')
+ goto fakeid_fail;
+ if (!Fflag) {
+ if (iflag) {
+ if (p[strspn(p, "0123456789")] == '\0' &&
+ getpwuid(atoi(p)) != NULL)
+ goto fakeid_fail;
+ } else {
+ if (getpwnam(p) != NULL)
+ goto fakeid_fail;
}
- } else
- cp = pw->pw_name;
- if (fakeid != NULL)
- fclose(fakeid);
- else if (fakeid_fd != -1)
+ }
+
+ strlcpy(idbuf, p, sizeof(idbuf));
+
+fakeid_fail:
+ if (fakeid_fd != -1)
close(fakeid_fd);
- } else if (!usedfallback)
- cp = pw->pw_name;
- else
- cp = fallback;
+ }
+
printit:
/* Finally, we make and send the reply. */
if (asprintf(&p, "%d , %d : USERID : %s : %s\r\n", lport, fport, osname,
- cp) == -1) {
+ idbuf) == -1) {
syslog(LOG_ERR, "asprintf: %m");
exit(EX_OSERR);
}
diff --git a/usr.sbin/inetd/inetd.8 b/usr.sbin/inetd/inetd.8
index 3cd6e5a..fda2267 100644
--- a/usr.sbin/inetd/inetd.8
+++ b/usr.sbin/inetd/inetd.8
@@ -455,6 +455,21 @@ If the real
service is disabled,
return this username for every request.
This is primarily useful when running this service on a NAT machine.
+.It Fl g
+Instead of returning
+the user's name to the ident requester,
+report a
+username made up of random alphanumeric characters,
+e.g.
+.Dq c0c993 .
+The
+.Fl g
+flag overrides not only the user names,
+but also any fallback name,
+.Pa .fakeid
+or
+.Pa .noident
+files.
.It Fl t Xo
.Ar sec Ns Op . Ns Ar usec
.Xc
@@ -465,6 +480,8 @@ Offer a real
.Dq auth
service, as per RFC 1413.
All the remaining flags apply only in this case.
+.It Fl i
+Return numeric user IDs instead of usernames.
.It Fl f
If the file
.Pa .fakeid
@@ -474,29 +491,25 @@ If the the username found in
.Pa .fakeid
is that of an existing user,
then the real username is reported.
+If the
+.Fl i
+flag is also given then the username in
+.Pa .fakeid
+is checked against existing user IDs instead.
.It Fl F
same as
.Fl f
but without the restriction that the username in
.Pa .fakeid
must not match an existing user.
-.It Fl g
-Instead of returning the user's name to the ident requester, report a
-username made up of random alphanumeric characters, e.g.
-.Dq c0c993 .
-The
-.Fl g
-flag overrides not only the user names, but also any
-.Pa .fakeid
-or
-.Pa .noident
-files.
.It Fl n
If the file
.Pa .noident
exists in the home directory of the identified user, return
.Dq ERROR\ : HIDDEN-USER .
-instead.
+This overrides any
+.Pa fakeid
+file which might exist.
.It Fl o Ar osname
Use
.Ar osname
diff --git a/usr.sbin/inetd/inetd.h b/usr.sbin/inetd/inetd.h
index c0c9e64..c11f4ad 100644
--- a/usr.sbin/inetd/inetd.h
+++ b/usr.sbin/inetd/inetd.h
@@ -122,7 +122,7 @@ void endconfig __P((void));
struct servtab *enter __P((struct servtab *));
void freeconfig __P((struct servtab *));
struct servtab *getconfigent __P((void));
-void iderror __P((int, int, int, int));
+void iderror __P((int, int, int, char *));
void ident_stream __P((int, struct servtab *));
void machtime_dg __P((int, struct servtab *));
void machtime_stream __P((int, struct servtab *));
OpenPOWER on IntegriCloud