diff --git a/inside/handheld.css b/css/handheld.css similarity index 100% rename from inside/handheld.css rename to css/handheld.css diff --git a/inside/print.css b/css/print.css similarity index 100% rename from inside/print.css rename to css/print.css diff --git a/inside/print_prog.css b/css/print_prog.css similarity index 100% rename from inside/print_prog.css rename to css/print_prog.css diff --git a/css/rebuild.css b/css/rebuild.css new file mode 100644 index 0000000..08a16fe --- /dev/null +++ b/css/rebuild.css @@ -0,0 +1,137 @@ +/* -------------------------------------------------------------- + + Rebuild the default browser styles + + Based on work by Blueprint CSS + http://code.google.com/p/blueprintcss/ + +-------------------------------------------------------------- */ + + +body { + background: #fff; +} +body, input, textarea { + color: #111; + font: 12px Arial,sans-serif; + line-height: 1.5; +} + + +/* Headings +-------------------------------------------------------------- */ + +h1,h2,h3,h4,h5,h6 { + font-weight: normal; + clear: both; +} +hr { + background-color: #999; + border:0; + height: 1px; + margin-bottom: 1.5em; +} + + +/* Text elements +-------------------------------------------------------------- */ + +p { + margin-bottom: 1.5em; +} +ul { + margin: 0 0 1.5em 2.5em; +} +ol { + margin: 0 0 1.5em 2.5em; +} +ul { + list-style:disc; +} +ol { + list-style-type: decimal; +} +ol ol { + list-style:upper-alpha; +} +ol ol ol { + list-style:lower-roman; +} +ol ol ol ol { + list-style:lower-alpha; +} +ul ul, ol ol, ul ol, ol ul { + margin-bottom:0; +} +dl { + margin:0 1.5em; +} +dt { + font-weight: bold; +} +dd { + margin-bottom: 1.5em; +} +strong { + font-weight: bold; +} +cite, em, i { + font-style: italic; +} +blockquote { + margin: 0 3em; +} +blockquote em, blockquote i, blockquote cite { + font-style: normal; +} +pre { + font: 11px Monaco, monospace; + line-height: 1.5; + margin-bottom: 1.5em; +} +code { + font: 11px Monaco, monospace; +} +abbr, acronym { + border-bottom: 1px dotted #666; + cursor: help; +} +ins { + text-decoration: none; +} +sup, +sub { + height: 0; + line-height: 1; + vertical-align: baseline; + position: relative; + +} +sup { + bottom: 1ex; +} +sub { + top: .5ex; +} + + +/* + +Adapt the following for use in your Child Themes when using +different font-sizes and line-heights + +body, input, textarea { + font: --px Arial,sans-serif; + line-height:--; +} +p, ul, ol, dd, pre { + margin-bottom:--em; +} +pre, code { + font:--px Monaco, monospace; + line-height:--; +} + +All other styles can be overridden--or ignored!--in Child Theme stylesheets + +*/ \ No newline at end of file diff --git a/css/reset.css b/css/reset.css new file mode 100644 index 0000000..cbcd60f --- /dev/null +++ b/css/reset.css @@ -0,0 +1,63 @@ +/* -------------------------------------------------------------- + + Reset default browser CSS. + + Based on work by Eric Meyer: + http://meyerweb.com/eric/tools/css/reset/index.html + +-------------------------------------------------------------- */ + +/* v1.0 | 20080212 */ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td { + margin: 0; + padding: 0; + border: 0; + outline: 0; + font-size: 100%; + vertical-align: baseline; + background: transparent; +} +body { + line-height: 1; +} +ol, ul { + list-style: none; +} +blockquote, q { + quotes: none; +} +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; +} + +/* remember to define focus styles! */ +:focus { + outline: 0; +} + +/* remember to highlight inserts somehow! */ +ins { + text-decoration: none; +} +del { + text-decoration: line-through; +} + +/* tables still need 'cellspacing="0"' in the markup */ +table { + border-collapse: collapse; + border-spacing: 0; +} + +a img { border: none; } diff --git a/inside/screen.css b/css/screen.css similarity index 98% rename from inside/screen.css rename to css/screen.css index 68bbbcc..f1d452a 100644 --- a/inside/screen.css +++ b/css/screen.css @@ -107,7 +107,7 @@ a.skip-nav { } a.contact { - background: url("graphics/user_go.png") no-repeat right; + background: url("../inside/graphics/user_go.png") no-repeat right; padding-right: 20px; } /* =lists @@ -406,7 +406,7 @@ h4 { } li.menulist { - background: url(graphics/minus.png) no-repeat 3px 0.3em; + background: url(../inside/graphics/minus.png) no-repeat 3px 0.3em; line-height: 1.2em; list-style: none outside; margin: 0px 0 10px; @@ -415,7 +415,7 @@ li.menulist { } .jsenabled li.menulist { - background: url(graphics/plus.png) no-repeat 3px 0.3em; + background: url(../inside/graphics/plus.png) no-repeat 3px 0.3em; } .jsenabled .menu, .jsenabled .submenu { diff --git a/css/style.css b/css/style.css index 61b9619..bfc2aab 100644 --- a/css/style.css +++ b/css/style.css @@ -1,6 +1,6 @@ -@import 'css/reset.css'; -@import 'css/rebuild.css'; -@import 'css/wp-css'; +@import 'reset.css'; +@import 'rebuild.css'; +@import 'wp.css'; /** @@ -80,10 +80,10 @@ body.dns { } /*body.dns */ #header { - background:#191919 url('img/header-210x.png') repeat-x bottom; + background:#191919 url('../inside/graphics/header-210x.png') repeat-x bottom; } #header { - height:155px; + height:110px; margin-bottom:10px; overflow:hidden; position:relative; @@ -92,7 +92,7 @@ body.dns { z-index:999 } .site-title a { - background: url('img/bannerindex-400.png') no-repeat -20px 0; + background: url('../inside/graphics/bannerindex-400.png') no-repeat -20px 0; display:block; height:63px; margin-top:20px; @@ -569,3 +569,8 @@ h2.jobb { margin-top:0.5em; padding:10px 10px 5px; } +/* random styles */ +.home-link { + display: inline-block; + margin-bottom: 5px; +} diff --git a/css/wp.css b/css/wp.css new file mode 100644 index 0000000..7df75e3 --- /dev/null +++ b/css/wp.css @@ -0,0 +1,75 @@ +/* -------------------------------------------------------------- + + Basic WordPress Blog Styles + +-------------------------------------------------------------- */ + + +/* Images +-------------------------------------------------------------- */ + +.entry-content img { + margin: 0 0 1.5em 0; +} +.alignleft, +img.alignleft { + display: inline; + float: left; + margin-right: 1.5em; +} +.alignright, +img.alignright { + display: inline; + float: right; + margin-left: 1.5em; +} +.aligncenter, +img.aligncenter { + clear: both; + display: block; + margin-left: auto !important; + margin-right: auto !important; +} +.wp-caption { + text-align: center; + margin-bottom: 1.5em; +} +.wp-caption img { + border: 0 none; + margin: 0; + padding: 0; +} +.wp-caption p.wp-caption-text { + margin: 0; +} +.wp-smiley { + max-height: 1em; + margin:0 !important; +} +.gallery dl { + margin: 0; +} +.gallery-caption { + margin:-1.5em 0 0 0; +} + + +/* Pullquotes +-------------------------------------------------------------- */ + +blockquote.left { + float: left; + margin-left: 0; + margin-right: 20px; + text-align: right; + width: 33%; +} +blockquote.right { + float: right; + margin-left: 20px; + margin-right: 0; + text-align: left; + width: 33%; +} + + diff --git a/includes/Ldap.class.php b/includes/Ldap.class.php new file mode 100644 index 0000000..1b17d55 --- /dev/null +++ b/includes/Ldap.class.php @@ -0,0 +1,830 @@ +conn = ldap_connect($host, $port); + if( $this->conn == null ) { + throw new Exception("Could not connect to ldap server `$host:$port'"); + } + ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3); + } + + + public function __destruct() { + ldap_close($this->conn); + } + + public function getConn() { + return $this->conn; + } + + private function bind() { + if( !ldap_bind($this->conn, BIND_USER, BIND_PASS) ) { + throw new Exception("ERROR: Could not bind to ldap server."); + } + } + + private function unbind() { + /* Seems the ldap_unbind() function closes the connection, + * so we just drop the unbind process. Some security risk + * as the script continues bound to the already bound user, + * but what can one do?... */ + } + public function testBind($username, $password) { + $password = strtr($password, array("\'"=>"'")); + $baseDn = USUFFIX . "," . SUFFIX; + if ( ($isBound = @ldap_bind($this->conn, $username, $password)) === false ) { + // @see wpLDAP comment at http://ashay.org/?page_id=133#comment-558 + $isBound = @ldap_bind($this->conn, "uid=$username, $baseDn", $password); + } + return $isBound; + } + + public function search($baseDn, $filter, $attrs, $bind = false) { + if( $bind === true ) { + $this->bind(); + } + $res = ldap_search($this->conn, $baseDn, $filter, $attrs); + if(!$res) { + return false; + } + + $entries = ldap_get_entries($this->conn, $res); + + if( $bind === true ) { + $this->unbind(); + } + + return $entries; + } + + public function read($dn, $filter, $attrs, $bind = false) { + if( $bind === true ) { + $this->bind(); + } + $res = ldap_read($this->conn, $dn, $filter, $attrs); + if(!$res) { + return false; + } + + $entries = ldap_get_entries($this->conn, $res); + + if( $bind === true ) { + $this->unbind(); + } + + return $entries; + } + + private function userDn($username) { + return "uid=". $username . "," . USUFFIX . "," . SUFFIX; + } + + private function groupDn($groupname) { + return "cn=". $groupname . "," . GSUFFIX . "," . SUFFIX; + } + + private function homeAutomountDn($username) { + return "cn=". $username . ",ou=auto.home," . ASUFFIX . "," . SUFFIX; + } + + private function kerberosPrincipalDn($username) { + return "krbPrincipalName=". $username . "@". KERBEROS_DOMAIN .",cn=". KERBEROS_DOMAIN . "," + . KSUFFIX . "," . SUFFIX; + } + + private function ldapAdd($dn, $record) { + $this->bind(); + $res = ldap_add($this->conn, $dn, $record); +/* if ( !$res ) { + _log(ldap_error($this->conn)); + }*/ + $this->unbind(); + + if( $res ) { + debug("Added $dn"); + } else { + debug("Could not add $dn"); + } + + return $res; + } + + public function ldapDelete($dn) { + $this->bind(); + $res = ldap_delete($this->conn, $dn); + $this->unbind(); + + if( $res ) { + debug("Deleted $dn"); + } else { + debug("Could not delete $dn"); + } + return $res; + } + + public function getUser($username) { + + $filter = "(&(uid=$username)(objectClass=posixAccount))"; + $attrs = array(); + + $info = $this->search(USUFFIX .",". SUFFIX, $filter, $attrs); + + if( $info['count'] != 1 ) { + throw new Exception("Error retreiving user " . $username . "."); + } + + $fl = $this->flatten($info); + + if( count($fl) != 1 ) { + throw new Exception("Unexpected size of user array."); + } + + /* Removing objectclass... */ + unset($fl[0]['objectclass']); + + return $fl[0]; + + } + public function getUserWithMail($mail) { + + $filter = "(&(mail=$mail)(objectClass=posixAccount))"; + $attrs = array(); + + $info = $this->search(USUFFIX .",". SUFFIX, $filter, $attrs); + + if( $info['count'] != 1 ) { + throw new Exception("Error retreiving user " . $username . "."); + } + + $fl = $this->flatten($info); + + if( count($fl) != 1 ) { + throw new Exception("Unexpected size of user array."); + } + + /* Removing objectclass... */ + unset($fl[0]['objectclass']); + + return $fl[0]; + + } + + private function flatten($info) { + $res = array(); + + for($i=0;$i<$info['count'];$i++) { + $obj_i = $info[$i]; + for($j=0;$j<$obj_i['count'];$j++) { + if( $obj_i[$obj_i[$j]]['count'] == 1) { + $res[$i][$obj_i[$j]] = $obj_i[$obj_i[$j]][0]; + } else { + for($k=0;$k<$obj_i[$obj_i[$j]]['count'];$k++) { + $res[$i][$obj_i[$j]][] = $obj_i[$obj_i[$j]][$k]; + } + } + } + } + return $res; + } + + public function getAllUsers() { + $filter = "(uid=*)"; + $attrs = array(); + $res = ldap_search($this->conn, USUFFIX . "," . SUFFIX, $filter, $attrs); + if(! $res ) { + throw new Exception("Could not search ldap directory for users."); + } + + $users = array(); + + $info = ldap_get_entries($this->conn, $res); + for($i=0;$i<$info['count'];$i++) { + $users[] = $info[$i]; + } + return $users; + } + + public function getAllUsernames() { + $filter = "(&(uid=*))"; + $attrs = array("uid"); + $res = $this->search(USUFFIX .",". SUFFIX, $filter, $attrs); + if(!$res) { + throw new Exception("Could not search ldap directory for users."); + } + + $users = array(); + for($i=0;$i<$res['count'];$i++) { + $users[] = $res[$i]['uid'][0]; + } + return $users; + } + + public function getAllPrivateGroups() { + $filter = "(&(!(cn=dns-*))(objectclass=posixGroup))"; + $attrs = array(); + $res = $this->search(GSUFFIX . "," . SUFFIX, $filter, $attrs); + if(!$res) { + throw new Exception("Could not search ldap directory for private groups."); + } + + $groups = array(); + + for($i=0;$i<$res['count'];$i++) { + $group = array(); + $group['cn'] = $res[$i]['cn'][0]; + $group['description'] = $res[$i]['description'][0]; + $group['gidNumber'] = (int) $res[$i]['gidnumber'][0]; + $groups[] = $group; + } + + + return $groups; + } + + public function getAllDnsGroups() { + $filter = "(&(cn=dns-*)(objectclass=posixGroup))"; + $attrs = array(); + $res = $this->search(GSUFFIX . "," . SUFFIX, $filter, $attrs); + if(!$res) { + throw new Exception("Could not search ldap directory for dns groups."); + } + + $groups = array(); + + for($i=0;$i<$res['count'];$i++) { + $group = array(); + $group['cn'] = $res[$i]['cn'][0]; + $group['description'] = $res[$i]['description'][0]; + $group['gidNumber'] = (int) $res[$i]['gidnumber'][0]; + $groups[] = $group; + } + + return $groups; + } + + public function getGroupMembers($group) { + $filter = "(&(cn=".$group.")(objectclass=posixGroup))"; + $attrs = array("memberUid"); + $res = $this->read($this->groupDn($group), $filter, $attrs); + + $members = array(); + + if( ! $res ) { + return $members; + } + /* Return an empty array for the groups that do not + * contain any members */ + if( $res[0]['count'] == 0 ) return $members; + + for($i=0;$i<$res[0]['memberuid']['count'];$i++) { + $members[] = $res[0]['memberuid'][$i]; + } + + return $members; + } + + public function getUserGroups($username) { + $filter = "(&(memberUid=$username))"; + $attrs = array("cn"); + $attrsonly = 0; + $res = ldap_search($this->conn, GSUFFIX . "," . SUFFIX, + $filter, $attrs, $attrsonly); + if( !$res ) { + throw new Exception("ERROR. An error occured while searching for usergroups."); + } + $info = ldap_get_entries($this->conn, $res); + + $groups = array(); + for($i = 0; $i < $info['count']; $i++) { + array_push($groups, $info[$i]['cn'][0]); + } + + return $groups; + } + + public function userExists($username) { + if( empty($username) ) { + throw new Exception("<". __FUNCTION__ ."> ERROR: username is empty or null."); + } + $dn = $this->userDn($username); + $filter = "(&(uid=$username))"; + $attrs = array("dn"); + $attrsonly = 1; + + $res = ldap_search($this->conn, USUFFIX . "," . SUFFIX, + $filter, $attrs, $attrsonly); + + if( !$res ) { + throw new Exception("ERROR: An error occured while searching for user."); + } + + $info = ldap_get_entries($this->conn, $res); + + return ($info['count'] == 0? false : true); + } + public function mailExists($mail) { + if( empty($mail) ) { + throw new Exception("<". __FUNCTION__ ."> ERROR: mail is empty or null."); + } + $dn = USUFFIX . "," . SUFFIX; + $filter = "(mail=$mail)"; + $attrs = array("mail"); + $attrsonly = 1; + + $res = ldap_search($this->conn, USUFFIX . "," . SUFFIX, + $filter, $attrs, $attrsonly); + + if( !$res ) { + throw new Exception("ERROR: An error occured while searching for user."); + } + + $info = ldap_get_entries($this->conn, $res); + + return ($info['count'] == 0? false : true); + } + + public function groupExists($groupname) { + if( empty($groupname) ) { + throw new Exception("<". __FUNCTION__ ."> ERROR: groupname is empty or null."); + } + $filter = "(objectclass=*)"; + $attrs = array("cn"); + $res = ldap_read($this->conn, $this->groupDn($groupname), $filter, $attrs); + + if( !$res ) { + return false; +// throw new Exception("<". __FUNCTION__ ."> ERROR: could not read group"); + } + + $count = ldap_count_entries($this->conn, $res); + + return ($count == 1? true : false); + } + + public function homeDirectoryMountExists($username) { + if( empty($username) ) { + throw new Exception("<". __FUNCTION__ ."> ERROR: username is empty or null."); + } + $filter = "(objectclass=*)"; + $attrs = array("cn"); + $res = ldap_read($this->conn, $this->homeAutomountDn($username), $filter, $attrs); + + if( !$res ) { + return false; +// throw new Exception("<". __FUNCTION__ ."> ERROR: could not read automount"); + } + + $count = ldap_count_entries($this->conn, $res); + + return ($count == 1? true : false); + + } + private function ldapError() { + return ldap_error($this->conn); + } + + public function kerberosPrincipalExists($username) { + if( empty($username) ) { + throw new Exception("<". __FUNCTION__ ."> ERROR: username is empty or null."); + } + + $filter = "(objectclass=*)"; + $attrs = array("krbprincipalname"); + $res = ldap_read($this->conn, $this->kerberosPrincipalDn($username), $filter, $attrs); + + if( !$res ) { + return false; + } + + $count = ldap_count_entries($this->conn, $res); + + return ($count == 1? true : false); + + } + + private function getNextGid() { + $dn = GSUFFIX . "," . SUFFIX; + $filter = "(&(cn=dns-*))"; + $attrs = array("gidNumber"); + $res = ldap_search($this->conn, $dn, $filter, $attrs); + + if( !$res ) { + throw new Exception("ERROR: could not perform search for gid."); + } + + $info = ldap_get_entries($this->conn, $res); + + $num = (int) GID_MIN; + + for($i = 0; $i < $info['count']; $i++) { + if( $num < $info[$i]['gidnumber'][0] ) { + $num = (int) $info[$i]['gidnumber'][0]; + } + } + + if( $num >= (int) GID_MAX ) { + throw new Exception("ERROR: Gid number larger then GID_MAX"); + } + + return $num + 1; + } + + private function getNextUserGid() { + $dn = GSUFFIX . "," . SUFFIX; + $filter = "(&(!(cn=dns-*))(gidNumber=*))"; + $attrs = array("gidNumber"); + $res = ldap_search($this->conn, $dn, $filter, $attrs); + + if( !$res ) { + throw new Exception("ERROR: could not perform search for gid."); + } + + $info = ldap_get_entries($this->conn, $res); + + $num = (int) USER_GID_MIN; + for($i = 0; $i < $info['count']; $i++) { + if( $num < $info[$i]['gidnumber'][0] ) { + $num = (int) $info[$i]['gidnumber'][0]; + } + } + + if( $num >= (int) USER_GID_MAX ) { + throw new Exception("Error: Gid number larger then USER_GID_MAX"); + } + + return $num + 1; + } + + private function getNextUid() { + $dn = USUFFIX . "," . SUFFIX; + $filter = "(&(uid=*))"; + $attrs = array("uidNumber"); + $res = ldap_search($this->conn, $dn, $filter, $attrs); + if( !$res ) { + throw new Exception("ERROR: could not perform search for uid."); + } + $info = ldap_get_entries($this->conn, $res); + $num = (int) UID_MIN; + for($i = 0; $i < $info['count']; $i++) { + if( $num < $info[$i]['uidnumber'][0] ) { + $num = (int) $info[$i]['uidnumber'][0]; + } + } + + if( $num >= (int) UID_MAX ) { + throw new Exception("ERROR: UID number larger then UID_MAX"); + } + + return $num + 1; + } + + private function createUserHomeDirectory($user) { + $username = $user['username']; + $res = exec("sudo -u localedb /opt/edb/inside_ldap/create_user_home_directory.sh $username", + $output, $retval); + if( $retval != 0 ) { + throw new Exception("Could not create users home directory: $res"); + } + debug("Created home directory"); + return true; + } + + private function createUserHomeDirectoryMount($username) { + $info = array(); + + $info['objectClass'] = array("top", "automount"); + + $info['cn'] = $username; + $info['automountInformation'] = "-fstype=nfs4,rw,sec=krb5 " . FILESERVER . ":" . FILESERVER_HOMES . + "/" . $username; + + $dn = "cn=" . $username .",ou=auto.home,ou=Automount," . SUFFIX; + + return $this->ldapAdd($dn, $info); + } + + private function deleteUserHomeDirectoryMount($username) { + + $dn = "cn=" . $username .",ou=auto.home,ou=Automount," . SUFFIX; + + return $this->ldapDelete($dn); + } + + private function createUserKerberosCredentials($username, $password) { + $str = "sudo -u localedb /opt/edb/inside_ldap/create_user_kerberos_credentials.sh $username $password"; + $res = exec($str, $output, $retval); + if( $retval != 0 ) { + ldap_log("ERROR creating kerberos credentials: " . implode(",", $output)); + throw new Exception("Could not create users kerberos credentials"); + } + debug("Created users kerberos credentials"); + return true; + } + + private function deleteUserKerberosCredentials($username) { + $dn = "krbPrincipalName=$username@NEUF.NO,cn=NEUF.NO,cn=krbcontainer," . SUFFIX; + return $this->ldapDelete($dn); + } + + public function addGroup($name, $description, $gid = null) { + $dn = $this->groupDn($name); + + $info = array(); + $info['objectClass'] = array(); + $info['objectClass'][0] = "posixGroup"; + $info['description'] = $description; + $info['gidNumber'] = (int) ($gid == null? $this->getNextGid() : $gid); + + return $this->ldapAdd($dn, $info); + } + + + public function addUser($userinfo) { + if( !is_array($userinfo) ) { + throw new Exception("ERROR: Userinfo is not an array"); + } + + $info = array(); + /* Objectclass */ + $info['objectClass'] = array(); + $info['objectClass'][0] = "inetOrgPerson"; + $info['objectClass'][1] = "posixAccount"; + $info['objectClass'][2] = "shadowAccount"; + + /* User dn (identifies this record in LDAP) */ + $dn = $this->userDn($userinfo['username']); + + /* General user info */ + $info['uid'] = $userinfo['username']; + $info['givenname'] = $userinfo['firstname']; + $info['sn'] = $userinfo['lastname']; + $info['cn'] = $userinfo['firstname'] . " " . $userinfo['lastname']; + $info['displayname'] = $userinfo['firstname'] . " " . $userinfo['lastname']; + $info['gecos'] = $this->gecos($userinfo['username']); + $info['mail'] = $userinfo['email']; + + /* System specific user info */ + $info['userpassword'] = "{SSHA}". ssha($userinfo['password']); + $info['loginshell'] = LOGIN_SHELL; + $info['shadowexpire'] = (int) SHADOW_EXPIRE; + $info['shadowflag'] = (int) SHADOW_FLAG; + $info['shadowwarning'] = (int) SHADOW_WARNING; + $info['shadowmin'] = (int) SHADOW_MIN; + $info['shadowmax'] = (int) SHADOW_MAX; + $info['shadowlastchange'] = (int) SHADOW_LAST_CHANGE; + $info['homedirectory'] = HOME_DIRECTORY_PREFIX . "/" . $userinfo['username']; + $info['uidnumber'] = (int) $this->getNextUid(); + $info['gidnumber'] = (int) $this->getNextUserGid(); + + /* Check if the user is already in the LDAP directory */ + $user = $this->userExists($userinfo['username']); + if( $user == true ) { + throw new Exception("User ". $userinfo['username'] . " already exists."); + } + + if( $this->addGroup($userinfo['username'], "Usergroup", $info['gidnumber']) + === false ) { + throw new Exception("ERROR: ldap_add `group' failed."); + } + + if( $this->ldapAdd($dn, $info) === false ) { + throw new Exception("ERROR: ldap_add user: `". $info['uid']."' failed."); + } + + if( $this->createUserHomeDirectory($userinfo) === false ) { + throw new Exception("ERROR: could not create user home directory."); + } + + if( $this->createUserHomeDirectoryMount($userinfo['username']) === false ) { + throw new Exception("ERROR: could not create home directory mount in ldap"); + } + + if( $this->createUserKerberosCredentials($userinfo['username'], $userinfo['password']) === false) { + throw new Exception("ERROR: could not create user kerberos credentials."); + } + return true; + } + + public function addUserToGroup($username, $groupname) { + $dn = $this->groupDn($groupname); + $attr = array(); + $attr['memberUid'][] = $username; + + $this->bind(); + $res = ldap_mod_add($this->conn, $dn, $attr); + $this->unbind(); + + if( $res ) { + debug("Added $username to $dn"); + } else { + debug("Could not add $username to $dn"); + } + + return $res; + } + + public function removeUserFromGroup($username, $groupname) { + $dn = $this->groupDn($groupname); + $attr = array(); + $attr['memberUid'][] = $username; + + $this->bind(); + $res = ldap_mod_del($this->conn, $dn, $attr); + $this->unbind(); + + if( $res ) { + debug("Removed $username from $dn"); + } else { + debug("Could not remove $username from $dn"); + } + + return $res; + } + + public function deleteUser($username) { + /* Find all groups the user is a member of */ + $usergroups = $this->getUserGroups($username); + + foreach($usergroups as $group) { + $this->removeUserFromGroup($username, $group); + } + + $this->deleteUserHomeDirectoryMount($username); + $this->deleteUserKerberosCredentials($username); + + /* Delete the users usergroup */ + $this->ldapDelete($this->groupDn($username)); + + /* Delete the user */ + $this->ldapDelete($this->userDn($username)); + + return true; + } + + public function setUserPassword($username, $password) { + $dn = $this->userDn($username); + $this->bind(); + $attrs = array(); + $attrs['userPassword'] = ssha($password); + $res = ldap_mod_replace($this->conn, $dn, $attrs); + + if( $res ) { + debug("Password set/change for $dn"); + } else { + debug("Could not set password for $dn"); + } + + return $res; + } + + private function gecos($string) { + return $string; + } + + public function printIntegrityCheckStart($name) { +// debug("Running integrity check <" . $name . ">"); + _log_check("Running integrity check <" . $name . ">"); + } + + public function printIntegrityCheckStop($name) { +// debug("Completed integrity check <" . $name . ">"); + _log_check("Completed integrity check <" . $name . ">"); + } + + public function runAllIntegrityChecks() { + _log_check("------ Starting all integrity checks ------"); + $pass = true; + $methods = get_class_methods(__CLASS__); + foreach($methods as $method) { + if( strpos($method, "check") === 0 ) { + $this->printIntegrityCheckStart($method); + try { + if( $this->$method() === false ) { + $pass = false; + } + + } catch( Exception $e ) { + _log_check($e->getMessage()); + } + $this->printIntegrityCheckStop($method); + } + } + + if( $pass === false ) { + mail_admins("Integrity check failed, please review log."); + } + + _log_check("------ Completed all integrity checks (pass=". ($pass? "true":"false") .") ------"); + } + + public function checkUserPrimaryGroup() { + $filter = "(&(uid=*))"; + $attrs = array("uid"); + $res = $this->search(USUFFIX .",". SUFFIX, $filter, $attrs, true); + if(!$res) { + return false; + } + + $return_val = true; + + for($i=0;$i<$res['count'];$i++) { + $user = $res[$i]; + if( $this->groupExists($user['uid'][0]) === false ) { + _log_check_error("User `". $user['uid'][0] ."' does not have a primary group."); + $return_val = false; + } + } + + return $return_val; + } + + public function checkUserKerberosPrincipal() { + $users = $this->getAllUsernames(); + $return_val = true; + foreach($users as $user) { + if( $this->kerberosPrincipalExists($user) === false ) { + _log_check_error("User `". $user . "' does not have a kerberos principal."); + $return_val = false; + } + } + + return $return_val; + } + + public function checkUserAutomountHomeDirectory() { + $users = $this->getAllUsernames(); + $return_val = true; + foreach($users as $user) { + if( $this->homeDirectoryMountExists($user) === false ) { + _log_check_error("User `". $user . "' does not have a home directory mount record."); + $return_val = false; + } + } + + return $return_val; + } + + public function checkPrivateGroupUserExists() { + $private_groups = $this->getAllPrivateGroups(); + $return_val = true; + foreach($private_groups as $group) { + /* Special groups that don't require a user */ + if( $group['cn'] == "edb" ) continue; + if( $group['cn'] == "edbadmin" ) continue; + + if( $this->userExists($group['cn']) === false ) { + _log_check_error("Private Group `" . $group['cn'] . "' exists but user does not."); + $return_val = false; + } + } + + return $return_val; + } + + public function checkDnsGroupMembersExists() { + $dns_groups = $this->getAllDnsGroups(); + + $return_val = true; + + foreach($dns_groups as $group) { +// debug("Getting members for " . $group['cn']); + $members = $this->getGroupMembers($group['cn']); + foreach($members as $member) { + if( !$this->userExists($member) ) { + _log_check_error("Group `". $group['cn'] ."' contain user `". $member . + "', but the user does not exist."); + $return_val = false; + } + } + } + + /* These two are special groups */ + foreach(array("edb", "edbadmin") as $group) { + $members = $this->getGroupMembers($group); + foreach($members as $member) { + if( !$this->userExists($member) ) { + _log_check_error("Group `". $group ."' contain user `". $member . + "', but the user does not exist."); + $return_val = false; + } + } + } + + return $return_val; + } + + public function checkKerberosPrincipalUserExists() { + _log_check_error("Not implemented"); + return false; + } + + public function checkAutomountHomeDirectoryUserExists() { + _log_check_error("Not implemented"); + return false; + } + +} diff --git a/includes/Ldap_defines.php b/includes/Ldap_defines.php new file mode 100644 index 0000000..41414b3 --- /dev/null +++ b/includes/Ldap_defines.php @@ -0,0 +1,136 @@ +lmhash($password); +} + +function ntPassword($password) { + $hash = new SmbHash(); + return $hash->nthash($password); +} + +function ssha($password) { + return ssha_encode($password); +/* $salt = sha1(rand()); + $salt = substr($salt, 0, 4); + $hash = base64_encode( sha1 ($password . $salt, true) . $salt ); + return $hash;*/ +} + +function ssha_encode($password) { + $salt = ""; + for ( $i=1;$i<=10;$i++ ) { + $salt .= substr('0123456789abcdef', rand(0,15), 1); + } + $hash = base64_encode(pack("H*", sha1($password.$salt)).$salt); + + return $hash; +} + +function debug($str) { + $time = date("[Y-m-d H:i:s] "); + echo $time . $str . "\n"; +} + +function ldap_log($str) { + $time = date("[Y-m-d H:i:s] "); + //file_put_contents("/var/www/neuf.no/userinfo/log/user.log", $time . + // $str . "\n", FILE_APPEND); +} + +function _log_check($str) { + $time = date("[Y-m-d H:i:s] "); +// file_put_contents("/var/www/neuf.no/userinfo/log/integrity_check.log", $time . +// $str . "\n", FILE_APPEND); + debug($str); +} + +function _log_check_error($str) { + $time = date("[Y-m-d H:i:s] "); +// file_put_contents("/var/www/neuf.no/userinfo/log/integrity_check.log", $time . "[ERROR] " . +// $str . "\n", FILE_APPEND); + debug($str); + +} + +function mail_admins($str) { + _log_check("Mailing admins..."); +} + +function validate_user_info($user) { + if( !is_array($user) ) { + throw new Exception("ERROR: user array is not an array"); + } + + if( preg_match(USERNAME_REGEXP, $user['username']) == 0 ) { + throw new Exception("ERROR: username did not validate"); + } + + if( empty($user['firstname']) ) { + throw new Exception("ERROR: firstname missing"); + } + + if( empty($user['lastname']) ) { + throw new Exception("ERROR: lastname missing"); + } + + if( empty($user['email']) ) { + throw new Exception("ERROR: email missing"); + } + + if( empty($user['password']) ) { + throw new Exception("ERROR: password missing"); + } +} diff --git a/inside/ActionParser.php b/inside/ActionParser.php index 6131e7f..4efae0b 100644 --- a/inside/ActionParser.php +++ b/inside/ActionParser.php @@ -39,7 +39,7 @@ class ActionParser { if (checkAuth('perform-' . $this->action) || checkResponsible()) { switch ($this->action) { case 'log-in' : - $this->_logIn(); + new_login(scriptParam('username'),scriptParam('password')); break; case 'log-out' : @@ -589,60 +589,58 @@ private function logError($username, $error) $conn->query($sql); } - public function _logIn() { +public function _logIn() { $conn = db_connect(); + /* query db with form data (password, username) */ $sql = sprintf("SELECT id, passwordReset FROM din_user " . - "WHERE username = %s " . - "AND (password = PASSWORD(%s) or password = old_password(%s))", $conn->quoteSmart(scriptParam('username')), $conn->quoteSmart(scriptParam('password')), $conn->quoteSmart(scriptParam('password'))); + "WHERE username = %s " . + "AND (password = PASSWORD(%s) or password = old_password(%s))", $conn->quoteSmart(scriptParam('username')), $conn->quoteSmart(scriptParam('password')), $conn->quoteSmart(scriptParam('password'))); $result = $conn->query($sql); if (DB :: isError($result) != true) { - if ($result->numRows() > 0) { - $row = $result->fetchRow(DB_FETCHMODE_ASSOC); - $_SESSION['valid-user'] = $row['id']; - - // SHA1 - if ($_GET['debug']){ - echo "{SHA}" . base64_encode(pack("H", hash('sha1', $conn->quoteSmart(scriptParam('password'))))); - - die("Jeg skammer meg over at dette er skrevet i vim - Sjur"); - } + /* more than 1 row means valid user */ + if ($result->numRows() > 0) { + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + $_SESSION['valid-user'] = $row['id']; - if ($row['passwordReset'] == 1) { - $GLOBALS['extraScriptParams']['page'] = "reset-password"; + /* someone has requested a password reset, redirect to that page instead */ + if ($row['passwordReset'] == 1) { + $GLOBALS['extraScriptParams']['page'] = "reset-password"; + } + } else { + try + { + /* log auth errors with reason */ + $sql = sprintf("SELECT id FROM din_user WHERE username = %s", $conn->quoteSmart(scriptParam('username'))); + $result = $conn->query($sql); + $userExists = $result->numRows() > 0; + + $error = ''; + if(scriptParam('password') == '') + { + $error = 'no password supplied?'; + } + elseif($userExists) + { + $error = "user exists, wrong password?"; + } + else + { + $error = "user not found.."; + } + + $this->logError(scriptParam('username'), $error); + } + catch(Exception $e) + { + mail('komans@studentersamfundet.no','error with errorlog','error with errorlog'); + } + /* give user feedback */ + notify("Problemer med innlogging."); } - } else { - try - { - $sql = sprintf("SELECT id FROM din_user WHERE username = %s", $conn->quoteSmart(scriptParam('username'))); - $result = $conn->query($sql); - $userExists = $result->numRows() > 0; - - $error = ''; - if(scriptParam('password') == '') - { - $error = 'no password supplied?'; - } - elseif($userExists) - { - $error = "user exists, wrong password?"; - } - else - { - $error = "user not found.."; - } - - $this->logError(scriptParam('username'), $error); - } - catch(Exception $e) - { - mail('komans@studentersamfundet.no','error with errorlog','error with errorlog'); - } - notify("Problemer med innlogging."); - } } - } +} public function _logOut() { unset ($_SESSION['valid-user']); diff --git a/inside/Navigation.php b/inside/Navigation.php index a1fe835..5346e73 100644 --- a/inside/Navigation.php +++ b/inside/Navigation.php @@ -7,8 +7,9 @@ class Navigation { ?> + -_displayFooter(); -?> - - - -"; - $html .= "

Script execution: $time seconds || support"; - - $html .= "

upload_max_filesize = " . ini_get("upload_max_filesize") . "

"; - $html .= "\n"; - - print $html; - -/** - * Google Analytics, since 2010-11-19 15:05 - */ -?> - - @@ -620,10 +479,10 @@ possibly include it instead? --Thomas Misund, 26. Oct 2009 - - - + href="../css/theme; ?>" media="screen, projection" /> + + + diff --git a/inside/Payment.php b/inside/Payment.php index 3de855e..800004a 100644 --- a/inside/Payment.php +++ b/inside/Payment.php @@ -16,21 +16,6 @@ class Payment { } private function initPayex() { - //From setupexample - define('PAYEX_PXPARTNER_WSDL', 'https://external.payex.com/pxorder/pxpartner.asmx?WSDL'); - define('PAYEX_PXPRINT_WSDL', 'https://external.payex.com/pxorder/pxprint.asmx?WSDL'); - define('PAYEX_PXDEPOSIT_WSDL', 'https://external.payex.com/pxorder/pxdeposit.asmx?WSDL'); - define('PAYEX_PXACCOUNT_WSDL', 'https://external.payex.com/pxorder/pxaccount.asmx?WSDL'); - define('PAYEX_PXORDER_WSDL', 'https://external.payex.com/pxorder/pxorder.asmx?WSDL'); - define('PAYEX_PXCLIENT_WSDL', 'https://external.payex.com/pxclient/pxclient.asmx?WSDL'); - define('PAYEX_PXMERCHANT_WSDL', 'https://external.payex.com/pxmerchant/pxmerchant.asmx?WSDL'); - define('PAYEX_PXSUBSCRIPTION_WSDL', 'https://external.payex.com/pxsubscription/pxsubscription.asmx?WSDL'); - define('PAYEX_PXAGREEMENT_WSDL', 'https://external.payex.com/pxagreement/pxagreement.asmx?WSDL'); - - define('PAYEX_PXORDER_URL', 'https://account.payex.com/pxorder.asp'); // url to redirect user to - define('PAYEX_ACCOUNTNUMBER', 20180218); // payex merchant account number - define('PAYEX_ENCRYPTIONKEY', 'vy8wMAvJjvW4RaCEWJFf'); // payex encryption key - // end setup require_once ('../payex2/payex_pxorder.php'); // Include the Payex PxOrder implementation $this->payex = new PayexPxOrder(); // Make an instance of the PayexPxOrder class diff --git a/inside/functions.php b/inside/functions.php index a5b7964..1b54e0b 100644 --- a/inside/functions.php +++ b/inside/functions.php @@ -692,7 +692,7 @@ function createTransactionId() { function checkResponsible() { $subject = $_REQUEST; ob_start(); - var_dump($subject); + //var_dump($subject); $subject = ob_get_clean(); if (strstr($subject, "id") != false) { $pattern = "/\w+id/"; @@ -1030,7 +1030,7 @@ function displayLogin() { "brukernavn", + "label" => "Epost eller brukernavn", "type" => "text", "attributes" => Array ( "name" => "username", - "size" => 12, - "maxlength" => 12 + "size" => 25, + "maxlength" => 100 ) ); $fields[] = Array ( - "label" => "passord", + "label" => "Passord", "type" => "password", "attributes" => Array ( "name" => "password", @@ -1665,5 +1665,4 @@ function find_groups($uid) { return $arr; } - ?> diff --git a/inside/graphics/bannerindex-400.png b/inside/graphics/bannerindex-400.png new file mode 100644 index 0000000..11e70c9 Binary files /dev/null and b/inside/graphics/bannerindex-400.png differ diff --git a/inside/graphics/header-210x.png b/inside/graphics/header-210x.png new file mode 100644 index 0000000..de59222 Binary files /dev/null and b/inside/graphics/header-210x.png differ diff --git a/inside/includes.php b/inside/includes.php index 86b9d58..8b68a23 100644 --- a/inside/includes.php +++ b/inside/includes.php @@ -21,7 +21,11 @@ set_include_path("../includes"); $include_path = "../includes/"; //PEAR-class -require_once $include_path."DB.php"; +require_once "DB.php"; + +/* LDAP auth*/ +require_once "Ldap_defines.php"; +require_once "ldap.php"; //Local classes require_once "Action.php"; diff --git a/inside/ldap.php b/inside/ldap.php new file mode 100644 index 0000000..321dbe4 --- /dev/null +++ b/inside/ldap.php @@ -0,0 +1,140 @@ +mailExists($username_or_email) ) { + return $db->getUserWithMail($username_or_email); + } + if($db->userExists($username_or_email)) { + return $db->getUser($username_or_email); + } + return false; +} + +function ldap_authenticate($username, $password, $db) { + return $db->testBind($username, $password); +} + +function legacy_user_exists($username) { + $conn = db_connect(); + + /* get legacy_user_id */ + $sql = sprintf("SELECT id FROM din_user WHERE username=%s", $conn->quoteSmart($username)); + $result = $conn->query($sql); + if (DB :: isError($result) == true) { + /* dberror */ + notify("Databasen sliter, prøv igjen senere."); + return false; + } + if ($row = & $result->fetchRow(DB_FETCHMODE_ASSOC)) { + return $row['id']; + } + return false; +} + +function legacy_get_user_from_mail($mail) { + $conn = db_connect(); + + $sql = sprintf("SELECT username FROM din_user WHERE email = %s", $conn->quoteSmart($mail)); + $result = $conn->query($sql); + if (DB :: isError($result) == true) { + /* dberror */ + notify("Databasen sliter, prøv igjen senere."); + return false; + } + if ($row = & $result->fetchRow(DB_FETCHMODE_ASSOC)) { + return $row['username']; + } + return false; +} + +function legacy_authenticate($username, $password) { + $conn = db_connect(); + /* query db with form data (password, username) */ + $sql = sprintf("SELECT id FROM din_user WHERE username = %s AND (password = PASSWORD(%s) or password = OLD_PASSWORD(%s))", + $conn->quoteSmart($username), + $conn->quoteSmart($password), + $conn->quoteSmart($password)); + + $result = $conn->query($sql); + if (DB :: isError($result) != true) { + /* more than 1 row means valid user */ + if ($result->numRows() > 0) { + $row = $result->fetchRow(DB_FETCHMODE_ASSOC); + return $row['id']; + } + } + return false; +} + +function is_mail($subject) { + $subject = trim($subject); + /* from: http://www.regular-expressions.info/email.html */ + $pattern = "/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i"; + $match = preg_match($pattern, $subject); + + return $match; +} + +?> diff --git a/inside/menuExpandable3.js b/inside/menuExpandable3.js index 236ad35..ca76409 100644 --- a/inside/menuExpandable3.js +++ b/inside/menuExpandable3.js @@ -17,11 +17,11 @@ function initializeMenu(menuId, actuatorId) { return; } - actuator.parentNode.style.backgroundImage = "url(graphics/plus.png)"; + actuator.parentNode.style.backgroundImage = "url(../inside/graphics/plus.png)"; actuator.onclick = function() { var display = menu.style.display; this.parentNode.style.backgroundImage = - (display == "block") ? "url(graphics/plus.png)" : "url(graphics/minus.png)"; + (display == "block") ? "url(../inside/graphics/plus.png)" : "url(../inside/graphics/minus.png)"; menu.style.display = (display == "block") ? "none" : "block"; return false; @@ -33,7 +33,7 @@ function menuExpandCurrentSection(menuId){ if (menu == null){ return; } - menu.parentNode.style.backgroundImage = "url(graphics/minus.png)"; + menu.parentNode.style.backgroundImage = "url(../inside/graphics/minus.png)"; menu.style.display = "block"; } diff --git a/inside/screen.css.backup b/inside/screen.css.backup deleted file mode 100644 index f6fada4..0000000 --- a/inside/screen.css.backup +++ /dev/null @@ -1,700 +0,0 @@ -/** - * text: #000 (black) - * background: #FFF (white) - * light-fill: #EEE - * conrast-fill: #DDD - * passive-cell: #AAA - * border: #CCC - * link: #00D - * - **/ -/* =general -*********************************************************************/ - -html, body { - margin: 0; - padding: 5px; - font-size: .905em; - line-height: 1.5em; - font-family: arial, sans-serif; -} - -img { - border: none; - display: block; -} - -td img { - display: inline; -} - -.mceEditor img { - display: inline; -} - -p { - margin: 0 0 5px 0; - padding: 0; -} - -em { - font-style: italic; -} - -strong, p.strong { - font-weight: bolder; -} - - -/* =links -*********************************************************************/ - -a { - margin: 0; - padding: 0; - text-decoration: none; - color: #00D; -} - -a:hover { - text-decoration: underline; -} - -a:visited { - color: #00D; -} - -th a { - color: #000; -} - -th a:visited { - color: #000; -} - -.optionsMenu a, a.button, span.button, label.button { - border: 1px solid #CCC; - background: #DDD; - padding: 1px 5px; - margin: 3px 0; - letter-spacing: 1px; - color: #000; - font-weight: bold; - white-space: nowrap; -} - -a.read { - font-weight: normal; -} - -a.unread { - font-weight: bold; -} - -a.skip-nav { - display: none; -} - -a.contact { - background: url("graphics/user_go.png") no-repeat right; - padding-right: 20px; -} -/* =lists -*********************************************************************/ - -ul { - -} - -li { - -} - -ul.linker, .linker li { - margin: 0; - padding: 0; - list-style: none; -} - -/* =forms -*********************************************************************/ - -form { - margin: 0; - padding: 0; -} - -textarea, input { - font-family: arial, sans-serif; - line-height: 1.2em; - font-size: 1em; - margin: 2px 0; -} - -form .title { - font-size: 16px; - font-weight: bold; -} - -textarea:focus, input:focus { - background: #FFD; -} - -.readonly { - background: inherit; - border: none; -} - -fieldset { - width: 90%; - max-width: 600px; - padding: 15px; - border: 3px solid #CCC; -} - -fieldset label { - font-weight: bold; -} - -legend { - font-weight: bold; - padding: 0 5px; - color: black; -} - -fieldset input, fieldset select, fieldset textarea { - margin: 0 15px; -} - -input.submit { - margin: 0px; - width: 100px; -} - -div.horizontal-form { - padding: 3px; - margin: 5px 0; - background: #EEE; - border: 1px solid #CCC; - font-weight: bold; -} - -.delete { - text-align: right; - color: red; - font-weight: bold; -} - -.formHelp { - cursor: help; -} - -.formHelpMessage { - background: #FFD; - border: 1px solid black; - font-size: 11px; - padding: 3px 3px 3px 20px; - max-width: 300px; -} - -.helpMessageClose { - border: 1px solid black; - position: absolute; - top: 2px; - left: 2px; - padding: 0 2px; - line-height: 1em; - cursor: pointer; - background: red; - color: white; - font-weight: bold; -} -/* =tables -*********************************************************************/ - -table { - margin: 5px 0; - padding: 0; - border: 1px solid #CCC; -} - -th { - padding: 0 5px; - text-align: center; - font-weight: bold; - letter-spacing: 2px; - background: #DDD; -} - -tr { - padding: 0px; - margin: 0px; -} - -td { - vertical-align: top; - padding: 0px 5px; - background: #EEE; -} - -td.label { - font-weight: bold; - text-align: right; -} - -td.number { - text-align: right; -} - -td.phone { - white-space: nowrap; -} - -td.date { - white-space: nowrap; -} - -td.is_member{ - text-align: center; -} - -tr.table-footer td { - font-weight: bold; - text-align: center; -} - -table.calendar { - width: 98%; - margin: 0 auto; - font-size: .85em; -} - -.calendar td { - padding: 0; - margin: 0; -} - -td.passive { - background: #AAA; -} - -td.weekNumber { - background: #DDD; - text-align: center; - vertical-align: middle; - font-weight: bold; -} - -div.calendar-event, label.calendar-event.button { - background: #CCC; -} - -div.calendar-concert, label.calendar-concert.button { - background: #DDD; -} - -.calendar td div { - padding: 2px 1px; - margin: 1px; - line-height: 1em; - border-bottom: 1px dotted #000; -} - -td h4 { - text-align: right; -} - -th a { - display: block; -} - -table.sortable tr:hover td { - background: #DDD; -} - -td.unread { - text-align: center; - font-size: 1.8em; - line-height: 0.1em; - padding: 15px 5px 0px 3px; -} - - -/* =headings -*********************************************************************/ - -h1, h2, h3, h4, h5, h6 { - margin: 0; - padding: 0; - line-height: 1.2em; -} - -h1 { - font-size: 2em; -} - -h2 { - font-size: 1.5em; - text-align: center; -} - -h3 { - font-size:1.2em; -} - -h4 { - font-size: 1em; - font-weight: bold; -} -/* =header -*********************************************************************/ -#header { - background-color: #EEE; - border: 1px solid #CCC; - -moz-border-radius: 8px; - color: #000; - text-align: center; - letter-spacing: 3px; - padding: 5px; -} - -#header h1 a { - text-decoration: none; - color: #000; - display: block; -} - - - -/* =navigation -*********************************************************************/ - - -#nav { - float: left; - background-color: #EEE; - border: 1px solid #CCC; - -moz-border-radius: 8px; - color: #000; - width: 170px; - margin: 5px 0 15px 0; - padding: 15px; -} - -#navList { - margin: 0px; - padding: 0px; -} - -li.menulist { - background: url(graphics/minus.png) no-repeat 3px 0.3em; - line-height: 1.2em; - list-style: none outside; - margin: 0px 0 10px; - padding: 2px 10px; - border: 1px solid black; -} - -.jsenabled li.menulist { - background: url(graphics/plus.png) no-repeat 3px 0.3em; -} - -.jsenabled .menu, .jsenabled .submenu { - display: none; -} - -.menu, .submenu { - margin: 0px; - padding: 0px; -} - -.menu li, .submenu li { - background: #EEE; - list-style: none outside; - margin: 3px 5px; - padding: 0px 3px; - border: 1px dotted #CCC; -} - -.menu li:hover, .submenu li:hover { - background: #DDD; -} - -#nav li a { - color: black; -} - -a.switch { - background-color: transparent; - color: #000; - font-size: .9em; - line-height: 1em; - padding-left: 5px; - text-decoration: none; - font-weight: bold; - display: block; -} - -a.switch:hover { - text-decoration: underline; -} - -.menu li a, .submenu li a { - display: block; - background-color: transparent; - color: #000; - text-decoration: none; -} - -.menu li a:hover, submenu li a:hover { - text-decoration: underline; -} - -span.key { - text-decoration: underline; -} - -#calHeader { - width: 400px; - margin: 0 auto; -} - -#previous { - float: left; - margin: 0px; -} - -#next { - float: right; - margin: 0px; -} - -#previous a, #next a { - border: 1px solid #CCC; - font-weight: bold; - padding: 0 5px; - margin: 0px; - line-height: 1em; - background: #DDD; - color: #000; -} - -/* =content -*********************************************************************/ -#content { - padding: 0px; - margin: 5px 0 15px 207px; -} - -div.text-column { - max-width: 600px; -} - -* html div.text-column { - width: 600px; -} - -div.article_images { - float: right; - margin: 0px 0px 3px 3px; - width: 200px; -} -div.article_images div { - border: 1px dotted #ccc; -} -/*div.primary_image { - float: right; - margin: 0px 0px 3px 3px; - width: 200px; - border: 1px dotted #ccc; -} -*/ -span.caption { - font-size: 11px; - font-style: italic; -} - -/*div.extra_image { - float: left; - margin: 0px 3px 3px 0px; - width: 200px; - border: 1px dotted #ccc; -}*/ - -p.date { - font-style: italic; -} - -p.date:first-letter { - text-transform: uppercase; -} - -p.subtitle { - font-style: italic; -} - -p.intro { - font-weight: bold; - font-style: italic; -} - -div.messages, div.errors { - margin: 0 0 5px 0; - padding: 3px; - background: #000; - color: #FFF; - border: 1px solid #CCC; -} - -div.messages ul, div.erros ul { - margin: 0 0 0 35px; - padding: 0; - font-weight: bold; -} - -div.timeData { - border: 1px solid #CCC; - background: #EEE; - padding: 1px; -} - -div.optionsMenu { - margin: 5px 0; -} - -div.product { - border: 1px solid black; - margin: 5px; - padding: 5px; - cursor: pointer; -} - -div.product_images { - float: right; -} - -tr.barshift-full td { - background: #AAA; - font-style: italic; -} - -td.worker-status { - text-align: center; - font-weight: bold; -} - -div.calendar-barshift { - border: 1px solid #CCC; -} - -div.calendar-barshift.full { - border: 1px solid #CCC; - background: #DDD; -} - -div.calendar-barshift h4 { - text-align: left; - white-space: nowrap; -} - -div.calendar-barshift ul { - margin: 0; - padding: 0; - list-style: none; -} - -.calendar-register-me { - border: 1px solid black; - padding: 1px; - width: 50%; - color: black; - margin: 0px; - display: block; - text-align: center; - background: #DDD; -} - -div.calendar-barshift li { - white-space: nowrap; - margin: 0; - padding: 0; -} - -div.comments { - border-top: 2px solid #CCC; - -} - -div.comment { - border-top: 2px solid #CCC; - padding: 5px 0; - position: relative; -} - -div.comment-meta { - position: absolute; - -} - -div.comment-main { - margin-left: 150px; - min-height: 60px; - border-left: 2px dotted #CCC; - padding-left: 5px; -} - -* html div.comment-main { - height: 60px; -} - -.clear-right { - clear: right; -} -/* =footer -*********************************************************************/ -#footer { - clear: both; - text-align: center; - background: #EEE; - border: 1px solid #CCC; - -moz-border-radius: 8px; - color: #000; - margin-top: 0px; -} - - - -/* =extras -*********************************************************************/ -.domenabled ul#finder, .domenabled ul#finder li, .domenabled ul#finder ul { - list-style-type:none; - margin: 5px 0; - padding:0; - line-height: 1em; -} - -.domenabled ul#finder ul.hidden { - display: none; -} -.domenabled ul#finder ul.shown { - margin: 3px 25px; - display: block; -} - -.domenabled ul#finder li a { -} - -.domenabled #finder a.open { - font-weight: bold; - display: block; - color: black; -} - -.domenabled #finder a.parent { - color: black; -} - - -.domenabled div.disabled { - display: none; -}