/* * Policy: openssh. * * (c) 2002, 2003 Pawel Jakub Dawidek * * $Id: openssh.cb,v 1.50 2003/08/22 22:08:19 dawidek Exp $ */ #include "addons.cbh" #if CERB_VERSION < 2003050901 #error Newer CerbNG required for this policy. #endif #define PERMIT_ROOT_LOGIN 0u #define PERMIT_SKEY_AUTH 0u #define SSHD_PNAME "sshd" #define SSHD_UID GET_UID("sshd") #define SSHD_GID GET_GID("sshd") #define SSHD_INODE GET_INODE("/usr/sbin/sshd") #define SSHD_DEV GET_DEV("/usr/sbin/sshd") #define SSHD_PORT 22u #define SSHD_PID_FILE "/var/run/sshd.pid" #define SSHD_VERBOSE 1 beginrules REGISTER("openssh"); #if CERB_VERSION >= 2003062901 if (INITRUN()) { crsysctl("openssh"); crsysctl("openssh.pname", SSHD_PNAME, CTLFLAG_RD); crsysctl("openssh.uid", SSHD_UID); #undef SSHD_UID #define SSHD_UID CB_SYSCTL("openssh.uid") crsysctl("openssh.gid", SSHD_GID); #undef SSHD_GID #define SSHD_GID CB_SYSCTL("openssh.gid") crsysctl("openssh.inode", SSHD_INODE); #undef SSHD_INODE #define SSHD_INODE CB_SYSCTL("openssh.inode") crsysctl("openssh.dev", SSHD_DEV); #undef SSHD_DEV #define SSHD_DEV CB_SYSCTL("openssh.dev") crsysctl("openssh.port", SSHD_PORT); #undef SSHD_PORT #define SSHD_PORT CB_SYSCTL("openssh.port") crsysctl("openssh.pid_file", SSHD_PID_FILE); #undef SSHD_PID_FILE #define SSHD_PID_FILE CB_SYSCTL("openssh.pid_file") crsysctl("openssh.permit_root_login", PERMIT_ROOT_LOGIN); #undef PERMIT_ROOT_LOGIN #define PERMIT_ROOT_LOGIN CB_SYSCTL("openssh.permit_root_login") crsysctl("openssh.permit_skey_auth", PERMIT_SKEY_AUTH); #undef PERMIT_SKEY_AUTH #define PERMIT_SKEY_AUTH CB_SYSCTL("openssh.permit_skey_auth") crsysctl("openssh.verbose", SSHD_VERBOSE); #undef SSHD_VERBOSE #define SSHD_VERBOSE CB_SYSCTL("openssh.verbose") } #endif ADD_SYSCALL( SYS_execve, SYS_open, SYS___sysctl, SYS_setuid, SYS_seteuid, SYS_setgid, SYS_setegid, SYS_getuid, SYS_geteuid, SYS_getgroups, SYS_chown, SYS_chmod, SYS_bind, SYS_chroot, SYS_setgroups, SYS_setlogin, SYS_setrlimit, SYS_unlink, SYS_stat, SYS_lstat, SYS_chdir ); /* * first of all, if someone with real uid 0 executes sshd, we will remove * uid and gid 0 from sshd process */ if (syscall == SYS_execve && ruid == 0) { if (getinode(arg[0]) == SSHD_INODE && getdev(arg[0]) == SSHD_DEV) { reg[1] = call(); if (reg[1] != 0) { return reg[1]; } /* everything is correct, removing uid and gid 0 */ setpruid(SSHD_UID); setpeuid(SSHD_UID); setpsvuid(SSHD_UID); setpgroups(addelem(addelem(MKNULL(CB_UDEFPTR_T), SSHD_GID), SSHD_GID)); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Removed uid 0."); return 0; } } if (finode == SSHD_INODE && fdev == SSHD_DEV && ruid == SSHD_UID) { if (syscall == SYS_execve) { /* * sshd can only run sshd on SIGHUP * (it can run also login program if UseLogin yes, but...) */ if (getinode(arg[0]) == SSHD_INODE && getdev(arg[0]) == SSHD_DEV) { reg[0] = call(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Running child " "[ret=%d].", reg[0]); return reg[0]; } CB_LOGEXT(SSHD_VERBOSE, LOG_WARNING, "!WARN! Attempt to run " "%s!", reg[0]); return EPERM; } if (syscall == SYS_open) { if (arg[0] == SSHD_PID_FILE && arg[1] == (O_WRONLY | O_CREAT | O_TRUNC)) { /* setting effective uid to 0 */ reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Openning %s " "(flags=%x) [ret=%d].", arg[0], arg[1], reg[0]); return reg[0]; } if (arg[1] == O_RDWR) { if (arg[0] == "/var/log/lastlog" || arg[0] == "/var/run/utmp" || arg[0] @ "/dev/ttyp?" || (PERMIT_SKEY_AUTH && (arg[0] == "/etc/skeykeys" || arg[0] == "/etc/opiekeys"))) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Openning %s " "(flags=%x) [ret=%d].", arg[0], arg[1], reg[0]); return reg[0]; } if (!PERMIT_SKEY_AUTH && (arg[0] == "/etc/skeykeys" || arg[0] == "/etc/opiekeys")) { CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Inform that " "%s doesn't exists.", arg[0]); return ENOENT; } } if (arg[0] == "/var/log/lastlog") { if (arg[1] == (O_RDWR | O_CREAT) && arg[2] == 02000) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Openning %s " "(flags=%x) [ret=%d].", arg[0], arg[1], reg[0]); return reg[0]; } } if (arg[0] == "/var/run/utmp" && arg[1] == (O_WRONLY | O_CREAT) && arg[2] == 0644) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Openning %s " "(flags=%x) [ret=%d].", arg[0], arg[1], reg[0]); return reg[0]; } if (arg[0] == "/var/log/wtmp" && arg[1] == (O_WRONLY | O_APPEND)) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Openning %s " "(flags=%x) [ret=%d].", arg[0], arg[1], reg[0]); return reg[0]; } /* * we only set effective uid to 0 for reading, when there * is no chance to read the files as regular user */ if (arg[1] == O_RDONLY) { if (arg[0] == "/etc/spwd.db" || arg[0] == "/etc/login.conf.db" || arg[0] == "/etc/ssh/ssh_host_dsa_key" || arg[0] == "/etc/ssh/ssh_host_key" || arg[0] @ "/home/*/.ssh/authorized_keys" || arg[0] @ "/home/*/.ssh/authorized_keys2") { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Openning %s " "(flags=%x) " "[ret=%d].", arg[0], arg[1], reg[0]); return reg[0]; } } } if (syscall == SYS___sysctl) { /* this means that process want to change sysctl value */ if (!isnull(arg[4])) { reg[1] = sysctlname(tabrange(arg[0], arg[1])); if (reg[1] == "kern.proc.args" || reg[1] == "sysctl.name2oid") { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Modyfing " "sysctl %s [ret=%d].", reg[1], reg[0]); return reg[0]; } } } if (syscall == SYS_setuid || syscall == SYS_seteuid) { if (arg[0] >= 1000 || arg[0] == SSHD_UID || (PERMIT_ROOT_LOGIN && arg[0] == 0)) { reg[0] = euid; setpeuid(0); reg[1] = call(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Setting uid/euid to " "%u [ret=%d].", arg[0], reg[1]); if (reg[1] != 0) { setpeuid(reg[0]); } return reg[1]; } } if (syscall == SYS_setgid || syscall == SYS_setegid) { if (arg[0] >= 1000 || (PERMIT_ROOT_LOGIN && arg[0] == 0)) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Setting gid/egid to " "%u [ret=%d].", arg[0], reg[0]); return reg[0]; } } if (syscall == SYS_getuid || syscall == SYS_geteuid) { /* Process is trying to check its, let's cheat him. */ CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Getting uid."); setpretval0(0); /* We don't even call getuid() syscall */ return 0; } if (syscall == SYS_getgroups) { reg[1] = call(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Getting groups."); return reg[1]; } if (syscall == SYS_chown) { if (arg[0] @ "/dev/ttyp?") { if ((arg[1] >= 1000 || arg[1] == 0) && (arg[2] >= 1000 || arg[2] == -1 || arg[2] == 4 || arg[2] == 0)) { /* we're getting file owner uid and gid */ reg[1] = getouid(arg[0]); reg[2] = getogid(arg[0]); reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Changing " "owner of %s from %d:%d to %d:%d [ret=%d].", arg[0], reg[1], reg[2], arg[1], arg[2], reg[0]); return reg[0]; } } } if (syscall == SYS_chmod) { if (arg[0] @ "/dev/ttyp?") { if (arg[1] == 0620 || arg[1] == 0622 || arg[1] == 0666) { reg[1] = getmode(arg[0]); reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Changing " "mode of %s from %o to %o [ret=%d].", arg[0], reg[1], arg[1], reg[0]); return reg[0]; } } } if (syscall == SYS_bind && (getfamily(arg[1]) == AF_INET || getfamily(arg[1]) == AF_INET6)) { reg[1] = getport(arg[1]); /* To which port number sshd have permission to bind? */ if (reg[1] == SSHD_PORT) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Binding to port %u " "[ret=%d].", reg[1], reg[0]); return reg[0]; } } if (syscall == SYS_chroot) { if (arg[0] == "/var/empty") { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Chrooting to %s " "[ret=%d].", arg[0], reg[0]); return reg[0]; } } if (syscall == SYS_setgroups) { reg[0] = euid; setpeuid(0); reg[1] = call(); setpeuid(reg[0]); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Setting groups to %U " "[ret=%d].", tabrange(arg[1], arg[0]), reg[1]); return reg[1]; } if (syscall == SYS_setlogin) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Setting login to %s " "[ret=%d].", arg[0], reg[0]); return reg[0]; } if (syscall == SYS_setrlimit) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Setting rlimit [ret=%d].", reg[0]); return reg[0]; } if (syscall == SYS_unlink) { if (arg[0] == SSHD_PID_FILE) { reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Removing %s " "[ret=%d].", arg[0], reg[0]); return reg[0]; } } if (syscall == SYS_stat) { reg[0] = euid; setpeuid(0); /* We need uid 0 to look into user's home directory. */ reg[1] = realpath(arg[0]); setpeuid(reg[0]); if (reg[1] @ "/usr/home/*/.ssh" || reg[1] @ "/usr/home/*/.ssh/authorized_keys" || reg[1] @ "/usr/home/*/.ssh/authorized_keys2") { arg[0] = reg[1]; /* race prevention */ reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Calling stat() on " "%s [ret=%d].", arg[0], reg[0]); return reg[0]; } } if (syscall == SYS_lstat) { reg[1] = realpath(arg[0]); reg[0] = sucall(); CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Calling lstat() on %s " "[real=%s] [ret=%d].", arg[0], reg[1], reg[0]); return reg[0]; } if (syscall == SYS_chdir) { if (arg[0] @ "/home/*/.ssh") { reg[0] = sucall(); /* calling chdir() */ CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Changing dir to %s " "[ret=%d].", arg[0], reg[0]); return reg[0]; } } } else { if (syscall == SYS_bind && getfamily(arg[1]) == AF_INET) { reg[0] = getport(arg[1]); if (reg[0] == SSHD_PORT) { CB_LOGEXT(SSHD_VERBOSE, LOG_INFO, "Port %u is reserved " "for sshd(8)!", reg[0]); return EPERM; } } } endrules