001 /* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at 010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE 011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE. 012 * See the License for the specific language governing permissions 013 * and limitations under the License. 014 * 015 * When distributing Covered Code, include this CDDL HEADER in each 016 * file and include the License file at 017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, 018 * add the following below this CDDL HEADER, with the fields enclosed 019 * by brackets "[]" replaced with your own identifying information: 020 * Portions Copyright [yyyy] [name of copyright owner] 021 * 022 * CDDL HEADER END 023 * 024 * 025 * Copyright 2008 Sun Microsystems, Inc. 026 */ 027 package org.opends.server.tasks; 028 import org.opends.messages.Message; 029 030 031 032 import java.util.List; 033 034 import org.opends.server.admin.std.server.ConnectionHandlerCfg; 035 import org.opends.server.backends.task.Task; 036 import org.opends.server.backends.task.TaskState; 037 import org.opends.server.api.ClientConnection; 038 import org.opends.server.api.ConnectionHandler; 039 import org.opends.server.core.DirectoryServer; 040 import org.opends.server.types.Attribute; 041 import org.opends.server.types.AttributeType; 042 import org.opends.server.types.AttributeValue; 043 import org.opends.server.types.DirectoryException; 044 import org.opends.server.types.DisconnectReason; 045 import org.opends.server.types.Entry; 046 import org.opends.server.types.Operation; 047 import org.opends.server.types.Privilege; 048 import org.opends.server.types.ResultCode; 049 050 import static org.opends.messages.TaskMessages.*; 051 import static org.opends.server.util.ServerConstants.*; 052 import static org.opends.server.util.StaticUtils.*; 053 054 055 056 /** 057 * This class provides an implementation of a Directory Server task that can be 058 * used to terminate a client connection. 059 */ 060 public class DisconnectClientTask 061 extends Task 062 { 063 // Indicates whether to send a notification message to the client. 064 private boolean notifyClient; 065 066 // The connection ID for the client connection to terminate. 067 private long connectionID; 068 069 // The disconnect message to send to the client. 070 private Message disconnectMessage; 071 072 /** 073 * {@inheritDoc} 074 */ 075 public Message getDisplayName() { 076 return INFO_TASK_DISCONNECT_CLIENT_NAME.get(); 077 } 078 079 /** 080 * {@inheritDoc} 081 */ 082 @Override 083 public void initializeTask() 084 throws DirectoryException 085 { 086 // If the client connection is available, then make sure the client has the 087 // DISCONNECT_CLIENT privilege. 088 Operation operation = getOperation(); 089 if (operation != null) 090 { 091 ClientConnection conn = operation.getClientConnection(); 092 if (! conn.hasPrivilege(Privilege.DISCONNECT_CLIENT, operation)) 093 { 094 Message message = ERR_TASK_DISCONNECT_NO_PRIVILEGE.get(); 095 throw new DirectoryException(ResultCode.INSUFFICIENT_ACCESS_RIGHTS, 096 message); 097 } 098 } 099 100 101 // Get the connection ID for the client connection. 102 Entry taskEntry = getTaskEntry(); 103 connectionID = -1L; 104 AttributeType attrType = 105 DirectoryServer.getAttributeType(ATTR_TASK_DISCONNECT_CONN_ID, true); 106 List<Attribute> attrList = taskEntry.getAttribute(attrType); 107 if (attrList != null) 108 { 109 connIDLoop: 110 for (Attribute a : attrList) 111 { 112 for (AttributeValue v : a.getValues()) 113 { 114 try 115 { 116 connectionID = Long.parseLong(v.getStringValue()); 117 break connIDLoop; 118 } 119 catch (Exception e) 120 { 121 Message message = 122 ERR_TASK_DISCONNECT_INVALID_CONN_ID.get(v.getStringValue()); 123 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 124 message, e); 125 } 126 } 127 } 128 } 129 130 if (connectionID < 0) 131 { 132 Message message = 133 ERR_TASK_DISCONNECT_NO_CONN_ID.get(ATTR_TASK_DISCONNECT_CONN_ID); 134 throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, 135 message); 136 } 137 138 139 // Determine whether to notify the client. 140 notifyClient = false; 141 attrType = 142 DirectoryServer.getAttributeType(ATTR_TASK_DISCONNECT_NOTIFY_CLIENT, 143 true); 144 attrList = taskEntry.getAttribute(attrType); 145 if (attrList != null) 146 { 147 notifyClientLoop: 148 for (Attribute a : attrList) 149 { 150 for (AttributeValue v : a.getValues()) 151 { 152 String stringValue = toLowerCase(v.getStringValue()); 153 if (stringValue.equals("true")) 154 { 155 notifyClient = true; 156 break notifyClientLoop; 157 } 158 else if (stringValue.equals("false")) 159 { 160 break notifyClientLoop; 161 } 162 else 163 { 164 Message message = 165 ERR_TASK_DISCONNECT_INVALID_NOTIFY_CLIENT.get(stringValue); 166 throw new DirectoryException(ResultCode.INVALID_ATTRIBUTE_SYNTAX, 167 message); 168 } 169 } 170 } 171 } 172 173 174 // Get the disconnect message. 175 disconnectMessage = INFO_TASK_DISCONNECT_GENERIC_MESSAGE.get(); 176 attrType = DirectoryServer.getAttributeType(ATTR_TASK_DISCONNECT_MESSAGE, 177 true); 178 attrList = taskEntry.getAttribute(attrType); 179 if (attrList != null) 180 { 181 disconnectMessageLoop: 182 for (Attribute a : attrList) 183 { 184 for (AttributeValue v : a.getValues()) 185 { 186 disconnectMessage = Message.raw(v.getStringValue()); 187 break disconnectMessageLoop; 188 } 189 } 190 } 191 } 192 193 194 195 /** 196 * {@inheritDoc} 197 */ 198 protected TaskState runTask() 199 { 200 // Get the specified client connection. 201 ClientConnection clientConnection = null; 202 for (ConnectionHandler handler : DirectoryServer.getConnectionHandlers()) 203 { 204 ConnectionHandler<? extends ConnectionHandlerCfg> connHandler = 205 (ConnectionHandler<? extends ConnectionHandlerCfg>) handler; 206 for (ClientConnection c : connHandler.getClientConnections()) 207 { 208 if (c.getConnectionID() == connectionID) 209 { 210 clientConnection = c; 211 break; 212 } 213 } 214 } 215 216 217 // If there is no such client connection, then return an error. Otherwise, 218 // terminate it. 219 if (clientConnection == null) 220 { 221 Message message = 222 ERR_TASK_DISCONNECT_NO_SUCH_CONNECTION.get( 223 String.valueOf(connectionID)); 224 logError(message); 225 226 return TaskState.COMPLETED_WITH_ERRORS; 227 } 228 else 229 { 230 clientConnection.disconnect(DisconnectReason.ADMIN_DISCONNECT, 231 notifyClient, disconnectMessage); 232 return TaskState.COMPLETED_SUCCESSFULLY; 233 } 234 } 235 } 236