| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 | // This file contains the password modify extended operation as specified in rfc 3062//// https://tools.ietf.org/html/rfc3062//package ldapimport (	"errors"	"fmt"	"gopkg.in/asn1-ber.v1")const (	passwordModifyOID = "1.3.6.1.4.1.4203.1.11.1")// PasswordModifyRequest implements the Password Modify Extended Operation as defined in https://www.ietf.org/rfc/rfc3062.txttype PasswordModifyRequest struct {	// UserIdentity is an optional string representation of the user associated with the request.	// This string may or may not be an LDAPDN [RFC2253].	// If no UserIdentity field is present, the request acts up upon the password of the user currently associated with the LDAP session	UserIdentity string	// OldPassword, if present, contains the user's current password	OldPassword string	// NewPassword, if present, contains the desired password for this user	NewPassword string}// PasswordModifyResult holds the server response to a PasswordModifyRequesttype PasswordModifyResult struct {	// GeneratedPassword holds a password generated by the server, if present	GeneratedPassword string}func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {	request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Password Modify Extended Operation")	request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, passwordModifyOID, "Extended Request Name: Password Modify OID"))	extendedRequestValue := ber.Encode(ber.ClassContext, ber.TypePrimitive, 1, nil, "Extended Request Value: Password Modify Request")	passwordModifyRequestValue := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Password Modify Request")	if r.UserIdentity != "" {		passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, r.UserIdentity, "User Identity"))	}	if r.OldPassword != "" {		passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 1, r.OldPassword, "Old Password"))	}	if r.NewPassword != "" {		passwordModifyRequestValue.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 2, r.NewPassword, "New Password"))	}	extendedRequestValue.AppendChild(passwordModifyRequestValue)	request.AppendChild(extendedRequestValue)	return request, nil}// NewPasswordModifyRequest creates a new PasswordModifyRequest//// According to the RFC 3602:// userIdentity is a string representing the user associated with the request.// This string may or may not be an LDAPDN (RFC 2253).// If userIdentity is empty then the operation will act on the user associated// with the session.//// oldPassword is the current user's password, it can be empty or it can be// needed depending on the session user access rights (usually an administrator// can change a user's password without knowing the current one) and the// password policy (see pwdSafeModify password policy's attribute)//// newPassword is the desired user's password. If empty the server can return// an error or generate a new password that will be available in the// PasswordModifyResult.GeneratedPassword//func NewPasswordModifyRequest(userIdentity string, oldPassword string, newPassword string) *PasswordModifyRequest {	return &PasswordModifyRequest{		UserIdentity: userIdentity,		OldPassword:  oldPassword,		NewPassword:  newPassword,	}}// PasswordModify performs the modification requestfunc (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) {	packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")	packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))	encodedPasswordModifyRequest, err := passwordModifyRequest.encode()	if err != nil {		return nil, err	}	packet.AppendChild(encodedPasswordModifyRequest)	l.Debug.PrintPacket(packet)	msgCtx, err := l.sendMessage(packet)	if err != nil {		return nil, err	}	defer l.finishMessage(msgCtx)	result := &PasswordModifyResult{}	l.Debug.Printf("%d: waiting for response", msgCtx.id)	packetResponse, ok := <-msgCtx.responses	if !ok {		return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed"))	}	packet, err = packetResponse.ReadPacket()	l.Debug.Printf("%d: got response %p", msgCtx.id, packet)	if err != nil {		return nil, err	}	if packet == nil {		return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))	}	if l.Debug {		if err := addLDAPDescriptions(packet); err != nil {			return nil, err		}		ber.PrintPacket(packet)	}	if packet.Children[1].Tag == ApplicationExtendedResponse {		resultCode, resultDescription := getLDAPResultCode(packet)		if resultCode != 0 {			return nil, NewError(resultCode, errors.New(resultDescription))		}	} else {		return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))	}	extendedResponse := packet.Children[1]	for _, child := range extendedResponse.Children {		if child.Tag == 11 {			passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes())			if len(passwordModifyReponseValue.Children) == 1 {				if passwordModifyReponseValue.Children[0].Tag == 0 {					result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes())				}			}		}	}	return result, nil}
 |