| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 | 
							- // Copyright 2011 The Go Authors. All rights reserved.
 
- // Use of this source code is governed by a BSD-style
 
- // license that can be found in the LICENSE file.
 
- package ldap
 
- import (
 
- 	"fmt"
 
- 	"strconv"
 
- 	"gopkg.in/asn1-ber.v1"
 
- )
 
- const (
 
- 	// ControlTypePaging - https://www.ietf.org/rfc/rfc2696.txt
 
- 	ControlTypePaging = "1.2.840.113556.1.4.319"
 
- 	// ControlTypeBeheraPasswordPolicy - https://tools.ietf.org/html/draft-behera-ldap-password-policy-10
 
- 	ControlTypeBeheraPasswordPolicy = "1.3.6.1.4.1.42.2.27.8.5.1"
 
- 	// ControlTypeVChuPasswordMustChange - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
 
- 	ControlTypeVChuPasswordMustChange = "2.16.840.1.113730.3.4.4"
 
- 	// ControlTypeVChuPasswordWarning - https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
 
- 	ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
 
- 	// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
 
- 	ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
 
- )
 
- // ControlTypeMap maps controls to text descriptions
 
- var ControlTypeMap = map[string]string{
 
- 	ControlTypePaging:               "Paging",
 
- 	ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
 
- 	ControlTypeManageDsaIT:          "Manage DSA IT",
 
- }
 
- // Control defines an interface controls provide to encode and describe themselves
 
- type Control interface {
 
- 	// GetControlType returns the OID
 
- 	GetControlType() string
 
- 	// Encode returns the ber packet representation
 
- 	Encode() *ber.Packet
 
- 	// String returns a human-readable description
 
- 	String() string
 
- }
 
- // ControlString implements the Control interface for simple controls
 
- type ControlString struct {
 
- 	ControlType  string
 
- 	Criticality  bool
 
- 	ControlValue string
 
- }
 
- // GetControlType returns the OID
 
- func (c *ControlString) GetControlType() string {
 
- 	return c.ControlType
 
- }
 
- // Encode returns the ber packet representation
 
- func (c *ControlString) Encode() *ber.Packet {
 
- 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
 
- 	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, c.ControlType, "Control Type ("+ControlTypeMap[c.ControlType]+")"))
 
- 	if c.Criticality {
 
- 		packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
 
- 	}
 
- 	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, string(c.ControlValue), "Control Value"))
 
- 	return packet
 
- }
 
- // String returns a human-readable description
 
- func (c *ControlString) String() string {
 
- 	return fmt.Sprintf("Control Type: %s (%q)  Criticality: %t  Control Value: %s", ControlTypeMap[c.ControlType], c.ControlType, c.Criticality, c.ControlValue)
 
- }
 
- // ControlPaging implements the paging control described in https://www.ietf.org/rfc/rfc2696.txt
 
- type ControlPaging struct {
 
- 	// PagingSize indicates the page size
 
- 	PagingSize uint32
 
- 	// Cookie is an opaque value returned by the server to track a paging cursor
 
- 	Cookie []byte
 
- }
 
- // GetControlType returns the OID
 
- func (c *ControlPaging) GetControlType() string {
 
- 	return ControlTypePaging
 
- }
 
- // Encode returns the ber packet representation
 
- func (c *ControlPaging) Encode() *ber.Packet {
 
- 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
 
- 	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypePaging, "Control Type ("+ControlTypeMap[ControlTypePaging]+")"))
 
- 	p2 := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (Paging)")
 
- 	seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Search Control Value")
 
- 	seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.PagingSize), "Paging Size"))
 
- 	cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Cookie")
 
- 	cookie.Value = c.Cookie
 
- 	cookie.Data.Write(c.Cookie)
 
- 	seq.AppendChild(cookie)
 
- 	p2.AppendChild(seq)
 
- 	packet.AppendChild(p2)
 
- 	return packet
 
- }
 
- // String returns a human-readable description
 
- func (c *ControlPaging) String() string {
 
- 	return fmt.Sprintf(
 
- 		"Control Type: %s (%q)  Criticality: %t  PagingSize: %d  Cookie: %q",
 
- 		ControlTypeMap[ControlTypePaging],
 
- 		ControlTypePaging,
 
- 		false,
 
- 		c.PagingSize,
 
- 		c.Cookie)
 
- }
 
- // SetCookie stores the given cookie in the paging control
 
- func (c *ControlPaging) SetCookie(cookie []byte) {
 
- 	c.Cookie = cookie
 
- }
 
- // ControlBeheraPasswordPolicy implements the control described in https://tools.ietf.org/html/draft-behera-ldap-password-policy-10
 
- type ControlBeheraPasswordPolicy struct {
 
- 	// Expire contains the number of seconds before a password will expire
 
- 	Expire int64
 
- 	// Grace indicates the remaining number of times a user will be allowed to authenticate with an expired password
 
- 	Grace int64
 
- 	// Error indicates the error code
 
- 	Error int8
 
- 	// ErrorString is a human readable error
 
- 	ErrorString string
 
- }
 
- // GetControlType returns the OID
 
- func (c *ControlBeheraPasswordPolicy) GetControlType() string {
 
- 	return ControlTypeBeheraPasswordPolicy
 
- }
 
- // Encode returns the ber packet representation
 
- func (c *ControlBeheraPasswordPolicy) Encode() *ber.Packet {
 
- 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
 
- 	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeBeheraPasswordPolicy, "Control Type ("+ControlTypeMap[ControlTypeBeheraPasswordPolicy]+")"))
 
- 	return packet
 
- }
 
- // String returns a human-readable description
 
- func (c *ControlBeheraPasswordPolicy) String() string {
 
- 	return fmt.Sprintf(
 
- 		"Control Type: %s (%q)  Criticality: %t  Expire: %d  Grace: %d  Error: %d, ErrorString: %s",
 
- 		ControlTypeMap[ControlTypeBeheraPasswordPolicy],
 
- 		ControlTypeBeheraPasswordPolicy,
 
- 		false,
 
- 		c.Expire,
 
- 		c.Grace,
 
- 		c.Error,
 
- 		c.ErrorString)
 
- }
 
- // ControlVChuPasswordMustChange implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
 
- type ControlVChuPasswordMustChange struct {
 
- 	// MustChange indicates if the password is required to be changed
 
- 	MustChange bool
 
- }
 
- // GetControlType returns the OID
 
- func (c *ControlVChuPasswordMustChange) GetControlType() string {
 
- 	return ControlTypeVChuPasswordMustChange
 
- }
 
- // Encode returns the ber packet representation
 
- func (c *ControlVChuPasswordMustChange) Encode() *ber.Packet {
 
- 	return nil
 
- }
 
- // String returns a human-readable description
 
- func (c *ControlVChuPasswordMustChange) String() string {
 
- 	return fmt.Sprintf(
 
- 		"Control Type: %s (%q)  Criticality: %t  MustChange: %v",
 
- 		ControlTypeMap[ControlTypeVChuPasswordMustChange],
 
- 		ControlTypeVChuPasswordMustChange,
 
- 		false,
 
- 		c.MustChange)
 
- }
 
- // ControlVChuPasswordWarning implements the control described in https://tools.ietf.org/html/draft-vchu-ldap-pwd-policy-00
 
- type ControlVChuPasswordWarning struct {
 
- 	// Expire indicates the time in seconds until the password expires
 
- 	Expire int64
 
- }
 
- // GetControlType returns the OID
 
- func (c *ControlVChuPasswordWarning) GetControlType() string {
 
- 	return ControlTypeVChuPasswordWarning
 
- }
 
- // Encode returns the ber packet representation
 
- func (c *ControlVChuPasswordWarning) Encode() *ber.Packet {
 
- 	return nil
 
- }
 
- // String returns a human-readable description
 
- func (c *ControlVChuPasswordWarning) String() string {
 
- 	return fmt.Sprintf(
 
- 		"Control Type: %s (%q)  Criticality: %t  Expire: %b",
 
- 		ControlTypeMap[ControlTypeVChuPasswordWarning],
 
- 		ControlTypeVChuPasswordWarning,
 
- 		false,
 
- 		c.Expire)
 
- }
 
- // ControlManageDsaIT implements the control described in https://tools.ietf.org/html/rfc3296
 
- type ControlManageDsaIT struct {
 
- 	// Criticality indicates if this control is required
 
- 	Criticality bool
 
- }
 
- // GetControlType returns the OID
 
- func (c *ControlManageDsaIT) GetControlType() string {
 
- 	return ControlTypeManageDsaIT
 
- }
 
- // Encode returns the ber packet representation
 
- func (c *ControlManageDsaIT) Encode() *ber.Packet {
 
- 	//FIXME
 
- 	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
 
- 	packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeManageDsaIT, "Control Type ("+ControlTypeMap[ControlTypeManageDsaIT]+")"))
 
- 	if c.Criticality {
 
- 		packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, c.Criticality, "Criticality"))
 
- 	}
 
- 	return packet
 
- }
 
- // String returns a human-readable description
 
- func (c *ControlManageDsaIT) String() string {
 
- 	return fmt.Sprintf(
 
- 		"Control Type: %s (%q)  Criticality: %t",
 
- 		ControlTypeMap[ControlTypeManageDsaIT],
 
- 		ControlTypeManageDsaIT,
 
- 		c.Criticality)
 
- }
 
- // NewControlManageDsaIT returns a ControlManageDsaIT control
 
- func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
 
- 	return &ControlManageDsaIT{Criticality: Criticality}
 
- }
 
- // FindControl returns the first control of the given type in the list, or nil
 
- func FindControl(controls []Control, controlType string) Control {
 
- 	for _, c := range controls {
 
- 		if c.GetControlType() == controlType {
 
- 			return c
 
- 		}
 
- 	}
 
- 	return nil
 
- }
 
- // DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
 
- func DecodeControl(packet *ber.Packet) Control {
 
- 	var (
 
- 		ControlType = ""
 
- 		Criticality = false
 
- 		value       *ber.Packet
 
- 	)
 
- 	switch len(packet.Children) {
 
- 	case 0:
 
- 		// at least one child is required for control type
 
- 		return nil
 
- 	case 1:
 
- 		// just type, no criticality or value
 
- 		packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
 
- 		ControlType = packet.Children[0].Value.(string)
 
- 	case 2:
 
- 		packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
 
- 		ControlType = packet.Children[0].Value.(string)
 
- 		// Children[1] could be criticality or value (both are optional)
 
- 		// duck-type on whether this is a boolean
 
- 		if _, ok := packet.Children[1].Value.(bool); ok {
 
- 			packet.Children[1].Description = "Criticality"
 
- 			Criticality = packet.Children[1].Value.(bool)
 
- 		} else {
 
- 			packet.Children[1].Description = "Control Value"
 
- 			value = packet.Children[1]
 
- 		}
 
- 	case 3:
 
- 		packet.Children[0].Description = "Control Type (" + ControlTypeMap[ControlType] + ")"
 
- 		ControlType = packet.Children[0].Value.(string)
 
- 		packet.Children[1].Description = "Criticality"
 
- 		Criticality = packet.Children[1].Value.(bool)
 
- 		packet.Children[2].Description = "Control Value"
 
- 		value = packet.Children[2]
 
- 	default:
 
- 		// more than 3 children is invalid
 
- 		return nil
 
- 	}
 
- 	switch ControlType {
 
- 	case ControlTypeManageDsaIT:
 
- 		return NewControlManageDsaIT(Criticality)
 
- 	case ControlTypePaging:
 
- 		value.Description += " (Paging)"
 
- 		c := new(ControlPaging)
 
- 		if value.Value != nil {
 
- 			valueChildren := ber.DecodePacket(value.Data.Bytes())
 
- 			value.Data.Truncate(0)
 
- 			value.Value = nil
 
- 			value.AppendChild(valueChildren)
 
- 		}
 
- 		value = value.Children[0]
 
- 		value.Description = "Search Control Value"
 
- 		value.Children[0].Description = "Paging Size"
 
- 		value.Children[1].Description = "Cookie"
 
- 		c.PagingSize = uint32(value.Children[0].Value.(int64))
 
- 		c.Cookie = value.Children[1].Data.Bytes()
 
- 		value.Children[1].Value = c.Cookie
 
- 		return c
 
- 	case ControlTypeBeheraPasswordPolicy:
 
- 		value.Description += " (Password Policy - Behera)"
 
- 		c := NewControlBeheraPasswordPolicy()
 
- 		if value.Value != nil {
 
- 			valueChildren := ber.DecodePacket(value.Data.Bytes())
 
- 			value.Data.Truncate(0)
 
- 			value.Value = nil
 
- 			value.AppendChild(valueChildren)
 
- 		}
 
- 		sequence := value.Children[0]
 
- 		for _, child := range sequence.Children {
 
- 			if child.Tag == 0 {
 
- 				//Warning
 
- 				child := child.Children[0]
 
- 				packet := ber.DecodePacket(child.Data.Bytes())
 
- 				val, ok := packet.Value.(int64)
 
- 				if ok {
 
- 					if child.Tag == 0 {
 
- 						//timeBeforeExpiration
 
- 						c.Expire = val
 
- 						child.Value = c.Expire
 
- 					} else if child.Tag == 1 {
 
- 						//graceAuthNsRemaining
 
- 						c.Grace = val
 
- 						child.Value = c.Grace
 
- 					}
 
- 				}
 
- 			} else if child.Tag == 1 {
 
- 				// Error
 
- 				packet := ber.DecodePacket(child.Data.Bytes())
 
- 				val, ok := packet.Value.(int8)
 
- 				if !ok {
 
- 					// what to do?
 
- 					val = -1
 
- 				}
 
- 				c.Error = val
 
- 				child.Value = c.Error
 
- 				c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
 
- 			}
 
- 		}
 
- 		return c
 
- 	case ControlTypeVChuPasswordMustChange:
 
- 		c := &ControlVChuPasswordMustChange{MustChange: true}
 
- 		return c
 
- 	case ControlTypeVChuPasswordWarning:
 
- 		c := &ControlVChuPasswordWarning{Expire: -1}
 
- 		expireStr := ber.DecodeString(value.Data.Bytes())
 
- 		expire, err := strconv.ParseInt(expireStr, 10, 64)
 
- 		if err != nil {
 
- 			return nil
 
- 		}
 
- 		c.Expire = expire
 
- 		value.Value = c.Expire
 
- 		return c
 
- 	default:
 
- 		c := new(ControlString)
 
- 		c.ControlType = ControlType
 
- 		c.Criticality = Criticality
 
- 		if value != nil {
 
- 			c.ControlValue = value.Value.(string)
 
- 		}
 
- 		return c
 
- 	}
 
- }
 
- // NewControlString returns a generic control
 
- func NewControlString(controlType string, criticality bool, controlValue string) *ControlString {
 
- 	return &ControlString{
 
- 		ControlType:  controlType,
 
- 		Criticality:  criticality,
 
- 		ControlValue: controlValue,
 
- 	}
 
- }
 
- // NewControlPaging returns a paging control
 
- func NewControlPaging(pagingSize uint32) *ControlPaging {
 
- 	return &ControlPaging{PagingSize: pagingSize}
 
- }
 
- // NewControlBeheraPasswordPolicy returns a ControlBeheraPasswordPolicy
 
- func NewControlBeheraPasswordPolicy() *ControlBeheraPasswordPolicy {
 
- 	return &ControlBeheraPasswordPolicy{
 
- 		Expire: -1,
 
- 		Grace:  -1,
 
- 		Error:  -1,
 
- 	}
 
- }
 
- func encodeControls(controls []Control) *ber.Packet {
 
- 	packet := ber.Encode(ber.ClassContext, ber.TypeConstructed, 0, nil, "Controls")
 
- 	for _, control := range controls {
 
- 		packet.AppendChild(control.Encode())
 
- 	}
 
- 	return packet
 
- }
 
 
  |