~ubuntu-branches/ubuntu/trusty/golang-openldap/trusty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package openldap

/* #include <stdlib.h>
#include <stdio.h>
#define LDAP_DEPRECATED 1
#include <ldap.h>

// goc can not use union on structs ; so create a new type with same attributes and size
// fixme : support binary mods (mod_bvalues)
typedef struct ldapmod_str {
	int		       mod_op;
	char		   *mod_type;
	char           **mod_vals;
} LDAPModStr;


int _ldap_add(LDAP *ld, char* dn, LDAPModStr **attrs){

	//API: int ldap_add_ext_s(LDAP *ld, char *dn, LDAPMod **attrs, LDAPControl *sctrls, LDAPControl *cctrls );
	// nota : cast (LDAPMod **) is possible because structs have same size
	return ldap_add_ext_s(ld, dn, (LDAPMod **)attrs, NULL, NULL);
}

int _ldap_modify(LDAP *ld, char* dn, LDAPModStr **mods ){
 
	// nota : cast (LDAPMod **) is possible because structs have same size
	return ldap_modify_ext_s( ld, dn, (LDAPMod **)mods, NULL, NULL);
}

int _ldap_rename (LDAP *ld, char *dn, char *newrdn, char *newSuperior, int deleteoldrdn){
	//API: int ldap_rename_s( ld, dn, newrdn, newparent, deleteoldrdn, sctrls[], cctrls[])

	return ldap_rename_s(ld, dn, newrdn, newSuperior, deleteoldrdn, NULL, NULL);
}

void _ldap_mods_free (LDAPModStr **mods, int freemods){
	//API: void ldap_mods_free(LDAPMod **mods, int freemods);
	return ldap_mods_free((LDAPMod **)mods, freemods);
}


*/
// #cgo CFLAGS: -DLDAP_DEPRECATED=1
// #cgo linux CFLAGS: -DLINUX=1
// #cgo LDFLAGS: -lldap -llber
import "C"

import (
	"errors"
	"unsafe"
	"fmt"
)


func (self *Ldap) doModify(dn string, attrs map[string][]string, changeType int, full_add bool) (int){

	_dn := C.CString(dn)
	defer C.free(unsafe.Pointer(_dn))
	
	mods := make([]*C.LDAPModStr, len(attrs)+1)
	// mods[len] = nil by default

	count:= 0
	for key, values := range attrs {

		// transform []string to C.char** null terminated array (attributes argument)
		_values := make([]*C.char, len(values)+1) // default set to nil (NULL in C)

		for i, value := range values {
			_values[i] = C.CString(value)
			defer C.free(unsafe.Pointer(_values[i]))
		}

		var mod C.LDAPModStr

		mod.mod_op = C.int(changeType)
		mod.mod_type = C.CString(key)
		mod.mod_vals = &_values[0]
		
		defer C.free(unsafe.Pointer(mod.mod_type))

		mods[count] = &mod

		count++
	}

	var rv int

	if full_add {
		// API: int ldap_add (LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods )
		rv = int(C._ldap_add(self.conn, _dn, &mods[0]))
	} else{
		// API: int ldap_modify (LDAP *ld, LDAP_CONST char *dn, LDAPMod **mods )
		rv = int(C._ldap_modify(self.conn, _dn, &mods[0]))
	}

	// FIXME: need to call ldap_mods_free(&mods) some where.
	// C._ldap_mods_free(&mods[0], 1) // not OK.
	return rv
}

func (self *Ldap) Modify(dn string, attrs map[string][]string) (error){

	changeType := C.LDAP_MOD_REPLACE
	full_add := false
	rv := self.doModify(dn, attrs, changeType, full_add)

	if rv != LDAP_OPT_SUCCESS {
		return errors.New(fmt.Sprintf("LDAP::Modify() error :  %d (%s)", rv, ErrorToString(rv)))
	}
	return nil
}

func (self *Ldap) ModifyDel(dn string, attrs map[string][]string) (error){

	changeType := C.LDAP_MOD_DELETE
	full_add := false
	rv := self.doModify(dn, attrs, changeType, full_add)

	if rv != LDAP_OPT_SUCCESS {
		return errors.New(fmt.Sprintf("LDAP::ModifyDel() error :  %d (%s)", rv, ErrorToString(rv)))
	}
	return nil
}

func (self *Ldap) ModifyAdd(dn string, attrs map[string][]string) (error){

	changeType := C.LDAP_MOD_ADD
	full_add := false
	rv := self.doModify(dn, attrs, changeType, full_add)
	if rv != LDAP_OPT_SUCCESS {
		return errors.New(fmt.Sprintf("LDAP::ModifyAdd() error :  %d (%s)", rv, ErrorToString(rv)))
	}
	return nil
}

func (self *Ldap) Add(dn string, attrs map[string][]string) (error){

	changeType := C.LDAP_MOD_ADD
	full_add := true
	rv := self.doModify(dn, attrs, changeType, full_add)
	if rv != LDAP_OPT_SUCCESS {
		return errors.New(fmt.Sprintf("LDAP::Add() error :  %d (%s)", rv, ErrorToString(rv)))
	}
	return nil
}

func (self *Ldap) Delete(dn string) (error){

	_dn := C.CString(dn)
	defer C.free(unsafe.Pointer(_dn))

	// API: int ldap_delete (LDAP *ld, LDAP_CONST char *dn)
	rv := C.ldap_delete_s(self.conn, _dn)

	if rv != LDAP_OPT_SUCCESS {
		return errors.New(fmt.Sprintf("LDAP::Delete() error :  %d (%s)", rv, ErrorToString(int(rv))))
	}

	return nil
}

// Rename() to rename LDAP entries.
//
// These  routines  are used to perform a LDAP rename operation.  The function changes the leaf compo-
// nent of an entry's distinguished name and  optionally moves the entry to a  new  parent  container.
// The  ldap_rename_s performs a rename operation synchronously.  The method takes dn, which points to
// the distinguished name of the entry whose attribute is being compared, newparent,the  distinguished
// name of the entry's new parent. If this parameter is NULL, only the RDN is changed.  The root DN is
// specified by passing a zero length string, "".  deleteoldrdn specifies whether the old  RDN  should
// be  retained  or  deleted.   Zero indicates that the old RDN should be retained. If you choose this
// option, the attribute will contain both names (the old and the new).  Non-zero indicates  that  the
// old  RDN should be deleted.  serverctrls points to an array of LDAPControl structures that list the
// client controls to use with this extended operation.  Use  NULL  to  specify  no  client  controls.
// clientctrls  points to an array of LDAPControl structures that list the client controls to use with
// the search.
// FIXME: support NULL and "" values for newSuperior parameter.
//
func (self *Ldap) Rename(dn string, newrdn string, newSuperior string, deleteOld bool) (error){

	_dn := C.CString(dn)
	defer C.free(unsafe.Pointer(_dn))

	_newrdn := C.CString(newrdn)
	defer C.free(unsafe.Pointer(_newrdn))

	_newSuperior := C.CString(newSuperior)
	defer C.free(unsafe.Pointer(_newSuperior))

	var _delete C.int = 0
	if deleteOld {
		_delete = 1
	}
 
	// API: int ldap_rename (LDAP *ld, char *newrdn, char *newSuperior, int deleteoldrdn)
	rv := C._ldap_rename(self.conn, _dn, _newrdn, _newSuperior, _delete)

	if rv != LDAP_OPT_SUCCESS {
		return errors.New(fmt.Sprintf("LDAP::Rename() error :  %d (%s)", rv, ErrorToString(int(rv))))
	}

	return nil
}