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.
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 )