View | Details | Raw Unified | Return to bug 132839
Collapse All | Expand All

(-)article.sgml (-48 / +66 lines)
Lines 307-313 Link Here
307
	organizational unit will look like:</para>
307
	organizational unit will look like:</para>
308
308
309
      <programlisting>dn: ou=people,dc=example,dc=org
309
      <programlisting>dn: ou=people,dc=example,dc=org
310
objectClass: top
311
objectClass: organizationalUnit
310
objectClass: organizationalUnit
312
ou: people</programlisting>
311
ou: people</programlisting>
313
312
Lines 336-342 Link Here
336
objectClass: person
335
objectClass: person
337
objectClass: posixAccount
336
objectClass: posixAccount
338
objectClass: shadowAccount
337
objectClass: shadowAccount
339
objectClass: top
340
uidNumber: 10000
338
uidNumber: 10000
341
gidNumber: 10000
339
gidNumber: 10000
342
homeDirectory: /home/tuser
340
homeDirectory: /home/tuser
Lines 352-364 Link Here
352
	user entries, but we will use the defaults below:</para>
350
	user entries, but we will use the defaults below:</para>
353
351
354
      <programlisting>dn: ou=groups,dc=example,dc=org
352
      <programlisting>dn: ou=groups,dc=example,dc=org
355
objectClass: top
356
objectClass: organizationalUnit
353
objectClass: organizationalUnit
357
ou: groups
354
ou: groups
358
355
359
dn: cn=tuser,ou=groups,dc=example,dc=org
356
dn: cn=tuser,ou=groups,dc=example,dc=org
360
objectClass: posixGroup
357
objectClass: posixGroup
361
objectClass: top
362
gidNumber: 10000
358
gidNumber: 10000
363
cn: tuser</programlisting>
359
cn: tuser</programlisting>
364
360
Lines 604-654 Link Here
604
	<screen>&prompt.root; <userinput>sysctl security.bsd.see_other_uids=0</userinput>.</screen>
600
	<screen>&prompt.root; <userinput>sysctl security.bsd.see_other_uids=0</userinput>.</screen>
605
      </caution>
601
      </caution>
606
602
607
      <para>A more flexible (and probably more secure) approach can be
603
  <para>A more flexible (and probably more secure) approach can be
608
	used by writing a custom program, or even a web interface.  The
604
	used by writing a custom program, or even a web interface.
609
	following is part of a <application>Ruby</application> library
605
	The following is modeled on a <application>Python</application>
610
	that can change LDAP passwords.  It sees use both on the command
606
	library that can change LDAP passwords.  It sees use both
611
	line, and on the web.</para>
607
	on the command line, and on the web.</para>
612
608
613
      <example id="chpw-ruby">
609
      <example id="chpw-python">
614
	<title>Ruby script for changing passwords</title>
610
	<title>Python script for changing passwords</title>
615
        
611
        
616
	<programlisting><![CDATA[require 'ldap'
612
	<programlisting><![CDATA[import ldap # python-ldap
617
require 'base64'
613
import os, sys
618
require 'digest'
614
from getpass import getpass
619
require 'password' # ruby-password
615
620
616
uri = "ldap://ldap1.dimins.com"
621
ldap_server = "ldap.example.org"
617
searchbase = "ou=people,dc=dimins,dc=com"
622
luser = "uid=#{ENV['USER']},ou=people,dc=example,dc=org"
618
filter = "(&(objectClass=posixAccount)(uid=%s))"
623
619
624
# get the new password, check it, and create a salted hash from it
620
# get the username; if none is given, use the current user
625
def get_password
621
user = os.environ['USER']
626
  pwd1 = Password.get("New Password: ")
622
if len(sys.argv) > 1:
627
  pwd2 = Password.get("Retype New Password: ")
623
    user = sys.argv[1]
628
624
629
  raise if pwd1 != pwd2
625
ldapobj = ldap.initialize(uri)
630
  pwd1.check # check password strength
626
ldapobj.start_tls_s() # this is pretty important
631
  
627
632
  salt = rand.to_s.gsub(/0\./, '')
628
# Get the users DN, and then bind as that.
633
  pass = pwd1.to_s
629
# The way to do this is first bind anonymously (if you don't allow anon
634
  hash = "{SSHA}"+Base64.encode64(Digest::SHA1.digest("#{pass}#{salt}")+salt).chomp!
630
# binds, there's probably some standard account you use for this.
635
  return hash
631
ldapobj.simple_bind_s()
636
end
632
637
633
# Search for a user with the uid we gave.  We search everything under
638
oldp = Password.get("Old Password: ")
634
# the "base" we configure above (as there may be other users with the same
639
newp = get_password
635
# UID elsewhere in the tree; we don't want to return those.
640
636
result = ldapobj.search_s(searchbase, ldap.SCOPE_SUBTREE, filter%user)
641
# We'll just replace it.  That we can bind proves that we either know
637
642
# the old password or are an admin.
638
if len(result) > 1:
643
639
    # This is kind of suspicious; we only want one user.
644
replace = LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE | LDAP::LDAP_MOD_BVALUES,
640
    print "I found several users that match that user id."
645
                        "userPassword",
641
    print "Talk to your sysadmin."
646
                        [newp])
642
    sys.exit(1)
647
643
648
conn = LDAP::SSLConn.new(ldap_server, 389, true)
644
# The results are an array of (dn, attrlist) tuples.
649
conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
645
dn = result[0][0]
650
conn.bind(luser, oldp)
646
651
conn.modify(luser, [replace])]]></programlisting>
647
# Now we get the user's old password, and bind to the server with it
648
# and his DN.  If it succeeds, he (and we) have the proper credentials to
649
# change his password.
650
passwd = getpass("current password: ")
651
try:
652
    ldapobj.simple_bind_s(dn, passwd)
653
except ldap.INVALID_CREDENTIALS:
654
    print "Bad password."
655
    sys.exit(1)
656
657
# Get and confirm new password.
658
npass1 = 'a'
659
npass2 = 'b'
660
while npass1 != npass2:
661
    npass1 = getpass("new password: ")
662
    npass2 = getpass("new password (again): ")
663
664
# This is the key.  This uses the LDAP Password Modify Extended Operation.
665
# It is important to use this when you can, although not all libraries
666
# (e.g. ruby-ldap) support it.  See rfc3062.
667
ldapobj.passwd_s(dn, passwd, npass1)
668
669
# And we're done.
670
ldapobj.unbind()]]></programlisting>
652
      </example>
671
      </example>
653
672
654
      <para>Although not guaranteed to be free of security holes (the
673
      <para>Although not guaranteed to be free of security holes (the
Lines 759-765 Link Here
759
	  <title>Creating a management group</title>
778
	  <title>Creating a management group</title>
760
779
761
	  <programlisting>dn: cn=homemanagement,dc=example,dc=org
780
	  <programlisting>dn: cn=homemanagement,dc=example,dc=org
762
objectClass: top
763
objectClass: posixGroup
781
objectClass: posixGroup
764
cn: homemanagement
782
cn: homemanagement
765
gidNumber: 121 # required for posixGroup
783
gidNumber: 121 # required for posixGroup

Return to bug 132839