Beispiel #1
0
asmlinkage long our_sys_fchmodat(int dirfd, const char *file, mode_t mode, int flags)
{
    long fd = 0;
    long uid, gid;
    long audit, pid;
    struct task_struct *task = NULL;
    struct passwd_entry *pe = NULL;


    if (is_relevant_file(file, &uid, &gid) == 1)
    {
        fd = original_sys_fchmodat_call(dirfd, file, mode, flags);
        if(fd >= 0) {
            pid = current->pid;
            uid = current_uid();
            pe = get_passwd_entry(uid);
            task = find_task_by_vpid(pid);
            audit = get_audit_id();

            LOG_FCHMODAT(SYSCALL_FCHMODAT, pe->username, pid, audit, task->comm, file, dirfd, mode,flags);
        }
    }
    else {
        fd = original_sys_fchmodat_call(dirfd, file, mode, flags);
    }
    return fd;
}
Beispiel #2
0
asmlinkage long our_sys_lchown(const char *file, uid_t owner, gid_t group)
{
    long fd = 0;
    long uid, gid;
    long audit, pid;
    struct task_struct *task = NULL;
    struct passwd_entry *pe = NULL;

    if (is_relevant_file(file, &uid, &gid) == 1)
    {
        fd = original_sys_lchown_call(file, owner, group);
        if(fd >= 0) {
            pid = current->pid;
            uid = current_uid();
            audit = get_audit_id();
            pe = get_passwd_entry(uid);
            task = find_task_by_vpid(pid);

            LOG_CHOWN(SYSCALL_LCHOWN, pe->username, pid, audit, task->comm, file, owner, group);
        }
    }
    else {
        fd = original_sys_lchown_call(file, owner, group);
    }
    return fd;
}
Beispiel #3
0
asmlinkage long our_sys_link(const char* file, const char* newfile)
{
    long result;
    long uid, gid;
    long audit, pid;
    struct log_path *p;
    struct passwd_entry *pe = NULL;


    if (is_relevant_file(file, &uid, &gid) == 1)
    {
        result = original_sys_link_call(file, newfile);
        if(result >= 0) {
            pid = current->pid;
            uid = current_uid();
            pe = get_passwd_entry(uid);
            audit = get_audit_id();
            p = find_path();
            LOG_LINK(SYSCALL_LINK, pe->username, pid, audit, file, newfile, p->name);
            kfree(p);
        }
    }
    else {
        result = original_sys_link_call(file, newfile);
    }
    return result;
}
asmlinkage long our_sys_recvmsg(int sockfd, const struct msghdr *msg, int flags) 
{
	struct passwd_entry *pe;
	char *hexdata, *data;
	unsigned int tmp, len;	
	int i;
	long result;
	long uid, pid, audit;

	result = original_sys_recvmsg_call(sockfd, msg, flags);
	if(result < 0) return result;

	uid = current_uid();
	audit = get_audit_id();
	pid = current->pid;
	pe = get_passwd_entry(uid);

	// Convert Data to Hex
	len = (unsigned int) msg->msg_iovlen;
	hexdata = kmalloc(sizeof(char) * (len * 2 + 1), GFP_KERNEL);
	data = (char *) msg->msg_iov;
	for(i = 0; i < len; i++) {
		tmp = (int)data[i];
		tmp = tmp & 255;
		sprintf(hexdata + (i * 2), "%02X", tmp);
	}
	hexdata[len * 2] = '\0';

	LOG_S_MSG(SYSCALL_S_RECVMSG, pe->username, pid, audit, sockfd, flags, len, hexdata);
	kfree(hexdata);

	return result;
}
Beispiel #5
0
asmlinkage long our_sys_pipe2(int pipefd[2], int flags)
{
    long result;
    long audit, pid, paudit;
    struct passwd_entry *pe = NULL;
    struct task_struct *ts = NULL;

    result = original_sys_pipe2_call(pipefd, flags);
    if(result < 0) return result;

    pid = current->pid;
    audit = get_audit_id();
    pe = get_passwd_entry(current_uid());

    ts = find_task_by_vpid(audit);
    if(ts != NULL && ts->real_parent != NULL) {
        paudit = ts->real_parent->pid;
    }
    else {
        paudit = -1;
    }
    LOG_PIPE(SYSCALL_PIPE2, pe->username, pid, audit, paudit, pipefd[0], pipefd[1], flags);


    return result;
}
Beispiel #6
0
asmlinkage long our_sys_dup2(unsigned int oldfd, unsigned int newfd)
{
    long uid, audit, paudit;
    long pid, ppid;
    long result;
    struct passwd_entry *pe = NULL;
    struct task_struct *atask;
    struct task_struct *ptask;

    result = original_sys_dup2_call(oldfd, newfd);
    if(result < 0) return result;

    uid = current_uid();
    audit = get_audit_id();
    pid = current->pid;
    pe = get_passwd_entry(uid);
    ptask = find_task_by_vpid(pid);
    ppid = (long)(ptask->real_parent->pid);
    atask = find_task_by_vpid(audit);
    if(atask != NULL && atask->real_parent != NULL) {
        paudit = atask->real_parent->pid;
    }
    else {
        paudit = -1;
    }
    LOG_DUP2(SYSCALL_DUP2, pe->username, pid, ppid, audit, paudit, oldfd, newfd);

    return result;
}
asmlinkage long our_sys_connect(int sockfd, struct sockaddr __user *addr, int addrlen)
{
	long uid, pid, audit;
	long result;
	struct passwd_entry *pe;
	struct sockaddr_in  *ipv4;
	unsigned int ipv4_addr;
	//struct sockaddr_in6 *ipv6;
	uid = current_uid();
	audit = get_audit_id();
	pid = current->pid;
	pe = get_passwd_entry(uid);

	result = original_sys_connect_call(sockfd, addr, addrlen);
	if(result < 0) return result;

	if(addr->sa_family == AF_INET) {
		ipv4 = (struct sockaddr_in *) addr;
		ipv4_addr = (unsigned int)(ipv4->sin_addr.s_addr);
		LOG_S_CONNECT(SYSCALL_S_CONNECT, pe->username, pid, audit, sockfd, ipv4_addr, ipv4->sin_port);
	}
	else if(addr->sa_family == AF_INET6){
		// TODO: Suport IPv6
	}
	return result; 
}
Beispiel #8
0
asmlinkage long our_sys_rename(const char* oldfile, const char* newfile)
{
    struct log_path *p;
    long euid, pid, ppid;
    long audit, paudit, result;
    struct passwd_entry *pe;
    struct task_struct *atask;
    struct task_struct *ptask;

    result = original_sys_rename_call(oldfile, newfile);
    if(result < 0) return result;

    euid = current_uid();
    pe = get_passwd_entry(euid);
    pid = current->pid;
    audit = get_audit_id();
    ptask = find_task_by_vpid(pid);
    ppid = (long)(ptask->real_parent->pid);

    atask = find_task_by_vpid(audit);
    if(atask != NULL && atask->real_parent != NULL) {
        paudit = atask->real_parent->pid;
    }
    else {
        paudit = -1;
    }
    if(euid > 0 && pe != NULL) {
        p = find_path();
        LOG_RENAME(SYSCALL_MOVE, pe->username, pid, ppid, audit, paudit, ptask->comm, oldfile, newfile, p->name);
        kfree(p);
    }
    return result;
}
Beispiel #9
0
asmlinkage long our_sys_close(unsigned int fd)
{
    long result;
    struct file *f;
    struct passwd_entry *pe;
    struct task_struct *atask;
    int is_sock;
    struct process_ids *pids;
    char *test = "Hello World, this is meeeee";
    u16 crc;

    result = original_sys_close_call(fd);
    if(result < 0 ) return result;

    pids = get_process_ids();
    pe = get_passwd_entry(pids->uid);
    atask = find_task_by_vpid(pids->audit);

    is_sock = 0;
    rcu_read_lock();
    f = fcheck_files(current->files, fd);
    if(f != NULL && ((f->f_path.dentry->d_inode->i_mode) & S_IFMT) == S_IFSOCK) is_sock = 1;
    rcu_read_unlock();

    if(atask != NULL && atask->cred != NULL && atask->cred->euid != 0) {
        if(is_sock) LOG_S_CLOSE(SYSCALL_CLOSE, pe->username, pids->pid, pids->ppid, pids->audit, pids->paudit, fd);
        else LOG_CLOSE(SYSCALL_CLOSE, pe->username, pids->pid, pids->ppid, pids->audit, pids->paudit, fd);
    }
    kfree(pids);
    return result;
}
Beispiel #10
0
asmlinkage long our_sys_write(unsigned int fd, const char __user *buf, size_t count)
{
    struct file *f;
    struct passwd_entry *pe;
    char *hexdata;
    char *p_hexdata;
    unsigned int value;
    int i;
    long offset;
    char *data;
    struct task_struct *atask;
    int is_sock;
    struct process_ids *pids;

    pids = get_process_ids();

    atask = find_task_by_vpid(pids->audit);

    if(atask != NULL && atask->cred != NULL && atask->cred->euid != 0) {
        pe = get_passwd_entry(pids->uid);

        data = kmalloc((count + 1) * sizeof(char), GFP_KERNEL);
        memcpy(data, buf, count + 1);
        data[count] = '\0';

        is_sock = 0;
        /* Get file offset */
        rcu_read_lock();
        f = fcheck_files(current->files, fd);
        if(f) {
            offset = f->f_pos;
            if(((f->f_path.dentry->d_inode->i_mode) & S_IFMT) == S_IFSOCK) is_sock = 1;
        }
        else {
            offset = 0;
        }
        rcu_read_unlock();

        hexdata = kmalloc((count + 1) * 2 * sizeof(char), GFP_KERNEL);
        p_hexdata = hexdata;
        for(i = 0; i < count; i++) {
            value = data[i];
            value = value & 255;
            sprintf(hexdata + (i * 2), "%02X", value);
        }
        hexdata[count * 2] = '\0';

        if(is_sock) LOG_S_RDWR(SYSCALL_WRITE, pe->username, pids->pid, pids->ppid, pids->audit, pids->paudit, fd, offset, hexdata);
        else LOG_RDWR(SYSCALL_WRITE, pe->username, pids->pid, pids->ppid, pids->audit, pids->paudit, fd, offset, hexdata);

        kfree(hexdata);
        kfree(data);
    }
    kfree(pids);
    return original_sys_write_call(fd, buf, count);
}
Beispiel #11
0
asmlinkage long our_sys_sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
{
    long result;
    long audit, pid;
    struct passwd_entry *pe = NULL;
    result = original_sys_sendfile_call(out_fd, in_fd, offset, count);
    if(result >= 0) {
        pid = current->pid;
        audit = get_audit_id();
        pe = get_passwd_entry(current_uid());

        LOG_SENDFILE(SYSCALL_SENDFILE, pe->username, pid, audit, out_fd, in_fd, *offset, count);
    }
    return result;
}
asmlinkage long our_sys_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, int addrlen)
{
	struct sockaddr_in  *ipv4;
	//struct sockaddr_in6 *ipv6;
	char *hexdata, *data;
	long uid, pid, audit;
	long result;
	struct passwd_entry *pe;
	unsigned int tmp;	
	int i;
	unsigned int ipv4_addr;

	result = original_sys_sendto_call(sockfd, buf, len, flags, dest_addr, addrlen);
	if(result < 0) return result;

	uid = current_uid();
	audit = get_audit_id();
	pid = current->pid;
	pe = get_passwd_entry(uid);

	// Convert Data to Hex
	hexdata = kmalloc(sizeof(char) * (len * 2 + 1), GFP_KERNEL);
	data = (char *) buf;
	for(i = 0; i < len; i++) {
		tmp = (int)data[i];
		tmp = tmp & 255;
		sprintf(hexdata + (i * 2), "%02X", tmp);
	}
	hexdata[len * 2] = '\0';
	

	if(dest_addr != NULL) {
		if(dest_addr->sa_family == AF_INET) {
			ipv4 = (struct sockaddr_in *) dest_addr;
			ipv4_addr = (unsigned int)(ipv4->sin_addr.s_addr);
			LOG_S_SENDRECV(SYSCALL_S_SENDTO, pe->username, pid, audit, sockfd, flags, len, ipv4_addr, hexdata);
		}
		else if(dest_addr->sa_family == AF_INET6) {
			// TODO: Suport IPv6
		}
	}
	else {
		LOG_S_SENDRECV(SYSCALL_S_SENDTO, pe->username, pid, audit, sockfd, flags, len, 0, hexdata);
	}
	kfree(hexdata);
	return result;
}
Beispiel #13
0
asmlinkage long our_sys_dup(unsigned int filde)
{
    long result;
    long uid, audit;
    long pid;
    struct passwd_entry *pe = NULL;

    result = original_sys_dup_call(filde);
    if(result < 0) return result;

    uid = current_uid();
    audit = get_audit_id();
    pid = current->pid;
    pe = get_passwd_entry(uid);
    LOG_DUP2(SYSCALL_DUP, pe->username, pid, 0, audit, 0, filde, result);
    return result;
}
Beispiel #14
0
asmlinkage long our_sys_open(const char* file, int flags, int mode)
{
    long fd = 0;
    long uid, gid;
    struct log_path *p;
    struct passwd_entry *pe = NULL;
    struct process_ids *pids;
    struct task_struct *ptask;
    int is_log;
    int type;

    type = SYSCALL_OPEN;
    is_log = is_log_file(file);
    //if (is_relevant_file(file, &uid, &gid) == 1)
    if(is_log == 0)
    {
        if((flags & O_CREAT) > 0) {
            flags -= O_CREAT;
            fd = original_sys_open_call(file, flags, mode);
            flags += O_CREAT;
            if(fd < 0) {
                type = SYSCALL_CREAT;
                fd = original_sys_open_call(file, flags, mode);
                if(fd < 0) return fd; //Error opening file
            }
        }
        else {
            fd = original_sys_open_call(file, flags, mode);
            if(fd < 0) return fd; //Error opening file
        }

        pids = get_process_ids();
        pe = get_passwd_entry(pids->uid);
        p = find_path();
        ptask = find_task_by_vpid(pids->pid);
        LOG_OPEN(type, pe->username, pids->pid, pids->ppid, pids->audit, pids->paudit, ptask->comm, file, p->name, flags, mode, fd);
        kfree(p);
        kfree(pids);
    }
    else
    {
        //TODO: check process if for rsyslog
        fd = original_sys_open_call(file, flags, mode);
    }
    return fd;
}
Beispiel #15
0
asmlinkage long our_sys_symlink(const char *path1, const char *path2)
{
    long euid, result;
    long audit, pid;
    struct passwd_entry *pe;
    struct log_path *p;
    result = original_sys_symlink_call(path1, path2);
    if(result >= 0) {
        euid = current_uid();
        audit = get_audit_id();
        pid = current->pid;
        pe = get_passwd_entry(euid);
        p = find_path();
        LOG_LINK(SYSCALL_SYMLINK, pe->username, pid, audit, path1, path2, p->name);
        kfree(p);
    }
    return result;
}
asmlinkage long our_sys_socket(int socket_family, int socket_type, int protocol)
{
	long uid, pid, audit;
	long result = 0;
	struct passwd_entry *pe = NULL;
	struct task_struct *task = NULL;
	result = original_sys_socket_call(socket_family, socket_type, protocol);
	if(result >= 0) {
		uid = current_uid();
		audit = get_audit_id();
		pid = current->pid;
		task = find_task_by_vpid(pid);
		pe = get_passwd_entry(uid);
		task = find_task_by_vpid(pid);
		LOG_S_SOCKET(SYSCALL_S_SOCKET, pe->username, pid, audit, task->comm, result, socket_type, protocol, socket_family);
	}

	return result;
}
Beispiel #17
0
asmlinkage long our_sys_fchown(int filefd, uid_t owner, gid_t group)
{
    long fd = 0;
    long uid;
    long audit, pid;
    struct task_struct *task = NULL;
    struct passwd_entry *pe = NULL;

    fd = original_sys_fchown_call(filefd, owner, group);
    if(fd >= 0) {
        pid = current->pid;
        uid = current_uid();
        audit = get_audit_id();
        pe = get_passwd_entry(uid);
        task = find_task_by_vpid(pid);
        LOG_FCHOWN(SYSCALL_FCHOWN, pe->username, pid, audit, task->comm, filefd, owner, group);
    }
    return fd;
}
Beispiel #18
0
asmlinkage long our_sys_fchmod(int filefd, mode_t mode)
{
    long fd = 0;
    long uid;
    long audit, pid;
    struct task_struct *task = NULL;
    struct passwd_entry *pe = NULL;

    fd = original_sys_fchmod_call(filefd, mode);
    if(fd >= 0) {
        pid = current->pid;
        uid = current_uid();
        pe = get_passwd_entry(uid);
        task = find_task_by_vpid(pid);
        audit = get_audit_id();

        LOG_FCHMOD(SYSCALL_FCHMOD, pe->username, pid, audit, task->comm, filefd, mode);
    }
    return fd;
}
Beispiel #19
0
asmlinkage long our_sys_mkdir(const char *pathname, mode_t mode)
{
    long euid, result;
    long audit, pid;
    struct passwd_entry *pe;
    struct log_path *p;
    result = original_sys_mkdir_call(pathname, mode);

    if(result >= 0) {
        euid = current_uid();
        audit = get_audit_id();
        pid = current->pid;
        pe = get_passwd_entry(euid);
        p = find_path();
        LOG_MKDIR(SYSCALL_MKDIR, pe->username, pid, audit, pathname, p->name, mode);
        kfree(p);
    }

    return result;
}
Beispiel #20
0
asmlinkage long our_sys_unlinkat(int dirfd, const char* file, int flags)
{
    long result = 0;
    long uid, gid;
    long pid, ppid, p_uid;
    long audit, paudit;
    struct log_path *p;
    struct passwd_entry *pe = NULL;
    struct task_struct *atask;
    struct task_struct *ptask;

    if (is_relevant_file(file, &uid, &gid) == 1)
    {
        result = original_sys_unlinkat_call(dirfd, file, flags);

        if(result >= 0) {
            pid = current->pid;
            p_uid = current_uid();
            pe = get_passwd_entry(p_uid);
            ptask = find_task_by_vpid(pid);
            ppid = (long)(ptask->real_parent->pid);
            audit = get_audit_id();
            p = find_path();
            atask = find_task_by_vpid(audit);
            if(atask != NULL && atask->real_parent != NULL) {
                paudit = atask->real_parent->pid;
            }
            else {
                paudit = -1;
            }
            LOG_UNLINKAT(SYSCALL_UNLINK, pe->username, pid, ppid, audit, paudit, ptask->comm, file, p->name, dirfd, flags);
        }
    }
    else {
        result = original_sys_unlinkat_call(dirfd, file, flags);
    }

    return result;
}
Beispiel #21
0
asmlinkage long our_sys_linkat(int dirfd, const char* file, int newfd, const char* newfile, int flags)
{
    long result;
    long uid, gid;
    long audit, pid;
    struct passwd_entry *pe = NULL;


    if (is_relevant_file(file, &uid, &gid) == 1)
    {
        result = original_sys_linkat_call(dirfd, file, newfd, newfile, flags);
        if(result >= 0) {
            pid = current->pid;
            uid = current_uid();
            audit = get_audit_id();
            pe = get_passwd_entry(uid);
            LOG_LINKAT(SYSCALL_LINKAT, pe->username, pid, audit, file, newfile, dirfd, newfd, flags);
        }
    }
    else {
        result = original_sys_linkat_call(dirfd, file, newfd, newfile, flags);
    }
    return result;
}
Beispiel #22
0
int main(int argc, char **argv)
{
	int c;
	int cnt;
	char *childArgv[10];
	char *buff;
	int childArgc = 0;
	int retcode;

	char *pwdbuf = NULL;
	struct passwd *pwd = NULL, _pwd;

	struct login_context cxt = {
		.tty_mode = TTY_MODE,		/* tty chmod() */
		.pid = getpid(),		/* PID */
		.conv = { misc_conv, NULL }	/* PAM conversation function */
	};

	timeout = getlogindefs_num("LOGIN_TIMEOUT", LOGIN_TIMEOUT);

	signal(SIGALRM, timedout);
	siginterrupt(SIGALRM, 1);	/* we have to interrupt syscalls like ioclt() */
	alarm((unsigned int)timeout);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);

	setlocale(LC_ALL, "");
	bindtextdomain(PACKAGE, LOCALEDIR);
	textdomain(PACKAGE);

	setpriority(PRIO_PROCESS, 0, 0);
	initproctitle(argc, argv);

	/*
	 * -p is used by getty to tell login not to destroy the environment
	 * -f is used to skip a second login authentication
	 * -h is used by other servers to pass the name of the remote
	 *    host to login so that it may be placed in utmp and wtmp
	 */
	while ((c = getopt(argc, argv, "fHh:pV")) != -1)
		switch (c) {
		case 'f':
			cxt.noauth = 1;
			break;

		case 'H':
			cxt.nohost = 1;
			break;

		case 'h':
			if (getuid()) {
				fprintf(stderr,
					_("login: -h for super-user only.\n"));
				exit(EXIT_FAILURE);
			}
			init_remote_info(&cxt, optarg);
			break;

		case 'p':
			cxt.keep_env = 1;
			break;

		case 'V':
			printf(UTIL_LINUX_VERSION);
			return EXIT_SUCCESS;
		case '?':
		default:
			fprintf(stderr, _("usage: login [ -p ] [ -h host ] [ -H ] [ -f username | username ]\n"));
			exit(EXIT_FAILURE);
		}
	argc -= optind;
	argv += optind;

	if (*argv) {
		char *p = *argv;
		cxt.username = xstrdup(p);

		/* wipe name - some people mistype their password here */
		/* (of course we are too late, but perhaps this helps a little ..) */
		while (*p)
			*p++ = ' ';
	}

	for (cnt = get_fd_tabsize() - 1; cnt > 2; cnt--)
		close(cnt);

	setpgrp();	 /* set pgid to pid this means that setsid() will fail */

	openlog("login", LOG_ODELAY, LOG_AUTHPRIV);

	init_tty(&cxt);
	init_loginpam(&cxt);

	/* login -f, then the user has already been authenticated */
	cxt.noauth = cxt.noauth && getuid() == 0 ? 1 : 0;

	if (!cxt.noauth)
		loginpam_auth(&cxt);

	/*
	 * Authentication may be skipped (for example, during krlogin, rlogin,
	 * etc...), but it doesn't mean that we can skip other account checks.
	 * The account could be disabled or password expired (althought
	 * kerberos ticket is valid).         -- [email protected] (22-Feb-2006)
	 */
	loginpam_acct(&cxt);

	if (!(cxt.pwd = get_passwd_entry(cxt.username, &pwdbuf, &_pwd))) {
		warnx(_("\nSession setup problem, abort."));
		syslog(LOG_ERR, _("Invalid user name \"%s\" in %s:%d. Abort."),
		       cxt.username, __FUNCTION__, __LINE__);
		pam_end(cxt.pamh, PAM_SYSTEM_ERR);
		sleepexit(EXIT_FAILURE);
	}

	pwd = cxt.pwd;
	cxt.username = pwd->pw_name;

	/*
	 * Initialize the supplementary group list. This should be done before
	 * pam_setcred because the PAM modules might add groups during
	 * pam_setcred.
	 *
         * For root we don't call initgroups, instead we call setgroups with
	 * group 0. This avoids the need to step through the whole group file,
	 * which can cause problems if NIS, NIS+, LDAP or something similar
	 * is used and the machine has network problems.
	 */
	retcode = pwd->pw_uid ? initgroups(cxt.username, pwd->pw_gid) :	/* user */
			        setgroups(0, NULL);			/* root */
	if (retcode < 0) {
		syslog(LOG_ERR, _("groups initialization failed: %m"));
		warnx(_("\nSession setup problem, abort."));
		pam_end(cxt.pamh, PAM_SYSTEM_ERR);
		sleepexit(EXIT_FAILURE);
	}

	/*
	 * Open PAM session (after successful authentication and account check)
	 */
	loginpam_session(&cxt);

	/* committed to login -- turn off timeout */
	alarm((unsigned int)0);

	endpwent();

	cxt.quiet = get_hushlogin_status(pwd);

	log_utmp(&cxt);
	log_audit(&cxt, 1);
	log_lastlog(&cxt);

	chown_tty(&cxt);

	if (setgid(pwd->pw_gid) < 0 && pwd->pw_gid) {
		syslog(LOG_ALERT, _("setgid() failed"));
		exit(EXIT_FAILURE);
	}

	if (pwd->pw_shell == NULL || *pwd->pw_shell == '\0')
		pwd->pw_shell = _PATH_BSHELL;

	init_environ(&cxt);		/* init $HOME, $TERM ... */

	setproctitle("login", cxt.username);

	log_syslog(&cxt);

	if (!cxt.quiet) {
		motd();

#ifdef LOGIN_STAT_MAIL
		/*
		 * This turns out to be a bad idea: when the mail spool
		 * is NFS mounted, and the NFS connection hangs, the
		 * login hangs, even root cannot login.
		 * Checking for mail should be done from the shell.
		 */
		{
			struct stat st;
			char *mail;

			mail = getenv("MAIL");
			if (mail && stat(mail, &st) == 0 && st.st_size != 0) {
				if (st.st_mtime > st.st_atime)
					printf(_("You have new mail.\n"));
				else
					printf(_("You have mail.\n"));
			}
		}
#endif
	}

	/*
	 * Detach the controlling terminal, fork() and create, new session
	 * and reinilizalize syslog stuff.
	 */
	fork_session(&cxt);

	/* discard permissions last so can't get killed and drop core */
	if (setuid(pwd->pw_uid) < 0 && pwd->pw_uid) {
		syslog(LOG_ALERT, _("setuid() failed"));
		exit(EXIT_FAILURE);
	}

	/* wait until here to change directory! */
	if (chdir(pwd->pw_dir) < 0) {
		warn(_("%s: change directory failed"), pwd->pw_dir);

		if (!getlogindefs_bool("DEFAULT_HOME", 1))
			exit(0);
		if (chdir("/"))
			exit(EXIT_FAILURE);
		pwd->pw_dir = "/";
		printf(_("Logging in with home = \"/\".\n"));
	}

	/* if the shell field has a space: treat it like a shell script */
	if (strchr(pwd->pw_shell, ' ')) {
		buff = xmalloc(strlen(pwd->pw_shell) + 6);

		strcpy(buff, "exec ");
		strcat(buff, pwd->pw_shell);
		childArgv[childArgc++] = "/bin/sh";
		childArgv[childArgc++] = "-sh";
		childArgv[childArgc++] = "-c";
		childArgv[childArgc++] = buff;
	} else {
		char tbuf[PATH_MAX + 2], *p;

		tbuf[0] = '-';
		xstrncpy(tbuf + 1, ((p = strrchr(pwd->pw_shell, '/')) ?
				    p + 1 : pwd->pw_shell), sizeof(tbuf) - 1);

		childArgv[childArgc++] = pwd->pw_shell;
		childArgv[childArgc++] = xstrdup(tbuf);
	}

	childArgv[childArgc++] = NULL;

	execvp(childArgv[0], childArgv + 1);

	if (!strcmp(childArgv[0], "/bin/sh"))
		warn(_("couldn't exec shell script"));
	else
		warn(_("no shell"));

	exit(EXIT_SUCCESS);
}