summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/inetd/builtins.c76
1 files changed, 65 insertions, 11 deletions
diff --git a/usr.sbin/inetd/builtins.c b/usr.sbin/inetd/builtins.c
index e3d2013..2ad656c 100644
--- a/usr.sbin/inetd/builtins.c
+++ b/usr.sbin/inetd/builtins.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: builtins.c,v 1.11 1999/07/24 17:06:05 green Exp $
+ * $Id: builtins.c,v 1.12 1999/07/25 23:15:03 green Exp $
*
*/
@@ -307,15 +307,9 @@ echo_stream(s, sep) /* Echo service -- echo data back */
* support.
*/
-/*
- * NOTE: If any of the asprintf()s here fail, rest assured that faulting
- * in the buffers for using snprintf() would have also failed.
- * Asprintf() is the proper way to do what we do.
- */
-
/* ARGSUSED */
void
-iderror(lport, fport, s, er)
+iderror(lport, fport, s, er) /* Generic ident_stream error-sending func */
int lport, fport, s, er;
{
char *p;
@@ -334,7 +328,7 @@ iderror(lport, fport, s, er)
/* ARGSUSED */
void
-ident_stream(s, sep) /* Ident service */
+ident_stream(s, sep) /* Ident service (AKA "auth") */
int s;
struct servtab *sep;
{
@@ -353,8 +347,17 @@ ident_stream(s, sep) /* Ident service */
u_short lport, fport;
inetd_setproctitle(sep->se_service, s);
+ /*
+ * Reset getopt() since we are a fork() but not an exec() from
+ * a parent which used getopt() already.
+ */
optind = 1;
optreset = 1;
+ /*
+ * Take the internal argument vector and count it out to make an
+ * argument count for getopt. This can be used for any internal
+ * service to read arguments and use getopt() easily.
+ */
for (av = sep->se_argv; *av; av++)
argc++;
if (argc) {
@@ -402,6 +405,12 @@ ident_stream(s, sep) /* Ident service */
len = sizeof(sin[1]);
if (getpeername(s, (struct sockaddr *)&sin[1], &len) == -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
+ * "local_port , foreign_port\r\n" (with local being the
+ * server's port and foreign being the client's.)
+ */
FD_ZERO(&fdset);
FD_SET(s, &fdset);
if (select(s + 1, &fdset, NULL, NULL, &tv) == -1)
@@ -416,17 +425,30 @@ ident_stream(s, sep) /* Ident service */
buf[len] = '\0';
if (sscanf(buf, "%hu , %hu", &lport, &fport) != 2)
iderror(0, 0, s, 0);
- if (!rflag)
+ if (!rflag) /* Send HIDDEN-USER immediately if not "real" */
iderror(lport, fport, s, -1);
+ /*
+ * 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.
+ */
sin[0].sin_port = htons(lport);
sin[1].sin_port = htons(fport);
len = sizeof(uc);
if (sysctlbyname("net.inet.tcp.getcred", &uc, &len, sin,
sizeof(sin)) == -1)
iderror(lport, fport, s, errno);
- pw = getpwuid(uc.cr_uid);
+ pw = getpwuid(uc.cr_uid); /* Look up the pw to get the username */
if (pw == NULL)
iderror(lport, fport, s, errno);
+ /*
+ * If enabled, we check for a file named ".noident" in the user's
+ * home directory. If found, we return HIDDEN-USER.
+ */
if (nflag) {
if (asprintf(&p, "%s/.noident", pw->pw_dir) == -1)
iderror(lport, fport, s, errno);
@@ -436,13 +458,30 @@ ident_stream(s, sep) /* Ident service */
}
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) {
FILE *fakeid = NULL;
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.
+ */
seteuid(pw->pw_uid);
setegid(pw->pw_gid);
+ /*
+ * If we were to lstat() here, it would do no good, since it
+ * would introduce a race condition and could be defeated.
+ * Therefore, we open the file we have permissions to open
+ * and if it's not a regular file, we close it and end up
+ * returning the user's real username.
+ */
fakeid = fopen(p, "r");
free(p);
if (fakeid != NULL &&
@@ -454,13 +493,27 @@ ident_stream(s, sep) /* Ident service */
goto printit;
}
fclose(fakeid);
+ /*
+ * Usually, the file will have the desired identity
+ * in the form "identity\n", so we use strtok() to
+ * end the string (which fgets() doesn't do.)
+ */
strtok(buf, "\r\n");
+ /* User names of >16 characters are invalid */
if (strlen(buf) > 16)
buf[16] = '\0';
cp = buf;
+ /* Allow for beginning white space... */
while (isspace(*cp))
cp++;
+ /* ...and ending white space. */
strtok(cp, " \t");
+ /*
+ * 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 || getpwnam(cp))
cp = getpwuid(uc.cr_uid)->pw_name;
} else
@@ -468,6 +521,7 @@ ident_stream(s, sep) /* Ident service */
} else
cp = pw->pw_name;
printit:
+ /* Finally, we make and send the reply. */
if (asprintf(&p, "%d , %d : USERID : %s : %s\r\n", lport, fport, osname,
cp) == -1) {
syslog(LOG_ERR, "asprintf: %m");
OpenPOWER on IntegriCloud