/*
 * Copyright (c) 1983 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#define KERNEL
#include "ixemul.h"
#include <pwd.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>

int _check_rhosts_file = 1;
int _validuser(FILE *hostf, char *rhost, const char *luser, const char *ruser, int baselen);

int
ruserok(const char *rhost, int superuser, const char *ruser, const char *luser) {
    FILE *hostf;
    char fhost[MAXHOSTNAMELEN];
    int first = 1;
    register char *sp, *p;
    int baselen = -1;

    sp = (char *)rhost;
    p = fhost;
    while (*sp) {
	if (*sp == '.') {
	    if (baselen == -1)
		baselen = sp - rhost;
	    *p++ = *sp++;
	}
	else {
	    *p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
	}
    }
    *p = '\0';
    hostf = superuser ? (FILE *)0 : fopen(_PATH_HEQUIV, "r");
r_again:
    if (hostf) {
	if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
	    (void) fclose(hostf);
	    return(0);
	}
	(void) fclose(hostf);
    }
    if (first == 1 && (_check_rhosts_file || superuser)) {
	struct stat sbuf;
	struct passwd *pwd;
	char pbuf[MAXPATHLEN];

	first = 0;
	if ((pwd = getpwnam(luser)) == NULL)
	    return(-1);

	(void)strcpy(pbuf, pwd->pw_dir);
	(void)strcat(pbuf, "/.rhosts");
	if ((hostf = fopen(pbuf, "r")) == NULL)
	    return(-1);
	/*
	 * if owned by someone other than user or root or if
	 * writeable by anyone but the owner, quit
	 */
	if (fstat(fileno(hostf), &sbuf) ||
	    (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) ||
	    sbuf.st_mode & 022) {
	    fclose(hostf);
	    return(-1);
	}
	goto r_again;
    }
    return (-1);
}

/* don't make static, used by lpd(8) */
int
_validuser(FILE *hostf, char *rhost, const char *luser, const char *ruser, int baselen) {
	register char *p;
	char *user, ahost[MAXHOSTNAMELEN];
	static int _checkhost();

    while (syscall(SYS_fgets,ahost, sizeof (ahost), hostf)) {
	    p = ahost;
	    while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
		*p = isupper(*p) ? tolower(*p) : *p;
		p++;
	    }
	    if (*p == ' ' || *p == '\t') {
		*p++ = '\0';
		while (*p == ' ' || *p == '\t')
		    p++;
		user = p;
		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
		    p++;
	    }
	else  { /* brackets here? indentation suggests it */
		user = p;
		*p = '\0';
		if (_checkhost(rhost, ahost, baselen) &&
		    !strcmp(ruser, *user ? user : luser)) {
			return (0);
		}
	}
    }
    return (-1);
}

static int
_checkhost(char *rhost, char *lhost, int len) {
    static char ldomain[MAXHOSTNAMELEN + 1];
    static char *domainp = NULL;
    static int nodomain = 0;
    register char *cp;

    if (len == -1)
	return(!strcmp(rhost, lhost));

    if (strncmp(rhost, lhost, len))
	return(0);

    if (!strcmp(rhost, lhost))
	return(1);

    if (*(lhost + len) != '\0')
	return(0);

    if (nodomain)
	return(0);

    if (!domainp) {
	if (gethostname(ldomain, sizeof(ldomain)) == -1) {
	    nodomain = 1;
	    return(0);
	}
	ldomain[MAXHOSTNAMELEN] = NULL;
	if ((domainp = index(ldomain, '.')) == (char *)NULL) {
	    nodomain = 1;
	    return(0);
	}
	for (cp = ++domainp; *cp; ++cp)
	    if (isupper(*cp))
		*cp = tolower(*cp);
    }
    return(!strcmp(domainp, rhost + len +1));
}


