ruby-ldap 0.9.11 → 0.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/ChangeLog +18 -0
  2. data/FAQ +5 -9
  3. data/NOTES +29 -0
  4. data/README +22 -18
  5. data/TODO +10 -0
  6. data/clientauth.c +605 -0
  7. data/conn.c +24 -1
  8. data/entry.c +9 -9
  9. data/extconf.rb +70 -29
  10. data/ldap.c +67 -0
  11. data/lib/ldap/control.rb +3 -3
  12. data/lib/ldap/ldif.rb +264 -269
  13. data/lib/ldap/schema.rb +39 -33
  14. data/mod.c +7 -3
  15. data/rbldap.h +8 -6
  16. data/test/cookbooks/apt/metadata.rb +13 -0
  17. data/test/cookbooks/apt/providers/repository.rb +73 -0
  18. data/test/cookbooks/apt/recipes/cacher-client.rb +44 -0
  19. data/test/cookbooks/apt/recipes/cacher.rb +45 -0
  20. data/test/cookbooks/apt/recipes/default.rb +50 -0
  21. data/test/cookbooks/apt/resources/repository.rb +30 -0
  22. data/test/cookbooks/nginx/attributes/default.rb +35 -0
  23. data/test/cookbooks/nginx/definitions/nginx_site.rb +35 -0
  24. data/test/cookbooks/nginx/metadata.rb +86 -0
  25. data/test/cookbooks/nginx/recipes/default.rb +56 -0
  26. data/test/cookbooks/nginx/recipes/source.rb +143 -0
  27. data/test/cookbooks/openldap/attributes/default.rb +61 -0
  28. data/test/cookbooks/openldap/metadata.rb +99 -0
  29. data/test/cookbooks/openldap/recipes/auth.rb +70 -0
  30. data/test/cookbooks/openldap/recipes/client.rb +28 -0
  31. data/test/cookbooks/openldap/recipes/default.rb +18 -0
  32. data/test/cookbooks/openldap/recipes/server.rb +110 -0
  33. data/test/cookbooks/postgresql/attributes/default.rb +68 -0
  34. data/test/cookbooks/postgresql/metadata.rb +15 -0
  35. data/test/cookbooks/postgresql/recipes/client.rb +27 -0
  36. data/test/cookbooks/postgresql/recipes/default.rb +20 -0
  37. data/test/cookbooks/postgresql/recipes/server.rb +36 -0
  38. data/test/cookbooks/postgresql/recipes/server_debian.rb +51 -0
  39. data/test/cookbooks/postgresql/recipes/server_redhat.rb +84 -0
  40. data/test/cookbooks/sqlite/metadata.rb +11 -0
  41. data/test/cookbooks/sqlite/recipes/default.rb +26 -0
  42. data/test/cookbooks/vagrant_main/recipes/default.rb +12 -0
  43. data/test/moz_cert.rb +105 -0
  44. data/test/setup.rb +2 -2
  45. data/win/wldap32.def +257 -0
  46. 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, 0 /* rb_ldap_entry_free */ , edata);
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
- /* this code may cause segv
128
- #if !defined(USE_OPENLDAP1)
129
- if( ber != NULL ){
130
- ber_free(ber, 0);
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.4
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 specify the LDAP directory.
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 specify the directory containing the LDAP libraries.
16
- --with-netscape build with Netscape SDK.
17
- --with-openldap1 build with OpenLDAP 1.x.
18
- --with-openldap2 build with OpenLDAP 2.x.
19
- --with-wldap32 Active Directory Client API.
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
- if( $INTERACTIVE )
52
- print("--with-ldap-dir=#{d} [y/n]")
53
- ans = $stdin.gets
54
- ans.chop!
55
- if( ans == "y" )
56
- result = [d, File.basename(l).split(".")[0][3..-1], File.basename(h)]
57
- return result
58
- break
59
- end
60
- else
61
- print("--with-ldap-dir=#{d}\n")
62
- result = [d, File.basename(l).split(".")[0][3..-1], File.basename(h)]
63
- return result
64
- break
65
- end
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
- print("--with-openldap2\n")
105
- $use_openldap2 = true
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"){|f|
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: doc
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
- values << val.value
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
- # 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'] )
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
- @controls == [] ? conn.add( @dn, @attrs ) :
49
- conn.add_ext( @dn, @attrs, @controls, [] )
48
+ @controls == [] ? conn.add( @dn, @attrs ) :
49
+ conn.add_ext( @dn, @attrs, @controls, [] )
50
50
  when LDAP_MOD_DELETE
51
- @controls == [] ? conn.delete( @dn ) :
52
- conn.delete_ext( @dn, @controls, [] )
51
+ @controls == [] ? conn.delete( @dn ) :
52
+ conn.delete_ext( @dn, @controls, [] )
53
53
  when LDAP_MOD_REPLACE
54
- @controls == [] ? conn.modify( @dn, @mods ) :
55
- conn.modify_ext( @dn, @mods, @controls, [] )
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
- @attrs.delete( attr )
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
- # 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
-
222
- end
223
-
224
- # Found a attr/value line.
225
- attr, val = line.split( md[1], 2 )
226
- attr.downcase!
227
-
228
- # Attribute must be ldap-oid / (ALPHA *(attr-type-chars))
229
- if attr !~ /^(?:(?:\d+\.)*\d+|[[:alnum:]-]+)(?:;[[:alnum:]-]+)*$/
230
- raise LDIFError, "Invalid attribute: #{attr}"
231
- end
232
-
233
- if attr == 'dn'
234
- header = false
235
- change_type = nil
236
- controls = []
237
- end
238
- sep = md[2]
239
-
240
- val = read_file( val ) if sep == ':<'
241
-
242
- case attr
243
- when 'version'
244
- # Check the LDIF version.
245
- if header
246
- if val != '1'
247
- raise LDIFError, "Unsupported LDIF version: #{val}"
248
- else
249
- header = false
250
- next
251
- end
252
- end
253
-
254
- when 'changetype'
255
- change_type = case val
256
- when 'add' then LDAP_MOD_ADD
257
- when 'delete' then LDAP_MOD_DELETE
258
- when 'modify' then LDAP_MOD_REPLACE
259
- when /^modr?dn$/ then :MODRDN
260
- end
261
-
262
- raise LDIFError, "Invalid change type: #{attr}" unless change_type
263
-
264
- when 'add', 'delete', 'replace'
265
- unless change_type == LDAP_MOD_REPLACE
266
- raise LDIFError, "Cannot #{attr} here."
267
- end
268
-
269
- mod_type = case attr
270
- when 'add' then LDAP_MOD_ADD
271
- when 'delete' then LDAP_MOD_DELETE
272
- when 'replace' then LDAP_MOD_REPLACE
273
- end
274
-
275
- mods[mod_type] ||= {}
276
- mods[mod_type][val] ||= []
277
-
278
- when 'control'
279
-
280
- oid, criticality = val.split( / /, 2 )
281
-
282
- unless oid =~ /(?:\d+\.)*\d+/
283
- raise LDIFError, "Bad control OID: #{oid}"
284
- end
285
-
286
- if criticality
287
- md = criticality.match( /(:[:<]?) ?/ )
288
- ctl_sep = md[1] if md
289
- criticality, value = criticality.split( /:[:<]? ?/, 2 )
290
-
291
- if criticality !~ /^(?:true|false)$/
292
- raise LDIFError, "Bad control criticality: #{criticality}"
293
- end
294
-
295
- # Convert 'true' or 'false'. to_boolean would be nice. :-)
296
- criticality = eval( criticality )
297
- end
298
-
299
- if value
300
- value = base64_decode( value ) if ctl_sep == '::'
301
- value = read_file( value ) if ctl_sep == ':<'
302
- value = Control.encode( value )
303
- end
304
-
305
- controls << Control.new( oid, value, criticality )
306
- else
307
-
308
- # Convert modrdn's deleteoldrdn from '1' to true, anything else
309
- # to false. Should probably raise an exception if not '0' or '1'.
310
- #
311
- if change_type == :MODRDN && attr == 'deleteoldrdn'
312
- val = val == '1' ? true : false
313
- end
314
-
315
- if change_type == LDAP_MOD_REPLACE
316
- mods[mod_type][attr] << val
317
- else
318
- hash[attr] ||= []
319
- hash[attr] << val
320
- end
321
-
322
- comment = false
323
-
324
- # Make a note of this attribute if value is binary.
325
- bvalues << attr if unsafe_char?( val )
326
- end
327
-
328
- else
329
-
330
- # Check last line's separator: if not a binary value, the
331
- # continuation line must be indented. If a comment makes it this
332
- # far, that's also an error.
333
- #
334
- if sep == ':' && line[0..0] != ' ' || comment
335
- raise LDIFError, "Improperly continued line: #{line}"
336
- end
337
-
338
- # OK; this is a valid continuation line.
339
-
340
- # Append line except for initial space.
341
- line[0] = '' if line[0..0] == ' '
342
-
343
- if change_type == LDAP_MOD_REPLACE
344
- # Append to last value of current mod type.
345
- mods[mod_type][attr][-1] << line
346
- else
347
- # Append to last value.
348
- hash[attr][-1] << line
349
- end
350
- end
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
- base64_decode( mods[mod_type][attr][-1] )
360
- bvalues << attr if unsafe_char?( mods[mod_type][attr][-1] )
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
- bvalues << attr if unsafe_char?( hash[attr][-1] )
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
- mods[LDAP_MOD_ADD] = []
382
-
383
- hash.each do |attr_local, val|
384
- if bvalues.include?( attr_local )
385
- ct = LDAP_MOD_ADD | LDAP_MOD_BVALUES
386
- else
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
- mods[LDAP_MOD_ADD] << LDAP.mod( ct, attr_local, val )
391
- end
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
- raise LDIFError, "mods should not be empty" if mods == {}
397
+ new_mods = {}
400
398
 
401
- new_mods = {}
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
- mods.each do |mod_type_local,attrs|
404
- attrs.each_key do |attr_local|
405
- if bvalues.include?( attr_local )
406
- mt = mod_type_local | LDAP_MOD_BVALUES
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
- mods = new_mods
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
- entries = []
443
- entry = false
444
- header = true
445
- version = false
446
-
447
- while line = f.gets
448
-
449
- if line =~ /^dn:/
450
- header = false
451
-
452
- if entry && ! version
453
- if block_given?
454
- yield parse_entry( entry )
455
- else
456
- entries << parse_entry( entry )
457
- end
458
- end
459
-
460
- if version
461
- entry << line
462
- version = false
463
- else
464
- entry = [ line ]
465
- end
466
-
467
- next
468
- end
469
-
470
- if header && line.downcase =~ /^version/
471
- entry = [ line ]
472
- version = true
473
- next
474
- end
475
-
476
- entry << line
477
- end
478
-
479
- if block_given?
480
- yield parse_entry( entry )
481
- nil
482
- else
483
- entries << parse_entry( entry )
484
-
485
- # Sort entries if sorting has been requested.
486
- entries.sort! { |x,y| x.dn.length <=> y.dn.length } if sort
487
- entries
488
- end
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
- when LDAP_MOD_ADD then 'add'
507
- when LDAP_MOD_DELETE then 'delete'
508
- when LDAP_MOD_REPLACE then 'replace'
509
- end
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
- get_values( attr ).each do |val|
533
- ldif << LDIF.to_ldif( attr, [ val ] )
534
- end
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
- ldif << "changetype: add\n"
550
+ ldif << "changetype: add\n"
556
551
  when LDAP_MOD_DELETE
557
- ldif << "changetype: delete\n"
552
+ ldif << "changetype: delete\n"
558
553
  when LDAP_MOD_REPLACE
559
- return LDIF.mods_to_ldif( dn, self )
554
+ return LDIF.mods_to_ldif( dn, self )
560
555
  end
561
556
 
562
557
  ldif << LDIF.to_ldif( mod_type, mod_vals )