mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-27 03:20:22 +08:00
543 lines
21 KiB
Plaintext
543 lines
21 KiB
Plaintext
# $OpenLDAP$
|
|
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
|
|
##
|
|
## Copyright 2004-2005 The OpenLDAP Foundation.
|
|
## All rights reserved.
|
|
##
|
|
## Redistribution and use in source and binary forms, with or without
|
|
## modification, are permitted only as authorized by the OpenLDAP
|
|
## Public License.
|
|
##
|
|
## A copy of this license is available in the file LICENSE in the
|
|
## top-level directory of the distribution or, alternatively, at
|
|
## <http://www.OpenLDAP.org/license.html>.
|
|
#
|
|
## Portions Copyright (C) The Internet Society (2004).
|
|
## Please see full copyright statement below.
|
|
|
|
# Definitions from Draft behera-ldap-password-policy-07 (a work in progress)
|
|
# Password Policy for LDAP Directories
|
|
# With extensions from Hewlett-Packard:
|
|
# pwdCheckModule etc.
|
|
|
|
# Contents of this file are subject to change (including deletion)
|
|
# without notice.
|
|
#
|
|
# Not recommended for production use!
|
|
# Use with extreme caution!
|
|
|
|
# Internet-Draft P. Behera
|
|
# draft behera-ldap-password-policy-07.txt L. Poitou
|
|
# Intended Category: Proposed Standard Sun Microsystems
|
|
# Expires: August 2004 J. Sermersheim
|
|
# Novell
|
|
#
|
|
# February 2004
|
|
#
|
|
#
|
|
# Password Policy for LDAP Directories
|
|
#
|
|
#
|
|
# Status of this Memo
|
|
#
|
|
# This document is an Internet-Draft and is in full conformance with
|
|
# all provisions of Section 10 of RFC 2026.
|
|
#
|
|
# Internet-Drafts are working documents of the Internet Engineering
|
|
# Task Force (IETF), its areas, and its working groups. Note that
|
|
# other groups may also distribute working documents as Internet-
|
|
# Drafts.
|
|
#
|
|
# Internet-Drafts are draft documents valid for a maximum of six
|
|
# months and may be updated, replaced, or obsoleted by other documents
|
|
# at any time. It is inappropriate to use Internet- Drafts as
|
|
# reference material or to cite them other than as "work in progress."
|
|
#
|
|
# The list of current Internet-Drafts can be accessed at
|
|
# http://www.ietf.org/ietf/1id-abstracts.txt
|
|
#
|
|
# The list of Internet-Draft Shadow Directories can be accessed at
|
|
# http://www.ietf.org/shadow.html.
|
|
#
|
|
# Technical discussions of this draft are held on the LDAPEXT Working
|
|
# Group mailing list at ietf-ldapext@netscape.com. Editorial comments
|
|
# may be sent to the authors listed in Section 13.
|
|
#
|
|
# Copyright (C) The Internet Society (2004). All rights Reserved.
|
|
#
|
|
# Please see the Copyright Section near the end of this document for
|
|
# more information.
|
|
#
|
|
#
|
|
# 1. Abstract
|
|
#
|
|
# Password policy as described in this document is a set of rules that
|
|
# controls how passwords are used and administered in LDAP
|
|
# directories. In order to improve the security of LDAP directories
|
|
# and make it difficult for password cracking programs to break into
|
|
# directories, it is desirable to enforce a set of rules on password
|
|
# usage. These rules are made to ensure that users change their
|
|
# passwords periodically, passwords meet construction requirements,
|
|
# the re-use of old password is restricted, and users are locked out
|
|
# after a certain number of failed attempts.
|
|
#
|
|
# [trimmed]
|
|
#
|
|
#
|
|
# 4.2. Attribute Types used in the pwdPolicy ObjectClass
|
|
#
|
|
# Following are the attribute types used by the pwdPolicy object
|
|
# class.
|
|
#
|
|
# 4.2.1. pwdAttribute
|
|
#
|
|
# This holds the name of the attribute to which the password policy is
|
|
# applied. For example, the password policy may be applied to the
|
|
# userPassword attribute.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.1
|
|
NAME 'pwdAttribute'
|
|
EQUALITY objectIdentifierMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
|
|
|
|
# 4.2.2. pwdMinAge
|
|
#
|
|
# This attribute holds the number of seconds that must elapse between
|
|
# modifications to the password. If this attribute is not present, 0
|
|
# seconds is assumed.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.2
|
|
NAME 'pwdMinAge'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.3. pwdMaxAge
|
|
#
|
|
# This attribute holds the number of seconds after which a modified
|
|
# password will expire.
|
|
#
|
|
# If this attribute is not present, or if the value is 0 the password
|
|
# does not expire. If not 0, the value must be greater than or equal
|
|
# to the value of the pwdMinAge.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.3
|
|
NAME 'pwdMaxAge'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.4. pwdInHistory
|
|
#
|
|
# This attribute specifies the maximum number of used passwords stored
|
|
# in the pwdHistory attribute.
|
|
#
|
|
# If this attribute is not present, or if the value is 0, used
|
|
# passwords are not stored in the pwdHistory attribute and thus may be
|
|
# reused.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.4
|
|
NAME 'pwdInHistory'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.5. pwdCheckQuality
|
|
#
|
|
# This attribute indicates how the password quality will be verified
|
|
# while being modified or added. If this attribute is not present, or
|
|
# if the value is '0', quality checking will not be enforced. A value
|
|
# of '1' indicates that the server will check the quality, and if the
|
|
# server is unable to check it (due to a hashed password or other
|
|
# reasons) it will be accepted. A value of '2' indicates that the
|
|
# server will check the quality, and if the server is unable to verify
|
|
# it, it will return an error refusing the password.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.5
|
|
NAME 'pwdCheckQuality'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.6. pwdMinLength
|
|
#
|
|
# When quality checking is enabled, this attribute holds the minimum
|
|
# number of characters that must be used in a password. If this
|
|
# attribute is not present, no minimum password length will be
|
|
# enforced. If the server is unable to check the length (due to a
|
|
# hashed password or otherwise), the server will, depending on the
|
|
# value of the pwdCheckQuality attribute, either accept the password
|
|
# without checking it ('0' or '1') or refuse it ('2').
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.6
|
|
NAME 'pwdMinLength'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.7. pwdExpireWarning
|
|
#
|
|
# This attribute specifies the maximum number of seconds before a
|
|
# password is due to expire that expiration warning messages will be
|
|
# returned to an authenticating user. If this attribute is not
|
|
# present, or if the value is 0 no warnings will be sent. If not 0,
|
|
# the value must be smaller than the value of the pwdMaxAge attribute.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.7
|
|
NAME 'pwdExpireWarning'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.8. pwdGraceLoginLimit
|
|
#
|
|
# This attribute specifies the number of times an expired password can
|
|
# be used to authenticate. If this attribute is not present or if the
|
|
# value is 0, authentication will fail.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.8
|
|
NAME 'pwdGraceLoginLimit'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.9. pwdLockout
|
|
#
|
|
# This attribute indicates, when its value is "TRUE", that the
|
|
# password may not be used to authenticate after a specified number of
|
|
# consecutive failed bind attempts. The maximum number of consecutive
|
|
# failed bind attempts is specified in pwdMaxFailure.
|
|
#
|
|
# If this attribute is not present, or if the value is "FALSE", the
|
|
# password may be used to authenticate when the number of failed bind
|
|
# attempts has been reached.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.9
|
|
NAME 'pwdLockout'
|
|
EQUALITY booleanMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.10. pwdLockoutDuration
|
|
#
|
|
# This attribute holds the number of seconds that the password cannot
|
|
# be used to authenticate due to too many failed bind attempts. If
|
|
# this attribute is not present, or if the value is 0 the password
|
|
# cannot be used to authenticate until reset by an administrator.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.10
|
|
NAME 'pwdLockoutDuration'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.11. pwdMaxFailure
|
|
#
|
|
# This attribute specifies the number of consecutive failed bind
|
|
# attempts after which the password may not be used to authenticate.
|
|
# If this attribute is not present, or if the value is 0, this policy
|
|
# is not checked, and the value of pwdLockout will be ignored.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.11
|
|
NAME 'pwdMaxFailure'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.12. pwdFailureCountInterval
|
|
#
|
|
# This attribute holds the number of seconds after which the password
|
|
# failures are purged from the failure counter, even though no
|
|
# successful authentication occurred.
|
|
#
|
|
# If this attribute is not present, or if its value is 0, the failure
|
|
# counter is only reset by a successful authentication.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.12
|
|
NAME 'pwdFailureCountInterval'
|
|
EQUALITY integerMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.13. pwdMustChange
|
|
#
|
|
# This attribute specifies with a value of "TRUE" that users must
|
|
# change their passwords when they first bind to the directory after a
|
|
# password is set or reset by the administrator. If this attribute is
|
|
# not present, or if the value is "FALSE", users are not required to
|
|
# change their password upon binding after the administrator sets or
|
|
# resets the password.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.13
|
|
NAME 'pwdMustChange'
|
|
EQUALITY booleanMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.14. pwdAllowUserChange
|
|
#
|
|
# This attribute indicates whether users can change their own
|
|
# passwords, although the change operation is still subject to access
|
|
# control. If this attribute is not present, a value of "TRUE" is
|
|
# assumed.
|
|
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.14
|
|
NAME 'pwdAllowUserChange'
|
|
EQUALITY booleanMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
|
SINGLE-VALUE )
|
|
|
|
# 4.2.15. pwdSafeModify
|
|
#
|
|
# This attribute specifies whether or not the existing password must
|
|
# be sent when changing a password. If this attribute is not present,
|
|
# a "FALSE" value is assumed.
|
|
#
|
|
attributetype ( 1.3.6.1.4.1.42.2.27.8.1.15
|
|
NAME 'pwdSafeModify'
|
|
EQUALITY booleanMatch
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
|
SINGLE-VALUE )
|
|
|
|
# HP extensions
|
|
#
|
|
# pwdCheckModule
|
|
#
|
|
# This attribute names a user-defined loadable module that provides
|
|
# a check_password() function. If pwdCheckQuality is set to '1' or '2'
|
|
# this function will be called after all of the internal password
|
|
# quality checks have been passed. The function has this prototype:
|
|
#
|
|
# int check_password( char *password, char **errormessage, void *arg )
|
|
#
|
|
# The function should return LDAP_SUCCESS for a valid password.
|
|
|
|
attributetype ( 1.3.6.1.4.1.4754.1.99.1
|
|
NAME 'pwdCheckModule'
|
|
EQUALITY caseExactIA5Match
|
|
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
|
|
DESC 'Loadable module that instantiates "check_password() function'
|
|
SINGLE-VALUE )
|
|
|
|
# 4.1. The pwdPolicy Object Class
|
|
#
|
|
# This object class contains the attributes defining a password policy
|
|
# in effect for a set of users. Section 8 describes the administration
|
|
# of this object, and the relationship between it and particular
|
|
# objects.
|
|
|
|
objectclass ( 1.3.6.1.4.1.42.2.27.8.2.1
|
|
NAME 'pwdPolicy'
|
|
SUP top
|
|
AUXILIARY
|
|
MUST ( pwdAttribute )
|
|
MAY ( pwdMinAge $ pwdMaxAge $ pwdInHistory $ pwdCheckQuality $
|
|
pwdMinLength $ pwdExpireWarning $ pwdGraceLoginLimit $ pwdLockout
|
|
$ pwdLockoutDuration $ pwdMaxFailure $ pwdFailureCountInterval $
|
|
pwdMustChange $ pwdAllowUserChange $ pwdSafeModify ) )
|
|
|
|
objectclass ( 1.3.6.1.4.1.4754.2.99.1
|
|
NAME 'pwdPolicyChecker'
|
|
SUP top
|
|
AUXILIARY
|
|
MAY ( pwdCheckModule ) )
|
|
|
|
# 4.3. Attribute Types for Password Policy State Information
|
|
#
|
|
# Password policy state information must be maintained for each user.
|
|
# The information is located in each user entry as a set of
|
|
# operational attributes. These operational attributes are:
|
|
# pwdChangedTime, pwdAccountLockedTime, pwdExpirationWarned,
|
|
# pwdFailureTime, pwdHistory, pwdGraceUseTime, pwdReset,
|
|
# pwdPolicySubEntry.
|
|
#
|
|
# 4.3.1. Password Policy State Attribute Option
|
|
#
|
|
# Since the password policy could apply to several attributes used to
|
|
# store passwords, each of the above operational attributes must have
|
|
# an option to specify which pwdAttribute is applies to.
|
|
# The password policy option is defined as the following:
|
|
# pwd-<passwordAttribute>
|
|
#
|
|
# where passwordAttribute a string following the OID syntax
|
|
# (1.3.6.1.4.1.1466.115.121.1.38). The attribute type descriptor
|
|
# (short name) MUST be used.
|
|
#
|
|
# For example, if the pwdPolicy object has for pwdAttribute
|
|
# "userPassword" then the pwdChangedTime operational attribute, in a
|
|
# user entry, will be:
|
|
# pwdChangedTime;pwd-userPassword: 20000103121520Z
|
|
#
|
|
# This attribute option follows sub-typing semantics. If a client
|
|
# requests a password policy state attribute to be returned in a
|
|
# search operation, and does not specify an option, all subtypes of
|
|
# that policy state attribute are returned.
|
|
#
|
|
# 4.3.2. pwdChangedTime
|
|
#
|
|
# This attribute specifies the last time the entry's password was
|
|
# changed. This is used by the password expiration policy. If this
|
|
# attribute does not exist, the password will never expire.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.16
|
|
# NAME 'pwdChangedTime'
|
|
# DESC 'The time the password was last changed'
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
|
|
# EQUALITY generalizedTimeMatch
|
|
# ORDERING generalizedTimeOrderingMatch
|
|
# SINGLE-VALUE
|
|
# USAGE directoryOperation)
|
|
#
|
|
# 4.3.3. pwdAccountLockedTime
|
|
#
|
|
# This attribute holds the time that the user's account was locked. A
|
|
# locked account means that the password may no longer be used to
|
|
# authenticate. A 0 value means that the account has been locked
|
|
# permanently, and that only an administrator can unlock the account.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.17
|
|
# NAME 'pwdAccountLockedTime'
|
|
# DESC 'The time an user account was locked'
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
|
|
# EQUALITY generalizedTimeMatch
|
|
# ORDERING generalizedTimeOrderingMatch
|
|
# SINGLE-VALUE
|
|
# USAGE directoryOperation)
|
|
#
|
|
# 4.3.4. pwdExpirationWarned
|
|
#
|
|
# This attribute contains the time when the password expiration
|
|
# warning was first sent to the client. The password will expire in
|
|
# the pwdExpireWarning time.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.18
|
|
# NAME 'pwdExpirationWarned'
|
|
# DESC 'The time the user was first warned about the coming
|
|
# expiration of the password'
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
|
|
# EQUALITY generalizedTimeMatch
|
|
# ORDERING generalizedTimeOrderingMatch
|
|
# SINGLE-VALUE
|
|
# USAGE directoryOperation )
|
|
#
|
|
# 4.3.5. pwdFailureTime
|
|
#
|
|
# This attribute holds the timestamps of the consecutive
|
|
# authentication failures.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.19
|
|
# NAME 'pwdFailureTime'
|
|
# DESC 'The timestamps of the last consecutive authentication
|
|
# failures'
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
|
|
# EQUALITY generalizedTimeMatch
|
|
# ORDERING generalizedTimeOrderingMatch
|
|
# USAGE directoryOperation )
|
|
#
|
|
# 4.3.6. pwdHistory
|
|
#
|
|
# This attribute holds a history of previously used passwords.
|
|
#
|
|
# Values of this attribute are transmitted in string format as given
|
|
# by the following ABNF:
|
|
#
|
|
# pwdHistory = time "#" syntaxOID "#" length "#" data
|
|
#
|
|
# time = <generalizedTimeString as specified in 6.14 of
|
|
# [RFC2252]>
|
|
#
|
|
# syntaxOID = numericoid ; the string representation of the
|
|
# ; dotted-decimal OID that defines the
|
|
# ; syntax used to store the password.
|
|
# ; numericoid is described in 4.1 of
|
|
# ; [RFC2252].
|
|
#
|
|
# length = numericstring ; the number of octets in data.
|
|
# ; numericstring is described in 4.1 of
|
|
# ; [RFC2252].
|
|
#
|
|
# data = <octets representing the password in the format
|
|
# specified by syntaxOID>.
|
|
#
|
|
# This format allows the server to store, and transmit a history of
|
|
# passwords that have been used. In order for equality matching to
|
|
# function properly, the time field needs to adhere to a consistent
|
|
# format. For this purpose, the time field MUST be in GMT format.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.20
|
|
# NAME 'pwdHistory'
|
|
# DESC 'The history of user s passwords'
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
|
|
# EQUALITY octetStringMatch
|
|
# USAGE directoryOperation)
|
|
#
|
|
# 4.3.7. pwdGraceUseTime
|
|
#
|
|
# This attribute holds the timestamps of grace login once a password
|
|
# has expired.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.21
|
|
# NAME 'pwdGraceUseTime'
|
|
# DESC 'The timestamps of the grace login once the password has
|
|
# expired'
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.24
|
|
# EQUALITY generalizedTimeMatch
|
|
#
|
|
# USAGE directoryOperation)
|
|
#
|
|
# 4.3.8. pwdReset
|
|
#
|
|
# This attribute holds a flag to indicate (when TRUE) that the
|
|
# password has been reset and therefore must be changed by the user on
|
|
# first authentication.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.22
|
|
# NAME 'pwdReset'
|
|
# DESC 'The indication that the password has been reset'
|
|
# EQUALITY booleanMatch
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
|
|
# SINGLE-VALUE
|
|
# USAGE directoryOperation)
|
|
#
|
|
# 4.3.9. pwdPolicySubentry
|
|
#
|
|
# This attribute points to the pwdPolicy subentry in effect for this
|
|
# object.
|
|
#
|
|
# ( 1.3.6.1.4.1.42.2.27.8.1.23
|
|
# NAME 'pwdPolicySubentry'
|
|
# DESC 'The pwdPolicy subentry in effect for this object'
|
|
# EQUALITY distinguishedNameMatch
|
|
# SYNTAX 1.3.6.1.4.1.1466.115.121.1.12
|
|
# SINGLE-VALUE
|
|
# USAGE directoryOperation)
|
|
#
|
|
# 14. Copyright Notice
|
|
#
|
|
# Copyright (C) The Internet Society (2004). All Rights
|
|
# Reserved.
|
|
#
|
|
# This document and translations of it may be copied and furnished to
|
|
# others, and derivative works that comment on or otherwise explain it
|
|
# or assist in its implementation may be prepared, copied, published
|
|
# and distributed, in whole or in part, without restriction of any
|
|
# kind, provided that the above copyright notice and this paragraph
|
|
# are included on all such copies and derivative works. However, this
|
|
# document itself may not be modified in any way, such as by removing
|
|
# the copyright notice or references to the Internet Society or other
|
|
# Internet organizations, except as needed for the purpose of
|
|
# developing Internet standards in which case the procedures for
|
|
# copyrights defined in the Internet Standards process must be
|
|
# followed, or as required to translate it into languages other than
|
|
# English.
|
|
#
|
|
# The limited permissions granted above are perpetual and will not be
|
|
# revoked by the Internet Society or its successors or assigns.
|
|
#
|
|
# This document and the information contained herein is provided on an
|
|
# "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
|
|
# TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
# BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
|
|
# HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
|
|
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE."
|