This commit is contained in:
John Dennis 2007-12-04 10:08:08 -05:00
commit d53915954e
45 changed files with 370 additions and 135 deletions

View File

@ -181,3 +181,4 @@ maintainer-clean: clean
rm -fr rpmbuild dist
cd ipa-server && $(MAKE) maintainer-clean
cd ipa-client && $(MAKE) maintainer-clean
cd ipa-python && $(MAKE) maintainer-clean

View File

@ -12,6 +12,7 @@ install:
install -m 755 ipa-finduser $(SBINDIR)
install -m 755 ipa-usermod $(SBINDIR)
install -m 755 ipa-deluser $(SBINDIR)
install -m 755 ipa-lockuser $(SBINDIR)
install -m 755 ipa-addgroup $(SBINDIR)
install -m 755 ipa-delgroup $(SBINDIR)
install -m 755 ipa-findgroup $(SBINDIR)

View File

@ -228,7 +228,7 @@ def main():
# Set the User's password
if password is not None:
try:
client.modifyPassword(principal, None, password)
client.modifyPassword(principal, '', password)
except ipa.ipaerror.IPAError, e:
print "User added but setting the password failed."
print "%s" % (e.message)

View File

@ -50,7 +50,19 @@ def main():
try:
client = ipaclient.IPAClient()
ret = client.delete_group(args[1])
groups = client.find_groups(args[1], ['cn','description','gidnumber','nsAccountLock'])
counter = groups[0]
groups = groups[1:]
if counter == 0:
print "Group '%s' not found." % args[1]
return 2
if counter != 1:
print "An exact group match was not found. Found %d groups" % counter
return 2
ret = client.delete_group(groups[0].dn)
if (ret == "Success"):
print args[1] + " successfully deleted"
else:

View File

@ -34,8 +34,6 @@ def usage():
def parse_options():
parser = OptionParser()
parser.add_option("-d", "--delete", action="store_true", dest="deluser",
help="Delete the user, don't inactivate them.")
parser.add_option("--usage", action="store_true",
help="Program usage")
@ -50,21 +48,10 @@ def main():
if len(args) != 2:
usage()
msg = "inactivated"
try:
client = ipaclient.IPAClient()
if options.deluser:
ret = client.delete_user(args[1])
msg = "deleted"
else:
try:
ret = client.mark_user_inactive(args[1])
except ipa.ipaerror.exception_for(ipa.ipaerror.LDAP_EMPTY_MODLIST):
print "User is already marked inactive"
return 0
except:
raise
print args[1] + " successfully %s" % msg
ret = client.delete_user(args[1])
print args[1] + " successfully deleted"
except xmlrpclib.Fault, fault:
if fault.faultCode == errno.ECONNREFUSED:
print "The IPA XML-RPC service is not responding."

View File

@ -0,0 +1,93 @@
#! /usr/bin/python -E
# Authors: Rob Crittenden <rcritten@redhat.com>
#
# Copyright (C) 2007 Red Hat
# see file 'COPYING' for use and warranty information
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 only
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
import sys
from optparse import OptionParser
import ipa
import ipa.ipaclient as ipaclient
import ipa.config
import errno
import xmlrpclib
import kerberos
def usage():
print "ipa-lockuser user"
sys.exit(1)
def parse_options():
parser = OptionParser()
parser.add_option("-u", "--unlock", action="store_true", dest="unlock",
help="Unlock a user's account")
parser.add_option("--usage", action="store_true",
help="Program usage")
args = ipa.config.init_config(sys.argv)
options, args = parser.parse_args(args)
return options, args
def main():
options, args = parse_options()
if len(args) != 2:
usage()
msg = "inactivated"
try:
client = ipaclient.IPAClient()
if options.unlock:
try:
ret = client.mark_user_active(args[1])
msg = "unlocked"
except ipa.ipaerror.exception_for(ipa.ipaerror.LDAP_EMPTY_MODLIST):
print "User is already marked active"
return 0
except:
raise
else:
try:
ret = client.mark_user_inactive(args[1])
except ipa.ipaerror.exception_for(ipa.ipaerror.LDAP_EMPTY_MODLIST):
print "User is already marked inactive"
return 0
except:
raise
print args[1] + " successfully %s" % msg
except xmlrpclib.Fault, fault:
if fault.faultCode == errno.ECONNREFUSED:
print "The IPA XML-RPC service is not responding."
else:
print fault.faultString
return 1
except kerberos.GSSError, e:
print "Could not initialize GSSAPI: %s/%s" % (e[0][0][0], e[0][1][0])
return 1
except xmlrpclib.ProtocolError, e:
print "Unable to connect to IPA server: %s" % (e.errmsg)
return 1
except ipa.ipaerror.IPAError, e:
print "%s" % (e.message)
return 1
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@ -98,7 +98,7 @@ def main():
try:
client = ipaclient.IPAClient()
client.modifyPassword(principal, None, password)
client.modifyPassword(principal, '', password)
except xmlrpclib.Fault, fault:
if fault.faultCode == errno.ECONNREFUSED:
print "The IPA XML-RPC service is not responding."

View File

@ -1,13 +1,18 @@
MANDIR = $(DESTDIR)/usr/share/man
MANFILES=\
ipa-adddelegation.1 \
ipa-addgroup.1 \
ipa-adduser.1 \
ipa-deldelegation.1 \
ipa-delgroup.1 \
ipa-deluser.1 \
ipa-findgroup.1 \
ipa-finduser.1 \
ipa-groupmod.1 \
ipa-listdelegation.1 \
ipa-lockuser.1 \
ipa-moddelegation.1 \
ipa-passwd.1 \
ipa-usermod.1

View File

@ -19,20 +19,14 @@
.\"
.TH "ipa-deluser" "1" "Oct 10 2007" "freeipa" ""
.SH "NAME"
ipa\-deluser \- Delete or inactivate a user
ipa\-deluser \- Delete a user
.SH "SYNOPSIS"
ipa\-deluser [\fIOPTION\fR]... \fIuser\fR
ipa\-deluser \fIuser\fR
.SH "DESCRIPTION"
Inactivates a user with login name \fIname\fR.
Deletes a user with login name \fIname\fR.
By default users are not completely removed. They are marked as inactive. Use the [\-d|\-\-delete] option to completely remove them.
Users are automatically removed from groups when they are deleted. The are not when inactivated.
.SH "OPTIONS"
.TP
\fB\-d\fR, \fB\-\-delete
Completely remove the user from the database. The default is to mark the user inactive.
Users are automatically removed from groups when they are deleted.
.SH "EXIT STATUS"
The exit status is 0 on success, nonzero on error.

View File

@ -0,0 +1,36 @@
.\" A man page for ipa-lockuser
.\" Copyright (C) 2007 Red Hat, Inc.
.\"
.\" This is free software; you can redistribute it and/or modify it under
.\" the terms of the GNU Library General Public License as published by
.\" the Free Software Foundation; either version 2 of the License, or
.\" (at your option) any later version.
.\"
.\" This program is distributed in the hope that it will be useful, but
.\" WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
.\" General Public License for more details.
.\"
.\" You should have received a copy of the GNU Library General Public
.\" License along with this program; if not, write to the Free Software
.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
.\"
.\" Author: Rob Crittenden <rcritten@redhat.com>
.\"
.TH "ipa-lockuser" "1" "Oct 10 2007" "freeipa" ""
.SH "NAME"
ipa\-lockuser \- Lock or unlock a user account
.SH "SYNOPSIS"
ipa\-lockuser [\fIOPTION\fR]... \fIuser\fR
.SH "DESCRIPTION"
Locks a user account with login name \fIname\fR.
Users are not removed from groups when their account is locked.
.SH "OPTIONS"
.TP
\fB\-u\fR, \fB\-\-unlock
Unlock a user's account
.SH "EXIT STATUS"
The exit status is 0 on success, nonzero on error.

View File

@ -1,4 +1,4 @@
AC_PREREQ(2.59c)
AC_PREREQ(2.59)
AC_INIT([ipa-client],
[0.5.0],
[https://hosted.fedoraproject.org/projects/freeipa/newticket])

View File

@ -131,8 +131,10 @@ def main():
opts = [{'name':'comment', 'type':'comment', 'value':'File modified by ipa-client-install'},
{'name':'empty', 'type':'empty'}]
defopts.append({'name':'server', 'type':'option', 'value':ds.getServerName()})
defopts.append({'name':'realm', 'type':'option', 'value':ds.getRealmName()})
#[defaults]
defopts = [{'name':'server', 'type':'option', 'value':ds.getServerName()},
{'name':'realm', 'type':'option', 'value':ds.getRealmName()}]
opts.append({'name':'defaults', 'type':'section', 'value':defopts})
opts.append({'name':'empty', 'type':'empty'})

View File

@ -17,6 +17,9 @@ clean:
distclean: clean
maintainer-clean: distclean
rm -rf build
.PHONY: test
test: $(subst .py,.tst,$(TESTS))

View File

@ -162,3 +162,18 @@ CONNECTION_UNWILLING = gen_error_code(
CONNECTION_CATEGORY,
0x0004,
"Account inactivated. Server is unwilling to perform.")
#
# Configuration errors
#
CONFIGURATION_CATEGORY = 0x0004
CONFIG_REQUIRED_GROUPS = gen_error_code(
CONFIGURATION_CATEGORY,
0x0001,
"The admins and editors groups are required.")
CONFIG_DEFAULT_GROUP = gen_error_code(
CONFIGURATION_CATEGORY,
0x0002,
"You cannot remove the default users group.")

View File

@ -36,6 +36,22 @@ from string import lower
import re
import xmlrpclib
import datetime
try:
from subprocess import CalledProcessError
class CalledProcessError(subprocess.CalledProcessError):
def __init__(self, returncode, cmd):
super(CalledProcessError, self).__init__(returncode, cmd)
except ImportError:
# Python 2.4 doesn't implement CalledProcessError
class CalledProcessError(Exception):
"""This exception is raised when a process run by check_call() returns
a non-zero exit status. The exit status will be stored in the
returncode attribute."""
def __init__(self, returncode, cmd):
self.returncode = returncode
self.cmd = cmd
def __str__(self):
return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
def realm_to_suffix(realm_name):
s = realm_name.split(".")
@ -66,7 +82,7 @@ def run(args, stdin=None):
logging.info(stderr)
if p.returncode != 0:
raise subprocess.CalledProcessError(p.returncode, ' '.join(args))
raise self.CalledProcessError(p.returncode, ' '.join(args))
def file_exists(filename):
try:

View File

@ -1,4 +1,4 @@
AC_PREREQ(2.59c)
AC_PREREQ(2.59)
AC_INIT([ipa-server],
[0.5],
[https://hosted.fedoraproject.org/projects/freeipa/newticket])

View File

@ -26,4 +26,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -16,4 +16,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -14,4 +14,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -43,7 +43,7 @@ aci_checkbox_attrs = [(field.name, field.label) for field in aci_attrs]
aci_name_to_label = dict(aci_checkbox_attrs)
class DelegateFields():
class DelegateFields(object):
name = widgets.TextField(name="name", label="Delegation Name")
source_group_dn = widgets.HiddenField(name="source_group_dn")

View File

@ -2,7 +2,7 @@ import turbogears
from turbogears import validators, widgets
from tg_expanding_form_widget.tg_expanding_form_widget import ExpandingForm
class GroupFields():
class GroupFields(object):
cn = widgets.TextField(name="cn", label="Name")
gidnumber = widgets.TextField(name="gidnumber", label="GID")
description = widgets.TextField(name="description", label="Description")

View File

@ -1,9 +1,9 @@
import turbogears
from turbogears import validators, widgets
class IPAPolicyFields():
class IPAPolicyFields(object):
# From cn=ipaConfig
ipausersearchfields = widgets.TextField(name="ipausersearchfields", label="User Search Fields")
ipausersearchfields = widgets.TextField(name="ipausersearchfields", label="User Search Fields", attrs=dict(size=50))
ipagroupsearchfields = widgets.TextField(name="ipagroupsearchfields", label="Group Search Fields")
ipasearchtimelimit = widgets.TextField(name="ipasearchtimelimit", label="Search Time Limit (sec.)", attrs=dict(size=6,maxlength=6))
ipasearchrecordslimit = widgets.TextField(name="ipasearchrecordslimit", label="Search Records Limit", attrs=dict(size=6,maxlength=6))
@ -16,8 +16,8 @@ class IPAPolicyFields():
ipapolicy_orig = widgets.HiddenField(name="ipapolicy_orig")
# From cn=accounts
krbmaxpwdlife = widgets.TextField(name="krbmaxpwdlife", label="Max. Password Lifetime", attrs=dict(size=3,maxlength=3))
krbminpwdlife = widgets.TextField(name="krbminpwdlife", label="Min. Password Lifetime", attrs=dict(size=3,maxlength=3))
krbmaxpwdlife = widgets.TextField(name="krbmaxpwdlife", label="Max. Password Lifetime (days)", attrs=dict(size=3,maxlength=3))
krbminpwdlife = widgets.TextField(name="krbminpwdlife", label="Min. Password Lifetime (hours)", attrs=dict(size=3,maxlength=3))
krbpwdmindiffchars = widgets.TextField(name="krbpwdmindiffchars", label="Min. number of character classes", attrs=dict(size=3,maxlength=3))
krbpwdminlength = widgets.TextField(name="krbpwdminlength", label="Min. Length of password", attrs=dict(size=3,maxlength=3))
krbpwdhistorylength = widgets.TextField(name="krbpwdhistorylength", label="Password History size", attrs=dict(size=3,maxlength=3))

View File

@ -2,7 +2,7 @@ import turbogears
from turbogears import validators, widgets
from tg_expanding_form_widget.tg_expanding_form_widget import ExpandingForm
class UserFields():
class UserFields(object):
givenname = widgets.TextField(name="givenname", label="Given Name")
sn = widgets.TextField(name="sn", label="Family Name")
cn = widgets.TextField(name="cn", label="Common Names")

View File

@ -12,4 +12,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -8,4 +8,5 @@ SUBDIRS = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -11,4 +11,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -24,4 +24,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -11,4 +11,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -17,4 +17,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -17,4 +17,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -16,4 +16,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -104,7 +104,7 @@ class IPAPolicyController(IPAController):
new_ipapolicy = ipa.entity.Entity(orig_ipapolicy_dict)
new_password = ipa.entity.Entity(orig_password_dict)
if str(new_ipapolicy.ipasearchtimelimit) != str(kw.get('ipasearchtimelimit')):
policy_modified = True
new_ipapolicy.setValue('ipasearchtimelimit', kw.get('ipasearchtimelimit'))
@ -158,7 +158,7 @@ class IPAPolicyController(IPAController):
turbogears.flash("IPA Policy updated")
raise turbogears.redirect('/ipapolicy/show')
except ipaerror.IPAError, e:
turbogears.flash("Policy update failed: " + str(e) + e.detail[0]['desc'])
turbogears.flash("Policy update failed: " + str(e) + "<br/>" + e.detail[0]['desc'])
return dict(form=ipapolicy_edit_form, ipapolicy=kw,
tg_template='ipagui.templates.ipapolicyedit')

View File

@ -45,4 +45,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -29,10 +29,10 @@ else:
?>
<div py:if='pw_expires_soon' class="warning_message">
Password will expire in ${pw_expires_days} day${days_suffix}
${user.get("uid")}'s password will expire in ${pw_expires_days} day${days_suffix}
</div>
<div py:if='pw_is_expired' class="warning_message">
Password has expired
${user.get("uid")}'s password has expired
</div>
${form.display(action=tg.url('/user/update'), value=user, user_groups=user_groups)}

View File

@ -28,10 +28,10 @@ else:
?>
<div id="alertbox" py:if='pw_expires_soon' class="warning_message">
Password will expire in ${pw_expires_days} day${days_suffix}
${user.get("uid")}'s password will expire in ${pw_expires_days} day${days_suffix}
</div>
<div id="alertbox" py:if='pw_is_expired' class="warning_message">
Password has expired
${user.get("uid")}'s password has expired
</div>
<h2 class="formsection">Identity Details</h2>

View File

@ -12,4 +12,5 @@ EXTRA_DIST = \
MAINTAINERCLEANFILES = \
*~ \
*.pyc \
Makefile.in

View File

@ -14,7 +14,7 @@ krbMinPwdLife: 3600
krbPwdMinDiffChars: 0
krbPwdMinLength: 8
krbPwdHistoryLength: 0
krbMaxPwdLife: 864000
krbMaxPwdLife: 7776000
dn: cn=users,cn=accounts,$SUFFIX
changetype: add
@ -34,6 +34,12 @@ objectClass: top
objectClass: nsContainer
cn: services
dn: cn=computers,cn=accounts,$SUFFIX
changetype: add
objectClass: top
objectClass: nsContainer
cn: computers
dn: cn=etc,$SUFFIX
changetype: add
objectClass: nsContainer
@ -143,6 +149,7 @@ ipaMaxUsernameLength: 8
ipaPwdExpAdvNotify: 4
dn: cn=account inactivation,cn=accounts,$SUFFIX
changetype: add
description: Lock accounts based on group membership
objectClass: top
objectClass: ldapsubentry
@ -154,11 +161,13 @@ cosSpecifier: memberOf
cn: Account Inactivation
dn: cn=cosTemplates,cn=accounts,$SUFFIX
changetype: add
objectclass: top
objectclass: nsContainer
cn: cosTemplates
dn: cn="cn=inactivated,cn=account inactivation,cn=accounts,$SUFFIX", cn=cosTemplates,cn=accounts,$SUFFIX
changetype: add
objectClass: top
objectClass: cosTemplate
objectClass: extensibleobject
@ -166,10 +175,12 @@ nsAccountLock: true
cosPriority: 1
dn: cn=inactivated,cn=account inactivation,cn=accounts,$SUFFIX
changetype: add
objectclass: top
objectclass: groupofnames
dn: cn="cn=activated,cn=account inactivation,cn=accounts,$SUFFIX", cn=cosTemplates,cn=accounts,$SUFFIX
changetype: add
objectClass: top
objectClass: cosTemplate
objectClass: extensibleobject
@ -177,5 +188,6 @@ nsAccountLock: false
cosPriority: 0
dn: cn=Activated,cn=Account Inactivation,cn=accounts,$SUFFIX
changetype: add
objectclass: top
objectclass: groupofnames

View File

@ -1,20 +1,23 @@
# $SUFFIX (base entry)
# FIXME: We need to allow truly anonymous access only to NIS data for older clients. We need to allow broad access to most attributes only to authewnticated users
dn: $SUFFIX
changetype: modify
replace: aci
aci: (targetattr!="userPassword || krbPrincipalKey ||sambaLMPassword || sambaNTPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn="ldap:///anyone";)
aci: (targetattr=*)(version 3.0; acl "Admin can manage any entry"; allow (all) userdn="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr="krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr="krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr="userPassword || krbPrincipalKey ||sambaLMPassword || sambaNTPassword || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange")(version 3.0; acl "Kpasswd access to passowrd hashes for passowrd changes"; allow (read, write) userdn="ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
aci: (targetfilter="(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup)(objectClass=radiusprofile))")(targetattr="*")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add,delete,read,write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso || userPassword")(version 3.0;acl "Self service";allow (write) userdn="ldap:///self";)
aci: (target="ldap:///cn=radius,cn=services,cn=etc,$SUFFIX")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
aci: (targetattr != "userPassword || krbPrincipalKey || krbMKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Enable anonymous access"; allow (read, search, compare) userdn = "ldap:///anyone";)
aci: (targetattr != "userPassword || krbPrincipalKey || krbMKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Admin can manage any entry except for passwords"; allow (all) userdn = "ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword")(version 3.0; acl "Admin can write passwords"; allow (write) userdn="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr = "krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account has access to kerberos material"; allow (read, search, compare) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr = "krbLastSuccessfulAuth || krbLastFailedAuth || krbLoginFailedCount")(version 3.0; acl "KDC System Account can update some fields"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr = "userPassword || krbPrincipalKey ||sambaLMPassword || sambaNTPassword || krbPasswordExpiration || krbPwdHistory || krbLastPwdChange")(version 3.0; acl "Kpasswd access to passowrd hashes for passowrd changes"; allow (read, write) userdn = "ldap:///krbprincipalname=kadmin/changepw@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
aci: (targetfilter = "(|(objectClass=person)(objectClass=krbPrincipalAux)(objectClass=posixAccount)(objectClass=groupOfNames)(objectClass=posixGroup)(objectClass=radiusprofile))")(targetattr != "aci")(version 3.0; acl "Account Admins can manage Users and Groups"; allow (add, delete, read, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetfilter = "(objectClass=krbPwdPolicy)")(targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbPwdMinLength || krbPwdHistoryLength")(version 3.0;acl "Admins can write password policies"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetattr = "givenName || sn || cn || displayName || initials || loginShell || homePhone || mobile || pager || facsimileTelephoneNumber || telephoneNumber || street || roomNumber || l || st || postalCode || manager || description || carLicense || labeledURI || inetUserHTTPURL || seeAlso")(version 3.0;acl "Self service";allow (write) userdn = "ldap:///self";)
aci: (target="ldap:///cn=radius,$SUFFIX")(version 3.0; acl "Only radius and admin can access radius service data"; deny (all) userdn!="ldap:///uid=admin,cn=sysaccounts,cn=etc,$SUFFIX || ldap:///krbprincipalname=radius/$FQDN@$REALM,cn=$REALM,cn=kerberos,$SUFFIX";)
dn: cn=ipaConfig,cn=etc,$SUFFIX
changetype: modify
add: aci
aci: (targetattr = "ipaUserSearchFields || ipaGroupSearchFields || ipaSearchTimeLimit || ipaSearchRecordsLimit || ipaCustomFields || ipaHomesRootDir || ipaDefaultLoginShell || ipaDefaultPrimaryGroup || ipaMaxUsernameLength || ipaPwdExpAdvNotify")(version 3.0;acl "Admins can write IPA policy"; allow (write) groupdn="ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
aci: (targetfilter = "(objectClass=ipaGuiConfig)")(targetattr != "aci")(version 3.0;acl "Admins can change GUI config"; allow (read, search, compare, write) groupdn = "ldap:///cn=admins,cn=groups,cn=accounts,$SUFFIX";)
dn: cn=accounts,$SUFFIX
changetype: modify
@ -24,4 +27,4 @@ aci: (targetattr = "krbMaxPwdLife || krbMinPwdLife || krbPwdMinDiffChars || krbP
dn: cn=services,cn=accounts,$SUFFIX
changetype: modify
add: aci
aci: (targetattr="krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbMKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account"; allow (read, search, compare,write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)
aci: (targetattr="krbPrincipalName || krbUPEnabled || krbPrincipalKey || krbTicketPolicyReference || krbPrincipalExpiration || krbPasswordExpiration || krbPwdPolicyReference || krbPrincipalType || krbPwdHistory || krbLastPwdChange || krbPrincipalAliases || krbExtraData")(version 3.0; acl "KDC System Account"; allow (read, search, compare, write) userdn="ldap:///uid=kdc,cn=sysaccounts,cn=etc,$SUFFIX";)

View File

@ -15,6 +15,7 @@ BuildRequires: openssl-devel
BuildRequires: openldap-devel
BuildRequires: krb5-devel
BuildRequires: nss-devel
BuildRequires: libcap-devel
Requires: ipa-python
Requires: ipa-admintools
@ -38,6 +39,7 @@ Requires: python-tgexpandingformwidget
Requires: acl
Requires: freeradius
Requires: pyasn1
Requires: libcap
%define httpd_conf /etc/httpd/conf.d
%define plugin_dir %{_libdir}/dirsrv/plugins

View File

@ -93,11 +93,7 @@
/* OID of the extended operation handled by this plug-in */
#define EXOP_PASSWD_OID "1.3.6.1.4.1.4203.1.11.1"
/* These are thye default enc:salt ypes if nothing is defined.
* TODO: retrieve the configure set of ecntypes either from the
* kfc.conf file or by synchronizing the the file content into
* the directory */
/* krbTicketFlags */
#define KTF_DISALLOW_POSTDATED 0x00000001
#define KTF_DISALLOW_FORWARDABLE 0x00000002
#define KTF_DISALLOW_TGT_BASED 0x00000004
@ -111,6 +107,11 @@
#define KTF_DISALLOW_SVR 0x00001000
#define KTF_PWCHANGE_SERVICE 0x00002000
/* These are the default enc:salt types if nothing is defined.
* TODO: retrieve the configure set of ecntypes either from the
* kfc.conf file or by synchronizing the the file content into
* the directory */
/* Salt types */
#define KRB5_KDB_SALTTYPE_NORMAL 0
#define KRB5_KDB_SALTTYPE_V4 1
@ -1061,6 +1062,7 @@ static int ipapwd_CheckPolicy(struct ipapwd_data *data)
{
const char *krbPrincipalExpiration;
const char *krbLastPwdChange;
const char *krbPasswordExpiration;
int krbMaxPwdLife = IPAPWD_DEFAULT_PWDLIFE;
int krbPwdMinLength = IPAPWD_DEFAULT_MINLEN;
int krbPwdMinDiffChars = 0;
@ -1105,6 +1107,7 @@ static int ipapwd_CheckPolicy(struct ipapwd_data *data)
goto no_policy;
}
krbPasswordExpiration = slapi_entry_attr_get_charptr(data->target, "krbPasswordExpiration");
krbLastPwdChange = slapi_entry_attr_get_charptr(data->target, "krbLastPwdChange");
/* if no previous change, it means this is probably a new account
* or imported, log and just ignore */
@ -1138,9 +1141,17 @@ static int ipapwd_CheckPolicy(struct ipapwd_data *data)
/* if no default then treat it as no limit */
if (krbMinPwdLife != 0) {
if (data->timeNow < data->lastPwChange + krbMinPwdLife) {
/* check for reset cases */
if (strcmp(krbPasswordExpiration, krbLastPwdChange) == 0) {
/* Expiration and last change time are the same
* this happens only when a password is reset by an admin
* or no expiration policy is set, PASS */
slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
"ipapwd_checkPassword: Too soon to change password\n");
"ipapwd_checkPolicy: Ignore krbMinPwdLife Expiration and Last change dates match\n");
} else if (data->timeNow < data->lastPwChange + krbMinPwdLife) {
slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
"ipapwd_checkPolicy: Too soon to change password\n");
slapi_entry_free(policy);
return IPAPWD_POLICY_ERROR | LDAP_PWPOLICY_PWDTOOYOUNG;
}
@ -1424,8 +1435,8 @@ static int ipapwd_SetPassword(struct ipapwd_data *data)
{
int ret = 0, i = 0;
Slapi_Mods *smods;
Slapi_Value **svals;
Slapi_Value **pwvals;
Slapi_Value **svals = NULL;
Slapi_Value **pwvals = NULL;
struct tm utctime;
char timestr[GENERALIZED_TIME_LENGTH+1];
krb5_context krbctx;
@ -1608,17 +1619,6 @@ static int ipapwd_extop(Slapi_PBlock *pb)
slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop", "=> ipapwd_extop\n");
/* make sure we have the master key */
if (ipa_kmkey == NULL) {
ret = ipapwd_getMasterKey(ipa_realm_dn);
if (ret != LDAP_SUCCESS) {
errMesg = "Fatal Internal Error Retrieving Master Key";
rc = LDAP_OPERATIONS_ERROR;
slapi_log_error( SLAPI_LOG_PLUGIN, "ipa_pwd_extop", errMesg );
goto free_and_return;
}
}
/* Before going any further, we'll make sure that the right extended operation plugin
* has been called: i.e., the OID shipped whithin the extended operation request must
* match this very plugin's OID: EXOP_PASSWD_OID. */
@ -1641,9 +1641,19 @@ static int ipapwd_extop(Slapi_PBlock *pb)
slapi_log_error( SLAPI_LOG_PLUGIN, "ipa_pwd_extop",
"Password Modify extended operation request confirmed.\n" );
}
/* Now , at least we know that the request was indeed a Password Modify one. */
/* make sure we have the master key */
if (ipa_kmkey == NULL) {
ret = ipapwd_getMasterKey(ipa_realm_dn);
if (ret != LDAP_SUCCESS) {
errMesg = "Fatal Internal Error Retrieving Master Key";
rc = LDAP_OPERATIONS_ERROR;
slapi_log_error( SLAPI_LOG_PLUGIN, "ipa_pwd_extop", errMesg );
goto free_and_return;
}
}
#ifdef LDAP_EXTOP_PASSMOD_CONN_SECURE
/* Allow password modify only for SSL/TLS established connections and
* connections using SASL privacy layers */
@ -1824,7 +1834,7 @@ parse_req_done:
slapi_pblock_set(pb, SLAPI_BACKEND, be);
}
ret = slapi_access_allowed ( pb, targetEntry, SLAPI_USERPWD_ATTR, NULL, SLAPI_ACL_WRITE );
ret = slapi_access_allowed ( pb, targetEntry, "krbPrincipalKey", NULL, SLAPI_ACL_WRITE );
if ( ret != LDAP_SUCCESS ) {
errMesg = "Insufficient access rights\n";
rc = LDAP_INSUFFICIENT_ACCESS;
@ -2140,7 +2150,6 @@ static int ipapwd_start( Slapi_PBlock *pb )
/*retrieve the master key from the stash file */
if (slapi_pblock_get(pb, SLAPI_TARGET_DN, &config_dn) != 0) {
slapi_log_error( SLAPI_LOG_FATAL, "ipapwd_start", "No config DN?\n");
krb5_free_context(krbctx);
free(keysalts);
free(realm);
return LDAP_OPERATIONS_ERROR;
@ -2148,7 +2157,6 @@ static int ipapwd_start( Slapi_PBlock *pb )
if (ipapwd_getEntry(config_dn, &config_entry, NULL) != LDAP_SUCCESS) {
slapi_log_error( SLAPI_LOG_FATAL, "ipapwd_start", "No config Entry?\n");
krb5_free_context(krbctx);
free(keysalts);
free(realm);
return LDAP_OPERATIONS_ERROR;
@ -2208,7 +2216,7 @@ int ipapwd_init( Slapi_PBlock *pb )
slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) ipapwd_start ) != 0 ||
slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *) ipapwd_extop ) != 0 ||
slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, ipapwd_oid_list ) != 0 ||
slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, ipapwd_name_list ) != 0 ) {
slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, ipapwd_name_list ) != 0) {
slapi_log_error( SLAPI_LOG_PLUGIN, "ipapwd_init",
"Failed to set plug-in version, function, and OID.\n" );

View File

@ -8,7 +8,7 @@ nsslapd-pluginpath: libipa_pwd_extop
nsslapd-plugininitfunc: ipapwd_init
nsslapd-plugintype: extendedop
nsslapd-pluginenabled: on
nsslapd-pluginid: Multi-hash Change Password Extended Operation
nsslapd-pluginid: ipa_pwd_extop
nsslapd-pluginversion: 1.0
nsslapd-pluginvendor: RedHat
nsslapd-plugindescription: Support saving passwords in multiple formats for different consumers (krb5, samba, freeradius, etc.)

View File

@ -29,7 +29,6 @@ import sys
from ipa.ipautil import *
import service
import installutils
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
@ -188,7 +187,7 @@ class DsInstance(service.Service):
try:
run(args)
logging.debug("done adding user")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("failed to add user %s" % e)
def __create_instance(self):
@ -206,13 +205,13 @@ class DsInstance(service.Service):
try:
run(args)
logging.debug("completed creating ds instance")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("failed to restart ds instance %s" % e)
logging.debug("restarting ds instance")
try:
self.restart()
logging.debug("done restarting ds instance")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "failed to restart ds instance", e
logging.debug("failed to restart ds instance %s" % e)
@ -233,7 +232,7 @@ class DsInstance(service.Service):
memberof_fd = write_tmp_file(memberof_txt)
try:
ldap_mod(memberof_fd, "cn=Directory Manager", self.dm_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to load memberof-conf.ldif: %s" % str(e))
memberof_fd.close()
@ -243,7 +242,7 @@ class DsInstance(service.Service):
memberof_fd = write_tmp_file(memberof_txt)
try:
ldap_mod(memberof_fd, "cn=Directory Manager", self.dm_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to load memberof-conf.ldif: %s" % str(e))
memberof_fd.close()
@ -253,7 +252,7 @@ class DsInstance(service.Service):
referint_fd = write_tmp_file(referint_txt)
try:
ldap_mod(referint_fd, "cn=Directory Manager", self.dm_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Failed to load referint-conf.ldif", e
referint_fd.close()
@ -263,7 +262,7 @@ class DsInstance(service.Service):
dna_fd = write_tmp_file(dna_txt)
try:
ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Failed to load dna-conf.ldif", e
dna_fd.close()
@ -273,7 +272,7 @@ class DsInstance(service.Service):
dna_fd = write_tmp_file(dna_txt)
try:
ldap_mod(dna_fd, "cn=Directory Manager", self.dm_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Failed to configure Posix uid/gid generation with dna-posix.ldif", e
dna_fd.close()
@ -283,7 +282,7 @@ class DsInstance(service.Service):
master_fd = write_tmp_file(master_txt)
try:
ldap_mod(master_fd, "cn=Directory Manager", self.dm_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Failed to add master-entry.ldif", e
master_fd.close()
@ -295,7 +294,7 @@ class DsInstance(service.Service):
try:
run(args)
logging.debug("done configuring ssl for ds instance")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to configure ssl in ds instance %s" % e)
def __add_default_layout(self):
@ -308,7 +307,7 @@ class DsInstance(service.Service):
try:
run(args)
logging.debug("done adding default ds layout")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Failed to add default ds layout", e
logging.critical("Failed to add default ds layout %s" % e)
@ -322,7 +321,7 @@ class DsInstance(service.Service):
try:
run(args)
logging.debug("done adding/updating indeces")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to add/update indeces %s" % str(e))
def __certmap_conf(self):
@ -347,7 +346,7 @@ class DsInstance(service.Service):
try:
run(args)
logging.debug("ldappasswd done")
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Unable to set admin password", e
logging.debug("Unable to set admin password %s" % e)

View File

@ -86,7 +86,7 @@ class HTTPInstance(service.Service):
if (os.path.exists('/usr/sbin/selinuxenabled')):
run(["/usr/sbin/selinuxenabled"])
selinux=1
except subprocess.CalledProcessError:
except ipautil.CalledProcessError:
# selinuxenabled returns 1 if not enabled
pass

View File

@ -33,7 +33,6 @@ import time
import shutil
import service
from ipa.ipautil import *
from ipa import ipaerror
import ipaldap
@ -47,6 +46,7 @@ import pyasn1.codec.ber.encoder
import pyasn1.codec.ber.decoder
import struct
import base64
from ipa.ipautil import *
def host_to_domain(fqdn):
s = fqdn.split(".")
@ -89,7 +89,7 @@ class KrbInstance(service.Service):
self.host = host_name.split(".")[0]
self.ip = socket.gethostbyname(host_name)
self.domain = host_to_domain(host_name)
self.suffix = realm_to_suffix(self.realm)
self.suffix = realm_to_suffix(self.realm)
self.kdc_password = ipa_generate_password()
self.admin_password = admin_password
@ -133,7 +133,7 @@ class KrbInstance(service.Service):
self.start_creation(11, "Configuring Kerberos KDC")
self.__configure_kdc_account_password()
self.__configure_kdc_account_password()
self.__configure_sasl_mappings()
self.__add_krb_entries()
self.__create_instance()
@ -245,7 +245,7 @@ class KrbInstance(service.Service):
kerberos_fd = write_tmp_file(kerberos_txt)
try:
ldap_mod(kerberos_fd, "cn=Directory Manager", self.admin_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to load kerberos.ldif: %s" % str(e))
kerberos_fd.close()
@ -254,7 +254,7 @@ class KrbInstance(service.Service):
aci_fd = write_tmp_file(aci_txt)
try:
ldap_mod(aci_fd, "cn=Directory Manager", self.admin_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to load default-aci.ldif: %s" % str(e))
aci_fd.close()
@ -291,7 +291,7 @@ class KrbInstance(service.Service):
args = ["/usr/kerberos/sbin/kdb5_ldap_util", "-D", "uid=kdc,cn=sysaccounts,cn=etc,"+self.suffix, "-w", self.kdc_password, "create", "-s", "-P", self.master_password, "-r", self.realm, "-subtrees", self.suffix, "-sscope", "sub"]
try:
run(args)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
print "Failed to populate the realm structure in kerberos", e
def __write_stash_from_ds(self):
@ -322,7 +322,7 @@ class KrbInstance(service.Service):
extop_fd = write_tmp_file(extop_txt)
try:
ldap_mod(extop_fd, "cn=Directory Manager", self.admin_password)
except subprocess.CalledProcessError, e:
except ipautil.CalledProcessError, e:
logging.critical("Failed to load pwd-extop-conf.ldif: %s" % str(e))
extop_fd.close()

View File

@ -332,7 +332,7 @@ class IPAServer:
# Higher-level API
def get_aci_entry(self, sattrs=None, opts=None):
def get_aci_entry(self, sattrs, opts=None):
"""Returns the entry containing access control ACIs."""
dn="%s,%s" % (ACIContainer, self.basedn)
@ -340,7 +340,7 @@ class IPAServer:
# General searches
def get_entry_by_dn (self, dn, sattrs=None, opts=None):
def get_entry_by_dn (self, dn, sattrs, opts=None):
"""Get a specific entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
@ -348,7 +348,7 @@ class IPAServer:
filter = "(objectClass=*)"
return self.__get_base_entry(dn, filter, sattrs, opts)
def get_entry_by_cn (self, cn, sattrs=None, opts=None):
def get_entry_by_cn (self, cn, sattrs, opts=None):
"""Get a specific entry by cn. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
@ -374,7 +374,7 @@ class IPAServer:
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return 1
def get_user_by_uid (self, uid, sattrs=None, opts=None):
def get_user_by_uid (self, uid, sattrs, opts=None):
"""Get a specific user's entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
@ -383,7 +383,7 @@ class IPAServer:
filter = "(uid=" + uid + ")"
return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
def get_user_by_principal(self, principal, sattrs=None, opts=None):
def get_user_by_principal(self, principal, sattrs, opts=None):
"""Get a user entry searching by Kerberos Principal Name.
Return as a dict of values. Multi-valued fields are
represented as lists.
@ -392,7 +392,7 @@ class IPAServer:
filter = "(krbPrincipalName="+self.__safe_filter(principal)+")"
return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
def get_user_by_email (self, email, sattrs=None, opts=None):
def get_user_by_email (self, email, sattrs, opts=None):
"""Get a specific user's entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
@ -401,7 +401,7 @@ class IPAServer:
filter = "(mail=" + email + ")"
return self.__get_sub_entry(self.basedn, filter, sattrs, opts)
def get_users_by_manager (self, manager_dn, sattrs=None, opts=None):
def get_users_by_manager (self, manager_dn, sattrs, opts=None):
"""Gets the users that report to a particular manager.
"""
@ -413,12 +413,12 @@ class IPAServer:
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return []
def add_user (self, user, user_container=None, opts=None):
def add_user (self, user, user_container, opts=None):
"""Add a user in LDAP. Takes as input a dict where the key is the
attribute name and the value is either a string or in the case
of a multi-valued field a list of values. user_container sets
where in the tree the user is placed."""
if user_container is None:
if not user_container:
user_container = DefaultUserContainer
if self.__is_user_unique(user['uid'], opts) == 0:
@ -738,7 +738,7 @@ class IPAServer:
return self.update_entry(config, new_config, opts)
def get_all_users (self, args=None, opts=None):
def get_all_users (self, opts=None):
"""Return a list containing a User object for each
existing user.
"""
@ -756,7 +756,7 @@ class IPAServer:
return users
def find_users (self, criteria, sattrs=None, searchlimit=-1, timelimit=-1,
def find_users (self, criteria, sattrs, searchlimit=-1, timelimit=-1,
opts=None):
"""Returns a list: counter followed by the results.
If the results are truncated, counter will be set to -1."""
@ -1002,7 +1002,7 @@ class IPAServer:
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return 1
def get_groups_by_member (self, member_dn, sattrs=None, opts=None):
def get_groups_by_member (self, member_dn, sattrs, opts=None):
"""Get a specific group's entry. Return as a dict of values.
Multi-valued fields are represented as lists.
"""
@ -1015,12 +1015,12 @@ class IPAServer:
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
return []
def add_group (self, group, group_container=None, opts=None):
def add_group (self, group, group_container, opts=None):
"""Add a group in LDAP. Takes as input a dict where the key is the
attribute name and the value is either a string or in the case
of a multi-valued field a list of values. group_container sets
where in the tree the group is placed."""
if group_container is None:
if not group_container:
group_container = DefaultGroupContainer
if self.__is_group_unique(group['cn'], opts) == 0:
@ -1047,7 +1047,7 @@ class IPAServer:
finally:
self.releaseConnection(conn)
def find_groups (self, criteria, sattrs=None, searchlimit=-1, timelimit=-1,
def find_groups (self, criteria, sattrs, searchlimit=-1, timelimit=-1,
opts=None):
"""Return a list containing a User object for each
existing group that matches the criteria.
@ -1396,6 +1396,16 @@ class IPAServer:
if group is None:
raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND)
# We have 2 special groups, don't allow them to be removed
if "admins" in group.get('cn') or "editors" in group.get('cn'):
raise ipaerror.gen_exception(ipaerror.CONFIG_REQUIRED_GROUPS)
# Don't allow the default user group to be removed
config=self.get_ipa_config(opts)
default_group = self.get_entry_by_cn(config.get('ipadefaultprimarygroup'), None, opts)
if group_dn == default_group.get('dn'):
raise ipaerror.gen_exception(ipaerror.CONFIG_DEFAULT_GROUP)
conn = self.getConnection(opts)
try:
res = conn.deleteEntry(group_dn)
@ -1455,11 +1465,12 @@ class IPAServer:
conn = self.getConnection(opts)
try:
results = conn.getListAsync(self.basedn, self.scope,
filter, attr_list, 0, None, None, timelimit,
searchlimit)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
results = [0]
try:
results = conn.getListAsync(self.basedn, self.scope,
filter, attr_list, 0, None, None, timelimit,
searchlimit)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
results = [0]
finally:
self.releaseConnection(conn)
@ -1565,14 +1576,22 @@ class IPAServer:
# The LDAP routines want strings, not ints, so convert a few
# things. Otherwise it sees a string -> int conversion as a change.
try:
newconfig['krbmaxpwdlife'] = str(newconfig.get('krbmaxpwdlife'))
newconfig['krbminpwdlife'] = str(newconfig.get('krbminpwdlife'))
newconfig['krbpwdmindiffchars'] = str(newconfig.get('krbpwdmindiffchars'))
newconfig['krbpwdminlength'] = str(newconfig.get('krbpwdminlength'))
newconfig['krbpwdhistorylength'] = str(newconfig.get('krbpwdhistorylength'))
newconfig['ipapwdexpadvnotify'] = str(newconfig.get('ipapwdexpadvnotify'))
newconfig['ipasearchtimelimit'] = str(newconfig.get('ipasearchtimelimit'))
newconfig['ipasearchrecordslimit'] = str(newconfig.get('ipasearchrecordslimit'))
newconfig['ipamaxusernamelength'] = str(newconfig.get('ipamaxusernamelength'))
except KeyError:
# These should all be there but if not, let things proceed
pass
# Ensure that the default group for users exists
try:
group = self.get_entry_by_cn(newconfig.get('ipadefaultprimarygroup'), None, opts)
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
raise
except:
raise
return self.update_entry(oldconfig, newconfig, opts)
def get_password_policy(self, opts=None):
@ -1582,6 +1601,10 @@ class IPAServer:
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
raise ipaerror.gen_exception(ipaerror.LDAP_NO_CONFIG)
# convert some values for display purposes
policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) / 86400)
policy['krbminpwdlife'] = str(int(policy.get('krbminpwdlife')) / 3600)
return policy
def update_password_policy(self, oldpolicy, newpolicy, opts=None):
@ -1590,14 +1613,24 @@ class IPAServer:
# The LDAP routines want strings, not ints, so convert a few
# things. Otherwise it sees a string -> int conversion as a change.
try:
newpolicy['krbmaxpwdlife'] = str(newpolicy.get('krbmaxpwdlife'))
newpolicy['krbminpwdlife'] = str(newpolicy.get('krbminpwdlife'))
newpolicy['krbpwdhistorylength'] = str(newpolicy.get('krbpwdhistorylength'))
newpolicy['krbpwdmindiffchars'] = str(newpolicy.get('krbpwdmindiffchars'))
newpolicy['krbpwdminlength'] = str(newpolicy.get('krbpwdminlength'))
for k in oldpolicy.iterkeys():
if k.startswith("krb", 0, 3):
oldpolicy[k] = str(oldpolicy[k])
for k in newpolicy.iterkeys():
if k.startswith("krb", 0, 3):
newpolicy[k] = str(newpolicy[k])
# Convert hours and days to seconds
oldpolicy['krbmaxpwdlife'] = str(int(oldpolicy.get('krbmaxpwdlife')) * 86400)
oldpolicy['krbminpwdlife'] = str(int(oldpolicy.get('krbminpwdlife')) * 3600)
newpolicy['krbmaxpwdlife'] = str(int(newpolicy.get('krbmaxpwdlife')) * 86400)
newpolicy['krbminpwdlife'] = str(int(newpolicy.get('krbminpwdlife')) * 3600)
except KeyError:
# These should all be there but if not, let things proceed
pass
except:
# Anything else raise an error
raise
return self.update_entry(oldpolicy, newpolicy, opts)