/** * Copyright 2009 Red Hat, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.safehaus.penrose.nis; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.safehaus.penrose.ldap.*; import org.safehaus.penrose.util.TextUtil; import org.safehaus.penrose.Penrose; import java.util.*; import net.sf.jpam.Pam; import net.sf.jpam.PamReturnValue; public abstract class NISClient { public Logger log = LoggerFactory.getLogger(getClass()); public Hashtable<String,String> parameters; public NISClient() throws Exception { } public void init(Map<String,String> parameters) throws Exception { this.parameters = new Hashtable<String,String>(); this.parameters.putAll(parameters); } public void connect() throws Exception { } public void close() throws Exception { } public void bind(String serviceName, String username, byte[] password) throws Exception { bind(serviceName, username, new String(password)); } public void bind(String serviceName, String username, String password) throws Exception { boolean debug = log.isDebugEnabled(); if (debug) { log.debug(TextUtil.displaySeparator(70)); log.debug(TextUtil.displayLine("Bind", 70)); log.debug(TextUtil.displayLine(" - User : "+username, 70)); log.debug(TextUtil.displayLine(" - Password: "+password, 70)); log.debug(TextUtil.displaySeparator(70)); } try { Pam pam = new Pam(serviceName); PamReturnValue returnValue = pam.authenticate(username, password); if (!returnValue.equals(PamReturnValue.PAM_SUCCESS)) { Penrose.errorLog.error("PAM return value: "+returnValue); throw LDAP.createException(LDAP.INVALID_CREDENTIALS); } } catch (Exception e) { Penrose.errorLog.error(e.getMessage(), e); throw LDAP.createException(e); } } public abstract void lookup( String base, RDN rdn, String type, SearchResponse response ) throws Exception; public abstract void list( String base, String type, SearchResponse response ) throws Exception; public SearchResult createSearchResult( String base, String type, String name, String line ) throws Exception { line = line.trim(); if ("".equals(line) || line.startsWith("#")) { log.debug("Empty/comment line: "+line); return null; } Attributes attributes = new Attributes(); DN dn = parse(base, type, name, line, attributes); if (dn == null) { log.debug("Unparsable line: "+line); return null; } return new SearchResult(dn, attributes); } public DN parse( String base, String type, String name, String line, Attributes attributes ) throws Exception { log.debug("Parsing "+name+": "+line+" ("+type +")"); if ("posixAccount".equals(type)) { return parsePosixAccount(name, line, attributes); } else if ("shadowAccount".equals(type)) { return parseShadowAccount(name, line, attributes); } else if ("ipHost".equals(type)) { return parseIPHost(name, line, attributes); } else if ("posixGroup".equals(type)) { return parsePosixGroup(name, line, attributes); } else if ("ipService".equals(type)) { return parseIPService(name, line, attributes); } else if ("oncRpc".equals(type)) { return parseONCRpc(name, line, attributes); } else if ("nisNetId".equals(type)) { return parseNISNetId(name, line, attributes); } else if ("ipProtocol".equals(type)) { return parseIPProtocol(name, line, attributes); } else if ("nisMailAlias".equals(type)) { return parseNISMailAlias(name, line, attributes); } else if ("nisNetgroup".equals(type)) { return parseNISNetgroup(name, line, attributes); } else if ("ieee802Device".equals(type)) { return parseIEEE802Device(name, line, attributes); } else if ("bootableDevice".equals(type)) { return parseBootableDevice(name, line, attributes); } else if ("ipNetwork".equals(type)) { return parseIPNetwork(name, line, attributes); } else if ("automountMap".equals(type)) { return parseAutomountMap(name, line, attributes); } else if ("automount".equals(type)) { return parseAutomount(base, name, line, attributes); } else if ("nisMap".equals(type)) { return parseNISMap(name, attributes); } return parseNISObject(type, name, line, attributes); } public DN parsePosixAccount(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); String tokens[] = line.split(":"); if (name == null) { name = tokens[0]; } rb.set("uid", name); attributes.setValue("primaryKey.uid", name); attributes.setValue("uid", name); String userPassword = tokens[1]; if (!"".equals(userPassword) && !"!!".equals(userPassword) && !"*".equals(userPassword) && !"x".equals(userPassword) && !userPassword.startsWith("##")) { attributes.setValue("userPassword", userPassword); } attributes.setValue("uidNumber", tokens[2]); attributes.setValue("gidNumber", tokens[3]); String gecos = tokens[4]; if (!"".equals(gecos)) attributes.setValue("gecos", gecos); if (tokens.length>5) attributes.setValue("homeDirectory", tokens[5]); if (tokens.length>6) attributes.setValue("loginShell", tokens[6]); return new DN(rb.toRdn()); } public DN parseShadowAccount(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); String tokens[] = line.split(":"); if (name == null) { name = tokens[0]; } rb.set("uid", name); attributes.setValue("primaryKey.uid", name); attributes.setValue("uid", name); DN dn = new DN(rb.toRdn()); if (tokens.length <= 1) return dn; String userPassword = tokens[1]; if (!"".equals(userPassword) && !"!!".equals(userPassword) && !"*".equals(userPassword) && !"x".equals(userPassword) && !userPassword.startsWith("##")) { attributes.setValue("userPassword", userPassword); } if (tokens.length <= 2) return dn; String s = tokens[2]; if (!"".equals(s)) attributes.setValue("shadowLastChange", s); if (tokens.length <= 3) return dn; s = tokens[3]; if (!"".equals(s)) attributes.setValue("shadowMin", s); if (tokens.length <= 4) return dn; s = tokens[4]; if (!"".equals(s)) attributes.setValue("shadowMax", s); if (tokens.length <= 5) return dn; s = tokens[5]; if (!"".equals(s)) attributes.setValue("shadowWarning", s); s = tokens[6]; if (tokens.length <= 6) return dn; if (!"".equals(s)) attributes.setValue("shadowInactive", s); if (tokens.length <= 7) return dn; s = tokens[7]; if (!"".equals(s)) attributes.setValue("shadowExpire", s); if (tokens.length <= 8) return dn; s = tokens[8]; if (!"".equals(s)) attributes.setValue("shadowFlag", s); return dn; } public DN parseIPHost(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); StringTokenizer st = new StringTokenizer(line, "\t "); attributes.setValue("ipHostNumber", st.nextToken()); while (st.hasMoreTokens()) { name = st.nextToken(); if (name.startsWith("#")) break; attributes.addValue("cn", name); } return new DN(rb.toRdn()); } public DN parsePosixGroup(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); String []tokens = line.split(":"); if (name == null) { name = tokens[0]; } rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); String userPassword = tokens[1]; if (!"".equals(userPassword) && !"!!".equals(userPassword) && !"*".equals(userPassword) && !"x".equals(userPassword)) { attributes.setValue("userPassword", userPassword); //attributes.set("userPassword", BinaryUtil.decode(BinaryUtil.BASE64, userPassword)); } attributes.setValue("gidNumber", tokens[2]); if (tokens.length > 3) { String members = tokens[3]; tokens = members.split(","); for (String token : tokens) { attributes.addValue("memberUid", token); } } return new DN(rb.toRdn()); } public DN parseIPService(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); String cn = st.nextToken(); attributes.setValue("cn", cn); String []tokens = st.nextToken().split("/"); attributes.setValue("ipServicePort", tokens[0]); attributes.setValue("ipServiceProtocol", tokens[1]); attributes.setValue("primaryKey.ipServicePort", tokens[0]); attributes.setValue("primaryKey.ipServiceProtocol", tokens[1]); rb.set("ipServicePort", tokens[0]); rb.set("ipServiceProtocol", tokens[1]); while (st.hasMoreTokens()) { cn = st.nextToken(); if (cn.startsWith("#")) break; attributes.addValue("cn", cn); } return new DN(rb.toRdn()); } public DN parseONCRpc(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); name = st.nextToken(); rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); attributes.setValue("oncRpcNumber", st.nextToken()); while (st.hasMoreTokens()) { name = st.nextToken(); if (name.startsWith("#")) break; attributes.addValue("cn", name); } return new DN(rb.toRdn()); } public DN parseNISNetId(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); if (name == null) { name = st.nextToken(); line = line.substring(name.length()+1).trim(); } rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); DN dn = new DN(rb.toRdn()); int i = name.indexOf("."); int j = name.indexOf("@", i+1); if (i > 0 && j > 0) { String s = name.substring(i+1, j); try { // unix.uid@domain uid:gid,gid,gid,... Long.parseLong(s); } catch (Exception e) { // unix.hostname@domain 0:hostname attributes.addValue("nisNetIdHost", s); return dn; } } else { // nobody uid:gid,gid // ignore } int k = line.indexOf(':'); String uid = line.substring(0, k); attributes.setValue("nisNetIdUser", uid); String remainder = line.substring(k+1).trim(); StringTokenizer st2 = new StringTokenizer(remainder, ",\t "); while (st2.hasMoreTokens()) { String token = st2.nextToken(); if (token.startsWith("#")) break; attributes.addValue("nisNetIdGroup", token); } return dn; } public DN parseIPProtocol(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); name = st.nextToken(); rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); attributes.setValue("ipProtocolNumber", st.nextToken()); while (st.hasMoreTokens()) { name = st.nextToken(); if (name.startsWith("#")) break; attributes.addValue("cn", name); } return new DN(rb.toRdn()); } public DN parseNISMailAlias(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); if (name == null) { int i = line.indexOf(':'); name = line.substring(0, i); line = line.substring(i+1).trim(); } rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); StringBuilder sb = new StringBuilder(); char[] chars = line.toCharArray(); boolean done = false; for (int i=0; i<chars.length && !done; i++) { char c = chars[i]; switch (c) { case ',': case '#': String value = sb.toString().trim(); if (value.startsWith("\"") && value.endsWith("\"")) { value = value.substring(1, value.length()-1); } if (value.length() > 0) attributes.addValue("rfc822mailMember", value); sb.delete(0, sb.length()); if (c == '#') { String comment = line.substring(i+1).trim(); if (comment.length() > 0) attributes.addValue("description", comment); done = true; } break; default: sb.append(c); break; } } if (sb.length() > 0) { String value = sb.toString().trim(); if (value.startsWith("\"") && value.endsWith("\"")) { value = value.substring(1, value.length()-1); } if (value.length() > 0) attributes.addValue("rfc822mailMember", value); } return new DN(rb.toRdn()); } public DN parseNISNetgroup(String name, String line, Attributes attributes) throws Exception { //log.warn("Parsing ["+name+"] ["+line+"]"); List<String> tokens = new ArrayList<String>(); StringBuilder sb = new StringBuilder(); int length = line.length(); char c; for (int i = 0; i < length; i++) { c = line.charAt(i); while (i < length-1 && Character.isWhitespace(c)) { // skip whitespaces i++; c = line.charAt(i); } if (i >= length) break; sb.append(c); // append token's first char if (c == '(') { // if nisNetgroupTriple while (i < length-1) { // find closing parentheses i++; c = line.charAt(i); sb.append(c); if (c == ')') break; } } else { // if memberNisNetgroup while (i < length-1) { // find next whitespace i++; c = line.charAt(i); if (Character.isWhitespace(c)) break; sb.append(c); } } tokens.add(sb.toString()); sb.setLength(0); } RDNBuilder rb = new RDNBuilder(); rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); while (!tokens.isEmpty()) { String token = tokens.remove(0); //log.warn(" - ["+token+"]"); if (token.startsWith("#")) break; if (token.startsWith("(") && token.endsWith(")")) { //token = token.substring(1, token.length()-1); attributes.addValue("nisNetgroupTriple", token); } else { attributes.addValue("memberNisNetgroup", token); } } return new DN(rb.toRdn()); } public DN parseIEEE802Device(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); attributes.setValue("macAddress", st.nextToken()); if (name == null) { name = st.nextToken(); } rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); while (st.hasMoreTokens()) { name = st.nextToken(); if (name.startsWith("#")) break; attributes.addValue("cn", name); } return new DN(rb.toRdn()); } public DN parseBootableDevice(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); if (name == null) { name = st.nextToken(); } rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); while (st.hasMoreTokens()) { String token = st.nextToken(); if (token.startsWith("#")) break; attributes.addValue("bootParameter", token); } return new DN(rb.toRdn()); } public DN parseIPNetwork(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); name = st.nextToken(); rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); attributes.setValue("ipNetworkNumber", st.nextToken()); while (st.hasMoreTokens()) { name = st.nextToken(); if (name.startsWith("#")) break; attributes.addValue("cn", name); } return new DN(rb.toRdn()); } public DN parseAutomountMap(String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); if (name == null) { name = st.nextToken(); line = line.substring(name.length()+1).trim(); } rb.set("automountKey", name); attributes.setValue("primaryKey.automountKey", name); attributes.setValue("automountKey", name); attributes.setValue("automountInformation", line); return new DN(rb.toRdn()); } public DN parseAutomount(String base, String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); if (name == null) { name = st.nextToken(); line = line.substring(name.length()+1).trim(); } rb.set("automountMapName", base); rb.set("automountKey", name); attributes.setValue("primaryKey.automountMapName", base); attributes.setValue("primaryKey.automountKey", name); attributes.setValue("automountMapName", base); attributes.setValue("automountKey", name); attributes.setValue("automountInformation", line); return new DN(rb.toRdn()); } public DN parseNISMap(String name, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); rb.set("nisMapName", name); attributes.setValue("primaryKey.nisMapName", name); attributes.setValue("nisMapName", name); return new DN(rb.toRdn()); } public DN parseNISObject(String mapName, String name, String line, Attributes attributes) throws Exception { RDNBuilder rb = new RDNBuilder(); StringTokenizer st = new StringTokenizer(line, "\t "); if (name == null) { name = st.nextToken(); line = line.substring(name.length()+1).trim(); } rb.set("cn", name); attributes.setValue("primaryKey.cn", name); attributes.setValue("cn", name); attributes.setValue("nisMapEntry", line); attributes.setValue("nisMapName", mapName); return new DN(rb.toRdn()); } }