ruby-ldap 0.9.11 → 0.9.12
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +18 -0
- data/FAQ +5 -9
- data/NOTES +29 -0
- data/README +22 -18
- data/TODO +10 -0
- data/clientauth.c +605 -0
- data/conn.c +24 -1
- data/entry.c +9 -9
- data/extconf.rb +70 -29
- data/ldap.c +67 -0
- data/lib/ldap/control.rb +3 -3
- data/lib/ldap/ldif.rb +264 -269
- data/lib/ldap/schema.rb +39 -33
- data/mod.c +7 -3
- data/rbldap.h +8 -6
- data/test/cookbooks/apt/metadata.rb +13 -0
- data/test/cookbooks/apt/providers/repository.rb +73 -0
- data/test/cookbooks/apt/recipes/cacher-client.rb +44 -0
- data/test/cookbooks/apt/recipes/cacher.rb +45 -0
- data/test/cookbooks/apt/recipes/default.rb +50 -0
- data/test/cookbooks/apt/resources/repository.rb +30 -0
- data/test/cookbooks/nginx/attributes/default.rb +35 -0
- data/test/cookbooks/nginx/definitions/nginx_site.rb +35 -0
- data/test/cookbooks/nginx/metadata.rb +86 -0
- data/test/cookbooks/nginx/recipes/default.rb +56 -0
- data/test/cookbooks/nginx/recipes/source.rb +143 -0
- data/test/cookbooks/openldap/attributes/default.rb +61 -0
- data/test/cookbooks/openldap/metadata.rb +99 -0
- data/test/cookbooks/openldap/recipes/auth.rb +70 -0
- data/test/cookbooks/openldap/recipes/client.rb +28 -0
- data/test/cookbooks/openldap/recipes/default.rb +18 -0
- data/test/cookbooks/openldap/recipes/server.rb +110 -0
- data/test/cookbooks/postgresql/attributes/default.rb +68 -0
- data/test/cookbooks/postgresql/metadata.rb +15 -0
- data/test/cookbooks/postgresql/recipes/client.rb +27 -0
- data/test/cookbooks/postgresql/recipes/default.rb +20 -0
- data/test/cookbooks/postgresql/recipes/server.rb +36 -0
- data/test/cookbooks/postgresql/recipes/server_debian.rb +51 -0
- data/test/cookbooks/postgresql/recipes/server_redhat.rb +84 -0
- data/test/cookbooks/sqlite/metadata.rb +11 -0
- data/test/cookbooks/sqlite/recipes/default.rb +26 -0
- data/test/cookbooks/vagrant_main/recipes/default.rb +12 -0
- data/test/moz_cert.rb +105 -0
- data/test/setup.rb +2 -2
- data/win/wldap32.def +257 -0
- metadata +78 -55
data/conn.c
CHANGED
@@ -31,6 +31,7 @@ rb_ldap_conn_free (RB_LDAP_DATA * ldapdata)
|
|
31
31
|
{
|
32
32
|
ldap_unbind (ldapdata->ldap);
|
33
33
|
};
|
34
|
+
xfree(ldapdata);
|
34
35
|
};
|
35
36
|
|
36
37
|
static void
|
@@ -167,6 +168,26 @@ rb_ldap_conn_s_open (int argc, VALUE argv[], VALUE klass)
|
|
167
168
|
return conn;
|
168
169
|
};
|
169
170
|
|
171
|
+
/*
|
172
|
+
* call-seq:
|
173
|
+
* LDAP::Conn.open_uri(uri) => LDAP::Conn
|
174
|
+
*
|
175
|
+
* Return a new LDAP::Conn connection to the server described with +uri+.
|
176
|
+
*/
|
177
|
+
VALUE
|
178
|
+
rb_ldap_conn_s_open_uri (VALUE klass, VALUE uri)
|
179
|
+
{
|
180
|
+
LDAP *cldap = NULL;
|
181
|
+
int rc;
|
182
|
+
|
183
|
+
rc = ldap_initialize (&cldap, StringValueCStr (uri));
|
184
|
+
|
185
|
+
if (rc || cldap == NULL)
|
186
|
+
rb_raise (rb_eLDAP_ResultError, "can't open an LDAP session");
|
187
|
+
|
188
|
+
return rb_ldap_conn_new (klass, cldap);
|
189
|
+
};
|
190
|
+
|
170
191
|
/*
|
171
192
|
* call-seq:
|
172
193
|
* conn.start_tls => nil
|
@@ -742,7 +763,7 @@ rb_ldap_conn_get_errno (VALUE self)
|
|
742
763
|
GET_LDAP_DATA (self, ldapdata);
|
743
764
|
|
744
765
|
#ifdef USE_NETSCAPE_SDK
|
745
|
-
cerr = ldap_get_lderrno (ldapdata->ldap, NULL, NULL);
|
766
|
+
int cerr = ldap_get_lderrno (ldapdata->ldap, NULL, NULL);
|
746
767
|
err = INT2NUM (cerr);
|
747
768
|
#else
|
748
769
|
# ifdef USE_OPENLDAP1
|
@@ -1515,6 +1536,7 @@ rb_ldap_conn_modify_s (VALUE self, VALUE dn, VALUE attrs)
|
|
1515
1536
|
|
1516
1537
|
ldapdata->err = ldap_modify_s (ldapdata->ldap, c_dn, c_attrs);
|
1517
1538
|
Check_LDAP_Result (ldapdata->err);
|
1539
|
+
free(c_attrs);
|
1518
1540
|
|
1519
1541
|
return self;
|
1520
1542
|
};
|
@@ -1777,6 +1799,7 @@ Init_ldap_conn ()
|
|
1777
1799
|
rb_ldap_conn_s_allocate, 0);
|
1778
1800
|
#endif
|
1779
1801
|
rb_define_singleton_method (rb_cLDAP_Conn, "open", rb_ldap_conn_s_open, -1);
|
1802
|
+
rb_define_singleton_method (rb_cLDAP_Conn, "open_uri", rb_ldap_conn_s_open_uri, 1);
|
1780
1803
|
rb_define_singleton_method (rb_cLDAP_Conn, "set_option",
|
1781
1804
|
rb_ldap_conn_s_set_option, 2);
|
1782
1805
|
rb_define_singleton_method (rb_cLDAP_Conn, "get_option",
|
data/entry.c
CHANGED
@@ -12,6 +12,7 @@ VALUE rb_cLDAP_Entry;
|
|
12
12
|
void
|
13
13
|
rb_ldap_entry_free (RB_LDAPENTRY_DATA * edata)
|
14
14
|
{
|
15
|
+
xfree(edata);
|
15
16
|
/* edata->msg is valid in a block given by each search operation */
|
16
17
|
/* ldap_msgfree should be called after ldap_search */
|
17
18
|
}
|
@@ -22,7 +23,7 @@ rb_ldap_entry_new (LDAP * ldap, LDAPMessage * msg)
|
|
22
23
|
VALUE val;
|
23
24
|
RB_LDAPENTRY_DATA *edata;
|
24
25
|
val = Data_Make_Struct (rb_cLDAP_Entry, RB_LDAPENTRY_DATA,
|
25
|
-
0,
|
26
|
+
0, rb_ldap_entry_free, edata);
|
26
27
|
edata->ldap = ldap;
|
27
28
|
edata->msg = msg;
|
28
29
|
return val;
|
@@ -112,7 +113,7 @@ rb_ldap_entry_get_attributes (VALUE self)
|
|
112
113
|
RB_LDAPENTRY_DATA *edata;
|
113
114
|
VALUE vals;
|
114
115
|
char *attr;
|
115
|
-
BerElement *ber;
|
116
|
+
BerElement *ber = NULL;
|
116
117
|
|
117
118
|
GET_LDAPENTRY_DATA (self, edata);
|
118
119
|
|
@@ -122,15 +123,14 @@ rb_ldap_entry_get_attributes (VALUE self)
|
|
122
123
|
attr = ldap_next_attribute (edata->ldap, edata->msg, ber))
|
123
124
|
{
|
124
125
|
rb_ary_push (vals, rb_tainted_str_new2 (attr));
|
126
|
+
ldap_memfree(attr);
|
125
127
|
}
|
126
128
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
#endif
|
133
|
-
*/
|
129
|
+
#if !defined(USE_OPENLDAP1)
|
130
|
+
if( ber != NULL ){
|
131
|
+
ber_free(ber, 0);
|
132
|
+
}
|
133
|
+
#endif
|
134
134
|
|
135
135
|
return vals;
|
136
136
|
}
|
data/extconf.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
#
|
3
3
|
# extconf.rb for ldap extension
|
4
4
|
# $Id: extconf.rb,v 1.7 2006/04/18 23:49:56 ianmacd Exp $
|
@@ -10,13 +10,14 @@ $INTERACTIVE = false
|
|
10
10
|
|
11
11
|
if( ARGV.include?("--help") )
|
12
12
|
print <<EOF
|
13
|
-
--with-ldap-dir
|
13
|
+
--with-ldap-dir specify the LDAP directory.
|
14
14
|
--with-ldap-include specify the directory containing ldap.h and lber.h.
|
15
|
-
--with-ldap-lib
|
16
|
-
--with-netscape
|
17
|
-
--with-
|
18
|
-
--with-
|
19
|
-
--with-
|
15
|
+
--with-ldap-lib specify the directory containing the LDAP libraries.
|
16
|
+
--with-netscape build with Netscape SDK.
|
17
|
+
--with-mozilla build with Mozilla SDK (Enables certificate authentication).
|
18
|
+
--with-openldap1 build with OpenLDAP 1.x.
|
19
|
+
--with-openldap2 build with OpenLDAP 2.x.
|
20
|
+
--with-wldap32 Active Directory Client API.
|
20
21
|
|
21
22
|
The following are library configuration options:
|
22
23
|
--with-libcrypto=crypto, --without-libcrypto
|
@@ -40,7 +41,9 @@ def find_files(dir = nil)
|
|
40
41
|
search_dirs =
|
41
42
|
["/usr/local", "/usr", "/opt"] +
|
42
43
|
Dir.glob("/usr/local/./*ldap*").collect{|d| d.gsub(/\/\.\//, "/")} +
|
43
|
-
Dir.glob("/usr/./*ldap*").collect{|d| d.gsub(/\/\.\//, "/")
|
44
|
+
Dir.glob("/usr/./*ldap*").collect{|d| d.gsub(/\/\.\//, "/") +
|
45
|
+
Dir.glob("/usr/lib{64,}/mozldap/*ldap*") + ["/usr/include/mozldap"]
|
46
|
+
}
|
44
47
|
end
|
45
48
|
for d in search_dirs
|
46
49
|
h = File.join(d,"include","ldap.h")
|
@@ -48,21 +51,21 @@ def find_files(dir = nil)
|
|
48
51
|
if( File.exist?(h) )
|
49
52
|
l = Dir.glob(l)[0]
|
50
53
|
if( l )
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
if( $INTERACTIVE )
|
55
|
+
print("--with-ldap-dir=#{d} [y/n]")
|
56
|
+
ans = $stdin.gets
|
57
|
+
ans.chop!
|
58
|
+
if( ans == "y" )
|
59
|
+
result = [d, File.basename(l).split(".")[0][3..-1], File.basename(h)]
|
60
|
+
return result
|
61
|
+
break
|
62
|
+
end
|
63
|
+
else
|
64
|
+
print("--with-ldap-dir=#{d}\n")
|
65
|
+
result = [d, File.basename(l).split(".")[0][3..-1], File.basename(h)]
|
66
|
+
return result
|
67
|
+
break
|
68
|
+
end
|
66
69
|
end
|
67
70
|
end
|
68
71
|
end
|
@@ -83,6 +86,9 @@ def ldap_with_config(arg, default = nil)
|
|
83
86
|
end
|
84
87
|
|
85
88
|
$use_netscape = ldap_with_config("netscape")
|
89
|
+
if ldap_with_config("mozilla")
|
90
|
+
$use_netscape = '6'
|
91
|
+
end
|
86
92
|
$use_openldap1 = ldap_with_config("openldap1")
|
87
93
|
$use_openldap2 = ldap_with_config("openldap2")
|
88
94
|
$use_wldap32 = ldap_with_config("wldap32")
|
@@ -100,9 +106,17 @@ if( !($use_netscape || $use_openldap1 || $use_openldap2 || $use_wldap32) )
|
|
100
106
|
when /^ssldap50+$/, /^ldap50+$/
|
101
107
|
print("--with-netscape=5")
|
102
108
|
$use_netscape = "5"
|
109
|
+
when /^ssldap60+$/, /^ldap60+$/
|
110
|
+
print("--with-netscape=6")
|
111
|
+
$use_netscape = "6"
|
103
112
|
else
|
104
|
-
|
105
|
-
|
113
|
+
if RUBY_PLATFORM =~ /-(:?mingw32|mswin32)/
|
114
|
+
print("--with-wldap32\n")
|
115
|
+
$use_wldap32 = true
|
116
|
+
else
|
117
|
+
print("--with-openldap2\n")
|
118
|
+
$use_openldap2 = true
|
119
|
+
end
|
106
120
|
end
|
107
121
|
end
|
108
122
|
if( $use_netscape == true )
|
@@ -127,6 +141,27 @@ if( $use_netscape )
|
|
127
141
|
$libns = ldap_with_config("libns", "nspr4,plc4,plds4").split(",")
|
128
142
|
$liblber = ldap_with_config("liblber", "lber50")
|
129
143
|
$libssl = ldap_with_config("libssl", "ssl3")
|
144
|
+
when /^6/
|
145
|
+
%x{pkg-config --exists 'mozldap >= 6.0 nspr >= 4.0'}
|
146
|
+
|
147
|
+
if $? == 0
|
148
|
+
puts 'Mozzilla LDAP libs will be used.'
|
149
|
+
$mozlibs = %x{pkg-config mozldap nspr --libs}.chomp
|
150
|
+
$mozincs = %x{pkg-config mozldap nspr --cflags}.chomp
|
151
|
+
else
|
152
|
+
puts 'pkg-config reported that no right mozilla LDAP libs were found'
|
153
|
+
puts 'we need mozldap >= 6.0 and nspr >= 4.0'
|
154
|
+
exit 1
|
155
|
+
end
|
156
|
+
|
157
|
+
$defs << "-DUSE_NETSCAPE_SDK -DUSE_SSL_CLIENTAUTH"
|
158
|
+
#$libnsl = ldap_with_config("libnsl", "nsl")
|
159
|
+
#$libpthread = ldap_with_config("libpthread", "pthread")
|
160
|
+
$libresolv = ldap_with_config("libresolv", "resolv")
|
161
|
+
$libldap = ldap_with_config("libldap", "ldap60")
|
162
|
+
$libns = ldap_with_config("libns", "nspr4,plc4,plds4").split(",")
|
163
|
+
$liblber = ldap_with_config("liblber", "lber60")
|
164
|
+
$libssl = ldap_with_config("libssl", "ssl3")
|
130
165
|
end
|
131
166
|
end
|
132
167
|
|
@@ -173,6 +208,10 @@ if( $use_wldap32 )
|
|
173
208
|
have_header("winldap.h")
|
174
209
|
have_header("winlber.h")
|
175
210
|
have_header("sys/time.h")
|
211
|
+
elsif $use_netscape =~ /^6/
|
212
|
+
# mozilla
|
213
|
+
pkg_config('mozldap')
|
214
|
+
pkg_config('nspr')
|
176
215
|
else
|
177
216
|
ldap_h = have_header("ldap.h")
|
178
217
|
lber_h = have_header("lber.h")
|
@@ -187,6 +226,7 @@ else
|
|
187
226
|
have_header("openssl/crypto.h") || have_header("crypto.h")
|
188
227
|
end
|
189
228
|
|
229
|
+
$LIBS << ' -pthread'
|
190
230
|
for l in [$libcrypto, $libssl, $libnsl, $libpthread, $libresolv,
|
191
231
|
$libns, $liblber, $libldap_r, $libldap].flatten
|
192
232
|
if( l )
|
@@ -194,7 +234,7 @@ for l in [$libcrypto, $libssl, $libnsl, $libpthread, $libresolv,
|
|
194
234
|
end
|
195
235
|
end
|
196
236
|
|
197
|
-
have_func("ldap_init")
|
237
|
+
have_func("ldap_init", 'ldap.h')
|
198
238
|
have_func("ldap_set_option")
|
199
239
|
have_func("ldap_get_option")
|
200
240
|
have_func("ldap_start_tls_s") if $use_openldap2
|
@@ -242,7 +282,7 @@ end
|
|
242
282
|
$run_test += " #{$slapd} #{$schema_dir}"
|
243
283
|
|
244
284
|
|
245
|
-
File.open("Makefile","a")
|
285
|
+
File.open("Makefile","a") do |f|
|
246
286
|
f.print <<EOF
|
247
287
|
|
248
288
|
test::
|
@@ -263,6 +303,7 @@ doc:
|
|
263
303
|
unit:
|
264
304
|
\t(cd test; $(RUBY_INSTALL_NAME) tc_ldif.rb)
|
265
305
|
|
266
|
-
.PHONY:
|
306
|
+
.PHONY: doc
|
267
307
|
EOF
|
268
|
-
|
308
|
+
|
309
|
+
end
|
data/ldap.c
CHANGED
@@ -88,6 +88,65 @@ rb_ldap_dn2ufn (VALUE self, VALUE dn)
|
|
88
88
|
}
|
89
89
|
}
|
90
90
|
|
91
|
+
VALUE
|
92
|
+
rb_ldap_explode_dn (VALUE self, VALUE dn, VALUE notypes)
|
93
|
+
{
|
94
|
+
char **c_arr, **p;
|
95
|
+
char *c_dn;
|
96
|
+
VALUE ary;
|
97
|
+
|
98
|
+
if (dn == Qnil)
|
99
|
+
{
|
100
|
+
return Qnil;
|
101
|
+
}
|
102
|
+
|
103
|
+
c_dn = StringValueCStr (dn);
|
104
|
+
if ((c_arr = ldap_explode_dn (c_dn, RTEST (notypes) ? 1 : 0)))
|
105
|
+
{
|
106
|
+
ary = rb_ary_new ();
|
107
|
+
for (p = c_arr; *p != NULL; p++)
|
108
|
+
{
|
109
|
+
rb_ary_push (ary, rb_tainted_str_new2 (*p));
|
110
|
+
}
|
111
|
+
ldap_value_free (c_arr);
|
112
|
+
|
113
|
+
return ary;
|
114
|
+
}
|
115
|
+
else
|
116
|
+
{
|
117
|
+
return Qnil;
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
121
|
+
VALUE
|
122
|
+
rb_ldap_explode_rdn (VALUE self, VALUE rdn, VALUE notypes)
|
123
|
+
{
|
124
|
+
char **c_arr, **p;
|
125
|
+
char *c_dn;
|
126
|
+
VALUE ary;
|
127
|
+
|
128
|
+
if (rdn == Qnil)
|
129
|
+
{
|
130
|
+
return Qnil;
|
131
|
+
}
|
132
|
+
|
133
|
+
c_dn = StringValueCStr (rdn);
|
134
|
+
if ((c_arr = ldap_explode_rdn (c_dn, RTEST (notypes) ? 1 : 0)))
|
135
|
+
{
|
136
|
+
ary = rb_ary_new ();
|
137
|
+
for (p = c_arr; *p != NULL; p++) {
|
138
|
+
rb_ary_push (ary, rb_tainted_str_new2 (*p));
|
139
|
+
}
|
140
|
+
ldap_value_free (c_arr);
|
141
|
+
|
142
|
+
return ary;
|
143
|
+
}
|
144
|
+
else
|
145
|
+
{
|
146
|
+
return Qnil;
|
147
|
+
}
|
148
|
+
}
|
149
|
+
|
91
150
|
/*
|
92
151
|
* call-seq:
|
93
152
|
* LDAP.mod(mod_type, attr, vals) => LDAP::Mod
|
@@ -165,6 +224,9 @@ extern void Init_ldap_entry ();
|
|
165
224
|
extern void Init_ldap_conn ();
|
166
225
|
extern void Init_ldap_sslconn ();
|
167
226
|
extern void Init_ldap_saslconn ();
|
227
|
+
#ifdef USE_SSL_CLIENTAUTH
|
228
|
+
extern void Init_ldap_clientauth ();
|
229
|
+
#endif
|
168
230
|
extern void Init_ldap_mod ();
|
169
231
|
extern void Init_ldap_misc ();
|
170
232
|
|
@@ -246,6 +308,8 @@ Init_ldap ()
|
|
246
308
|
|
247
309
|
|
248
310
|
rb_define_module_function (rb_mLDAP, "err2string", rb_ldap_err2string, 1);
|
311
|
+
rb_define_module_function (rb_mLDAP, "explode_dn", rb_ldap_explode_dn, 2);
|
312
|
+
rb_define_module_function (rb_mLDAP, "explode_rdn", rb_ldap_explode_rdn, 2);
|
249
313
|
rb_define_module_function (rb_mLDAP, "dn2ufn", rb_ldap_dn2ufn, 1);
|
250
314
|
rb_define_module_function (rb_mLDAP, "mod", rb_ldap_mod_s_new, -1);
|
251
315
|
rb_define_module_function (rb_mLDAP, "hash2mods", rb_ldap_hash2mods, 2);
|
@@ -571,6 +635,9 @@ Init_ldap ()
|
|
571
635
|
Init_ldap_conn ();
|
572
636
|
Init_ldap_sslconn ();
|
573
637
|
Init_ldap_saslconn ();
|
638
|
+
#ifdef USE_SSL_CLIENTAUTH
|
639
|
+
Init_ldap_clientauth();
|
640
|
+
#endif
|
574
641
|
Init_ldap_entry ();
|
575
642
|
Init_ldap_mod ();
|
576
643
|
Init_ldap_misc ();
|
data/lib/ldap/control.rb
CHANGED
@@ -17,7 +17,7 @@ module LDAP
|
|
17
17
|
#
|
18
18
|
def Control.encode( *vals )
|
19
19
|
encoded_vals = []
|
20
|
-
|
20
|
+
|
21
21
|
vals.each do |val|
|
22
22
|
encoded_vals <<
|
23
23
|
case val
|
@@ -29,7 +29,7 @@ module LDAP
|
|
29
29
|
# What other types may exist?
|
30
30
|
end
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
OpenSSL::ASN1::Sequence.new( encoded_vals ).to_der
|
34
34
|
end
|
35
35
|
|
@@ -40,7 +40,7 @@ module LDAP
|
|
40
40
|
values = []
|
41
41
|
|
42
42
|
OpenSSL::ASN1::decode( self.value ).value.each do |val|
|
43
|
-
|
43
|
+
values << val.value
|
44
44
|
end
|
45
45
|
|
46
46
|
values
|
data/lib/ldap/ldif.rb
CHANGED
@@ -37,22 +37,22 @@ module LDAP
|
|
37
37
|
#
|
38
38
|
def send( conn )
|
39
39
|
if @change_type == :MODRDN
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
# TODO: How do we deal with 'newsuperior'?
|
41
|
+
# The LDAP API's ldap_modrdn2_s() function doesn't seem to use it.
|
42
|
+
return conn.modrdn( @dn, @attrs['newrdn'], @attrs['deleteoldrdn'] )
|
43
43
|
end
|
44
44
|
|
45
45
|
# Mask out the LDAP_MOD_BVALUES bit, as it's irrelevant here.
|
46
46
|
case @change_type & ~LDAP_MOD_BVALUES
|
47
47
|
when LDAP_MOD_ADD
|
48
|
-
|
49
|
-
|
48
|
+
@controls == [] ? conn.add( @dn, @attrs ) :
|
49
|
+
conn.add_ext( @dn, @attrs, @controls, [] )
|
50
50
|
when LDAP_MOD_DELETE
|
51
|
-
|
52
|
-
|
51
|
+
@controls == [] ? conn.delete( @dn ) :
|
52
|
+
conn.delete_ext( @dn, @controls, [] )
|
53
53
|
when LDAP_MOD_REPLACE
|
54
|
-
|
55
|
-
|
54
|
+
@controls == [] ? conn.modify( @dn, @mods ) :
|
55
|
+
conn.modify_ext( @dn, @mods, @controls, [] )
|
56
56
|
end
|
57
57
|
|
58
58
|
self
|
@@ -75,7 +75,7 @@ module LDAP
|
|
75
75
|
#
|
76
76
|
%w[ creatorsname createtimestamp modifiersname modifytimestamp
|
77
77
|
entrycsn entryuuid structuralobjectclass ].each do |attr|
|
78
|
-
|
78
|
+
@attrs.delete( attr )
|
79
79
|
end
|
80
80
|
|
81
81
|
# Clean out duplicate attribute values.
|
@@ -132,7 +132,7 @@ module LDAP
|
|
132
132
|
unless url.sub!( %r(^file://), '' )
|
133
133
|
raise ArgumentError, "Bad external file reference: #{url}"
|
134
134
|
end
|
135
|
-
|
135
|
+
|
136
136
|
# Slurp an external file.
|
137
137
|
# TODO: Support other URL types in the future.
|
138
138
|
File.open( url ).readlines( nil )[0]
|
@@ -150,10 +150,10 @@ module LDAP
|
|
150
150
|
sep = '::'
|
151
151
|
val = base64_encode( val, true )
|
152
152
|
end
|
153
|
-
|
153
|
+
|
154
154
|
firstline_len = LINE_LENGTH - ( "%s%s " % [ attr, sep ] ).length
|
155
155
|
ldif << "%s%s %s\n" % [ attr, sep, val.slice!( 0..firstline_len ) ]
|
156
|
-
|
156
|
+
|
157
157
|
while val.length > 0
|
158
158
|
ldif << " %s\n" % val.slice!( 0..LINE_LENGTH - 1 )
|
159
159
|
end
|
@@ -182,173 +182,172 @@ module LDAP
|
|
182
182
|
hash = {}
|
183
183
|
mods = {}
|
184
184
|
mod_type = nil
|
185
|
-
|
185
|
+
|
186
186
|
lines.each do |line|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
187
|
+
# Skip (continued) comments.
|
188
|
+
if line =~ /^#/ || ( comment && line[0..0] == ' ' )
|
189
|
+
comment = true
|
190
|
+
next
|
191
|
+
end
|
192
|
+
|
193
|
+
# Skip blank lines.
|
194
|
+
next if line =~ /^$/
|
195
|
+
|
196
|
+
# Reset mod type if this entry has more than one mod to make.
|
197
|
+
# A '-' continuation is only valid if we've already had a
|
198
|
+
# 'changetype: modify' line.
|
199
|
+
if line =~ /^-$/ && change_type == LDAP_MOD_REPLACE
|
200
|
+
next
|
201
|
+
end
|
202
|
+
|
203
|
+
line.chomp!
|
204
|
+
|
205
|
+
# N.B. Attributes and values can be separated by one or two colons,
|
206
|
+
# or one colon and a '<'. Either of these is then followed by zero
|
207
|
+
# or one spaces.
|
208
|
+
if md = line.match( /^[^ ].*?((:[:<]?) ?)/ )
|
209
|
+
|
210
|
+
# If previous value was Base64-encoded and is not continued,
|
211
|
+
# we need to decode it now.
|
212
|
+
if sep == '::'
|
213
|
+
if mod_type
|
214
|
+
mods[mod_type][attr][-1] =
|
215
|
+
base64_decode( mods[mod_type][attr][-1] )
|
216
|
+
bvalues << attr if unsafe_char?( mods[mod_type][attr][-1] )
|
217
|
+
else
|
218
|
+
hash[attr][-1] = base64_decode( hash[attr][-1] )
|
219
|
+
bvalues << attr if unsafe_char?( hash[attr][-1] )
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Found a attr/value line.
|
224
|
+
attr, val = line.split( md[1], 2 )
|
225
|
+
attr.downcase!
|
226
|
+
|
227
|
+
# Attribute must be ldap-oid / (ALPHA *(attr-type-chars))
|
228
|
+
if attr !~ /^(?:(?:\d+\.)*\d+|[[:alnum:]-]+)(?:;[[:alnum:]-]+)*$/
|
229
|
+
raise LDIFError, "Invalid attribute: #{attr}"
|
230
|
+
end
|
231
|
+
|
232
|
+
if attr == 'dn'
|
233
|
+
header = false
|
234
|
+
change_type = nil
|
235
|
+
controls = []
|
236
|
+
end
|
237
|
+
sep = md[2]
|
238
|
+
|
239
|
+
val = read_file( val ) if sep == ':<'
|
240
|
+
|
241
|
+
case attr
|
242
|
+
when 'version'
|
243
|
+
# Check the LDIF version.
|
244
|
+
if header
|
245
|
+
if val != '1'
|
246
|
+
raise LDIFError, "Unsupported LDIF version: #{val}"
|
247
|
+
else
|
248
|
+
header = false
|
249
|
+
next
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
when 'changetype'
|
254
|
+
change_type = case val
|
255
|
+
when 'add' then LDAP_MOD_ADD
|
256
|
+
when 'delete' then LDAP_MOD_DELETE
|
257
|
+
when 'modify' then LDAP_MOD_REPLACE
|
258
|
+
when /^modr?dn$/ then :MODRDN
|
259
|
+
end
|
260
|
+
|
261
|
+
raise LDIFError, "Invalid change type: #{attr}" unless change_type
|
262
|
+
|
263
|
+
when 'add', 'delete', 'replace'
|
264
|
+
unless change_type == LDAP_MOD_REPLACE
|
265
|
+
raise LDIFError, "Cannot #{attr} here."
|
266
|
+
end
|
267
|
+
|
268
|
+
mod_type = case attr
|
269
|
+
when 'add' then LDAP_MOD_ADD
|
270
|
+
when 'delete' then LDAP_MOD_DELETE
|
271
|
+
when 'replace' then LDAP_MOD_REPLACE
|
272
|
+
end
|
273
|
+
|
274
|
+
# In this case val is actually an attribute and should be lowercased.
|
275
|
+
mods[mod_type] ||= {}
|
276
|
+
mods[mod_type][val.downcase] ||= []
|
277
|
+
|
278
|
+
when 'control'
|
279
|
+
oid, criticality = val.split( / /, 2 )
|
280
|
+
|
281
|
+
unless oid =~ /(?:\d+\.)*\d+/
|
282
|
+
raise LDIFError, "Bad control OID: #{oid}"
|
283
|
+
end
|
284
|
+
|
285
|
+
if criticality
|
286
|
+
md = criticality.match( /(:[:<]?) ?/ )
|
287
|
+
ctl_sep = md[1] if md
|
288
|
+
criticality, value = criticality.split( /:[:<]? ?/, 2 )
|
289
|
+
|
290
|
+
if criticality !~ /^(?:true|false)$/
|
291
|
+
raise LDIFError, "Bad control criticality: #{criticality}"
|
292
|
+
end
|
293
|
+
|
294
|
+
# Convert 'true' or 'false'. to_boolean would be nice. :-)
|
295
|
+
criticality = eval( criticality )
|
296
|
+
end
|
297
|
+
|
298
|
+
if value
|
299
|
+
value = base64_decode( value ) if ctl_sep == '::'
|
300
|
+
value = read_file( value ) if ctl_sep == ':<'
|
301
|
+
value = Control.encode( value )
|
302
|
+
end
|
303
|
+
|
304
|
+
controls << Control.new( oid, value, criticality )
|
305
|
+
|
306
|
+
else
|
307
|
+
# Convert modrdn's deleteoldrdn from '1' to true, anything else
|
308
|
+
# to false. Should probably raise an exception if not '0' or '1'.
|
309
|
+
#
|
310
|
+
if change_type == :MODRDN && attr == 'deleteoldrdn'
|
311
|
+
val = val == '1' ? true : false
|
312
|
+
end
|
313
|
+
|
314
|
+
if change_type == LDAP_MOD_REPLACE
|
315
|
+
mods[mod_type][attr] << val
|
316
|
+
else
|
317
|
+
hash[attr] ||= []
|
318
|
+
hash[attr] << val
|
319
|
+
end
|
320
|
+
|
321
|
+
comment = false
|
322
|
+
|
323
|
+
# Make a note of this attribute if value is binary.
|
324
|
+
bvalues << attr if unsafe_char?( val )
|
325
|
+
|
326
|
+
end
|
327
|
+
|
328
|
+
else
|
329
|
+
# Check last line's separator: if not a binary value, the
|
330
|
+
# continuation line must be indented. If a comment makes it this
|
331
|
+
# far, that's also an error.
|
332
|
+
#
|
333
|
+
if sep == ':' && line[0..0] != ' ' || comment
|
334
|
+
raise LDIFError, "Improperly continued line: #{line}"
|
335
|
+
end
|
336
|
+
|
337
|
+
# OK; this is a valid continuation line.
|
338
|
+
|
339
|
+
# Append line except for initial space.
|
340
|
+
line[0] = '' if line[0..0] == ' '
|
341
|
+
|
342
|
+
if change_type == LDAP_MOD_REPLACE
|
343
|
+
# Append to last value of current mod type.
|
344
|
+
mods[mod_type][attr][-1] << line
|
345
|
+
else
|
346
|
+
# Append to last value.
|
347
|
+
hash[attr][-1] << line
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
352
351
|
end
|
353
352
|
|
354
353
|
# If last value in LDIF entry was Base64-encoded, we need to decode
|
@@ -356,11 +355,11 @@ module LDAP
|
|
356
355
|
if sep == '::'
|
357
356
|
if mod_type
|
358
357
|
mods[mod_type][attr][-1] =
|
359
|
-
|
360
|
-
|
358
|
+
base64_decode( mods[mod_type][attr][-1] )
|
359
|
+
bvalues << attr if unsafe_char?( mods[mod_type][attr][-1] )
|
361
360
|
else
|
362
361
|
hash[attr][-1] = base64_decode( hash[attr][-1] )
|
363
|
-
|
362
|
+
bvalues << attr if unsafe_char?( hash[attr][-1] )
|
364
363
|
end
|
365
364
|
end
|
366
365
|
|
@@ -377,47 +376,43 @@ module LDAP
|
|
377
376
|
|
378
377
|
case change_type
|
379
378
|
when LDAP_MOD_ADD
|
379
|
+
mods[LDAP_MOD_ADD] = []
|
380
380
|
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
ct = LDAP_MOD_ADD
|
388
|
-
end
|
381
|
+
hash.each do |attr_local, val|
|
382
|
+
if bvalues.include?( attr_local )
|
383
|
+
ct = LDAP_MOD_ADD | LDAP_MOD_BVALUES
|
384
|
+
else
|
385
|
+
ct = LDAP_MOD_ADD
|
386
|
+
end
|
389
387
|
|
390
|
-
|
391
|
-
|
388
|
+
mods[LDAP_MOD_ADD] << LDAP.mod( ct, attr_local, val )
|
389
|
+
end
|
392
390
|
|
393
391
|
when LDAP_MOD_DELETE
|
394
|
-
|
395
|
-
# Nothing to do.
|
392
|
+
# Nothing to do.
|
396
393
|
|
397
394
|
when LDAP_MOD_REPLACE
|
395
|
+
raise LDIFError, "mods should not be empty" if mods == {}
|
398
396
|
|
399
|
-
|
397
|
+
new_mods = {}
|
400
398
|
|
401
|
-
|
399
|
+
mods.each do |mod_type_local,attrs|
|
400
|
+
attrs.each_key do |attr_local|
|
401
|
+
if bvalues.include?( attr_local )
|
402
|
+
mt = mod_type_local | LDAP_MOD_BVALUES
|
403
|
+
else
|
404
|
+
mt = mod_type_local
|
405
|
+
end
|
402
406
|
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
else
|
408
|
-
mt = mod_type_local
|
409
|
-
end
|
410
|
-
|
411
|
-
new_mods[mt] ||= {}
|
412
|
-
new_mods[mt][attr_local] = mods[mod_type_local][attr_local]
|
413
|
-
end
|
414
|
-
end
|
407
|
+
new_mods[mt] ||= {}
|
408
|
+
new_mods[mt][attr_local] = mods[mod_type_local][attr_local]
|
409
|
+
end
|
410
|
+
end
|
415
411
|
|
416
|
-
|
412
|
+
mods = new_mods
|
417
413
|
|
418
414
|
when :MODRDN
|
419
|
-
|
420
|
-
# Nothing to do.
|
415
|
+
# Nothing to do.
|
421
416
|
|
422
417
|
end
|
423
418
|
|
@@ -439,53 +434,53 @@ module LDAP
|
|
439
434
|
def LDIF.parse_file( file, sort=false ) # :yield: record
|
440
435
|
|
441
436
|
File.open( file ) do |f|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
437
|
+
entries = []
|
438
|
+
entry = false
|
439
|
+
header = true
|
440
|
+
version = false
|
441
|
+
|
442
|
+
while line = f.gets
|
443
|
+
|
444
|
+
if line =~ /^dn:/
|
445
|
+
header = false
|
446
|
+
|
447
|
+
if entry && ! version
|
448
|
+
if block_given?
|
449
|
+
yield parse_entry( entry )
|
450
|
+
else
|
451
|
+
entries << parse_entry( entry )
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
if version
|
456
|
+
entry << line
|
457
|
+
version = false
|
458
|
+
else
|
459
|
+
entry = [ line ]
|
460
|
+
end
|
461
|
+
|
462
|
+
next
|
463
|
+
end
|
464
|
+
|
465
|
+
if header && line.downcase =~ /^version/
|
466
|
+
entry = [ line ]
|
467
|
+
version = true
|
468
|
+
next
|
469
|
+
end
|
470
|
+
|
471
|
+
entry << line
|
472
|
+
end
|
473
|
+
|
474
|
+
if block_given?
|
475
|
+
yield parse_entry( entry )
|
476
|
+
nil
|
477
|
+
else
|
478
|
+
entries << parse_entry( entry )
|
479
|
+
|
480
|
+
# Sort entries if sorting has been requested.
|
481
|
+
entries.sort! { |x,y| x.dn.length <=> y.dn.length } if sort
|
482
|
+
entries
|
483
|
+
end
|
489
484
|
|
490
485
|
end
|
491
486
|
|
@@ -503,10 +498,10 @@ module LDAP
|
|
503
498
|
# TODO: Need to dynamically assemble this case statement to add
|
504
499
|
# OpenLDAP's increment change type, etc.
|
505
500
|
change_type = case mod.mod_op & ~LDAP_MOD_BVALUES
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
501
|
+
when LDAP_MOD_ADD then 'add'
|
502
|
+
when LDAP_MOD_DELETE then 'delete'
|
503
|
+
when LDAP_MOD_REPLACE then 'replace'
|
504
|
+
end
|
510
505
|
|
511
506
|
ldif << "-\n" if plural
|
512
507
|
ldif << LDIF.to_ldif( change_type, mod.mod_type )
|
@@ -529,9 +524,9 @@ module LDAP
|
|
529
524
|
ldif = "dn: %s\n" % get_dn
|
530
525
|
|
531
526
|
get_attributes.each do |attr|
|
532
|
-
|
533
|
-
|
534
|
-
|
527
|
+
get_values( attr ).each do |val|
|
528
|
+
ldif << LDIF.to_ldif( attr, [ val ] )
|
529
|
+
end
|
535
530
|
end
|
536
531
|
|
537
532
|
LDIF::Entry.new( ldif )
|
@@ -540,7 +535,7 @@ module LDAP
|
|
540
535
|
alias_method :to_s, :to_ldif
|
541
536
|
end
|
542
537
|
|
543
|
-
|
538
|
+
|
544
539
|
class Mod
|
545
540
|
|
546
541
|
# Convert an LDAP::Mod with the DN given in +dn+ to LDIF.
|
@@ -552,11 +547,11 @@ module LDAP
|
|
552
547
|
# OpenLDAP's increment change type, etc.
|
553
548
|
case mod_op & ~LDAP_MOD_BVALUES
|
554
549
|
when LDAP_MOD_ADD
|
555
|
-
|
550
|
+
ldif << "changetype: add\n"
|
556
551
|
when LDAP_MOD_DELETE
|
557
|
-
|
552
|
+
ldif << "changetype: delete\n"
|
558
553
|
when LDAP_MOD_REPLACE
|
559
|
-
|
554
|
+
return LDIF.mods_to_ldif( dn, self )
|
560
555
|
end
|
561
556
|
|
562
557
|
ldif << LDIF.to_ldif( mod_type, mod_vals )
|