summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2013-01-08 04:10:35 -0500
committerMartin Kosek <mkosek@redhat.com>2013-03-11 17:07:07 +0100
commit91606e6679f3a18b1c1789efd240eed982a563d4 (patch)
treea002e8fbc837058f6c1d9178cbefadcd03b7d6f2
parent8d432353cc1e66b235e928650764f879c24d19f7 (diff)
downloadfreeipa-91606e6679f3a18b1c1789efd240eed982a563d4.tar.gz
freeipa-91606e6679f3a18b1c1789efd240eed982a563d4.tar.xz
freeipa-91606e6679f3a18b1c1789efd240eed982a563d4.zip
Change DNA magic value to -1 to make UID 999 usable
Change user-add's uid & gid parameters from autofill to optional. Change the DNA magic value to -1. For old clients, which will still send 999 when they want DNA assignment, translate the 999 to -1. This is done via a new capability, optional_uid_params. Tests included https://fedorahosted.org/freeipa/ticket/2886
-rw-r--r--API.txt13
-rw-r--r--VERSION2
-rw-r--r--daemons/ipa-sam/ipa_sam.c2
-rw-r--r--daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif4
-rw-r--r--install/share/default-smb-group.ldif2
-rw-r--r--install/share/dna.ldif2
-rw-r--r--install/updates/20-dna.update10
-rw-r--r--ipalib/capabilities.py6
-rw-r--r--ipalib/plugins/baseldap.py2
-rw-r--r--ipalib/plugins/group.py5
-rw-r--r--ipalib/plugins/user.py34
-rw-r--r--tests/test_install/1_add.update4
-rw-r--r--tests/test_xmlrpc/test_user_plugin.py86
13 files changed, 144 insertions, 28 deletions
diff --git a/API.txt b/API.txt
index 5ddda6371..734f99e36 100644
--- a/API.txt
+++ b/API.txt
@@ -3416,7 +3416,7 @@ option: Str('cn', attribute=True, autofill=True, cli_name='cn', multivalue=False
option: Str('displayname', attribute=True, autofill=True, cli_name='displayname', multivalue=False, required=False)
option: Str('facsimiletelephonenumber', attribute=True, cli_name='fax', multivalue=True, required=False)
option: Str('gecos', attribute=True, autofill=True, cli_name='gecos', multivalue=False, required=False)
-option: Int('gidnumber', attribute=True, autofill=True, cli_name='gidnumber', default=999, minvalue=1, multivalue=False, required=True)
+option: Int('gidnumber', attribute=True, cli_name='gidnumber', minvalue=1, multivalue=False, required=False)
option: Str('givenname', attribute=True, cli_name='first', multivalue=False, required=True)
option: Str('homedirectory', attribute=True, cli_name='homedir', multivalue=False, required=False)
option: Str('initials', attribute=True, autofill=True, cli_name='initials', multivalue=False, required=False)
@@ -3440,7 +3440,7 @@ option: Str('st', attribute=True, cli_name='state', multivalue=False, required=F
option: Str('street', attribute=True, cli_name='street', multivalue=False, required=False)
option: Str('telephonenumber', attribute=True, cli_name='phone', multivalue=True, required=False)
option: Str('title', attribute=True, cli_name='title', multivalue=False, required=False)
-option: Int('uidnumber', attribute=True, autofill=True, cli_name='uid', default=999, minvalue=1, multivalue=False, required=True)
+option: Int('uidnumber', attribute=True, cli_name='uid', minvalue=1, multivalue=False, required=False)
option: Password('userpassword', attribute=True, cli_name='password', exclude='webui', multivalue=False, required=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
@@ -3477,7 +3477,7 @@ option: Str('cn', attribute=True, autofill=False, cli_name='cn', multivalue=Fals
option: Str('displayname', attribute=True, autofill=False, cli_name='displayname', multivalue=False, query=True, required=False)
option: Str('facsimiletelephonenumber', attribute=True, autofill=False, cli_name='fax', multivalue=True, query=True, required=False)
option: Str('gecos', attribute=True, autofill=False, cli_name='gecos', multivalue=False, query=True, required=False)
-option: Int('gidnumber', attribute=True, autofill=False, cli_name='gidnumber', default=999, minvalue=1, multivalue=False, query=True, required=False)
+option: Int('gidnumber', attribute=True, autofill=False, cli_name='gidnumber', minvalue=1, multivalue=False, query=True, required=False)
option: Str('givenname', attribute=True, autofill=False, cli_name='first', multivalue=False, query=True, required=False)
option: Str('homedirectory', attribute=True, autofill=False, cli_name='homedir', multivalue=False, query=True, required=False)
option: Str('in_group*', cli_name='in_groups', csv=True)
@@ -3511,7 +3511,7 @@ option: Str('telephonenumber', attribute=True, autofill=False, cli_name='phone',
option: Int('timelimit?', autofill=False, minvalue=0)
option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, query=True, required=False)
option: Str('uid', attribute=True, autofill=False, cli_name='login', maxlength=255, multivalue=False, pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', primary_key=True, query=True, required=False)
-option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', default=999, minvalue=1, multivalue=False, query=True, required=False)
+option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, query=True, required=False)
option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, query=True, required=False)
option: Str('version?', exclude='webui')
option: Flag('whoami', autofill=True, default=False)
@@ -3530,7 +3530,7 @@ option: Str('delattr*', cli_name='delattr', exclude='webui')
option: Str('displayname', attribute=True, autofill=False, cli_name='displayname', multivalue=False, required=False)
option: Str('facsimiletelephonenumber', attribute=True, autofill=False, cli_name='fax', multivalue=True, required=False)
option: Str('gecos', attribute=True, autofill=False, cli_name='gecos', multivalue=False, required=False)
-option: Int('gidnumber', attribute=True, autofill=False, cli_name='gidnumber', default=999, minvalue=1, multivalue=False, required=False)
+option: Int('gidnumber', attribute=True, autofill=False, cli_name='gidnumber', minvalue=1, multivalue=False, required=False)
option: Str('givenname', attribute=True, autofill=False, cli_name='first', multivalue=False, required=False)
option: Str('homedirectory', attribute=True, autofill=False, cli_name='homedir', multivalue=False, required=False)
option: Str('initials', attribute=True, autofill=False, cli_name='initials', multivalue=False, required=False)
@@ -3554,7 +3554,7 @@ option: Str('st', attribute=True, autofill=False, cli_name='state', multivalue=F
option: Str('street', attribute=True, autofill=False, cli_name='street', multivalue=False, required=False)
option: Str('telephonenumber', attribute=True, autofill=False, cli_name='phone', multivalue=True, required=False)
option: Str('title', attribute=True, autofill=False, cli_name='title', multivalue=False, required=False)
-option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', default=999, minvalue=1, multivalue=False, required=False)
+option: Int('uidnumber', attribute=True, autofill=False, cli_name='uid', minvalue=1, multivalue=False, required=False)
option: Password('userpassword', attribute=True, autofill=False, cli_name='password', exclude='webui', multivalue=False, required=False)
option: Str('version?', exclude='webui')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
@@ -3588,3 +3588,4 @@ output: Output('result', <type 'bool'>, None)
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Output('value', <type 'unicode'>, None)
capability: messages 2.52
+capability: optional_uid_params 2.54
diff --git a/VERSION b/VERSION
index 65bef341b..4108bc808 100644
--- a/VERSION
+++ b/VERSION
@@ -89,4 +89,4 @@ IPA_DATA_VERSION=20100614120000
# #
########################################################
IPA_API_VERSION_MAJOR=2
-IPA_API_VERSION_MINOR=53
+IPA_API_VERSION_MINOR=54
diff --git a/daemons/ipa-sam/ipa_sam.c b/daemons/ipa-sam/ipa_sam.c
index b9fc00c8d..dd3ad617b 100644
--- a/daemons/ipa-sam/ipa_sam.c
+++ b/daemons/ipa-sam/ipa_sam.c
@@ -101,7 +101,7 @@ bool secrets_store(const char *key, const void *data, size_t size); /* available
#define IPA_KEYTAB_SET_OID "2.16.840.1.113730.3.8.10.1"
#define IPA_KEYTAB_SET_OID_OLD "2.16.840.1.113730.3.8.3.1"
-#define IPA_MAGIC_ID_STR "999"
+#define IPA_MAGIC_ID_STR "-1"
#define LDAP_ATTRIBUTE_CN "cn"
#define LDAP_ATTRIBUTE_UID "uid"
diff --git a/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif b/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif
index b646c2b10..08b43277f 100644
--- a/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif
+++ b/daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif
@@ -24,5 +24,5 @@ ipaWinSyncDefaultGroupAttr: ipaDefaultPrimaryGroup
ipaWinSyncDefaultGroupFilter: (gidNumber=*)(objectclass=posixGroup)(objectclass=groupOfNames)
ipaWinSyncAcctDisable: both
ipaWinSyncForceSync: true
-ipaWinSyncUserAttr: uidNumber 999
-ipaWinSyncUserAttr: gidNumber 999
+ipaWinSyncUserAttr: uidNumber -1
+ipaWinSyncUserAttr: gidNumber -1
diff --git a/install/share/default-smb-group.ldif b/install/share/default-smb-group.ldif
index abcc8a945..3d2e2a04c 100644
--- a/install/share/default-smb-group.ldif
+++ b/install/share/default-smb-group.ldif
@@ -2,7 +2,7 @@ dn: cn=Default SMB Group,cn=groups,cn=accounts,$SUFFIX
changetype: add
cn: Default SMB Group
description: Fallback group for primary group RID, do not add users to this group
-gidnumber: 999
+gidnumber: -1
objectclass: top
objectclass: ipaobject
objectclass: posixgroup
diff --git a/install/share/dna.ldif b/install/share/dna.ldif
index ee927fcc5..86be44ccf 100644
--- a/install/share/dna.ldif
+++ b/install/share/dna.ldif
@@ -9,7 +9,7 @@ dnaType: uidNumber
dnaType: gidNumber
dnaNextValue: eval($IDSTART)
dnaMaxValue: eval($IDMAX)
-dnaMagicRegen: 999
+dnaMagicRegen: -1
dnaFilter: (|(objectClass=posixAccount)(objectClass=posixGroup)(objectClass=ipaIDobject))
dnaScope: $SUFFIX
dnaThreshold: 500
diff --git a/install/updates/20-dna.update b/install/updates/20-dna.update
index b83a3703d..04047dd12 100644
--- a/install/updates/20-dna.update
+++ b/install/updates/20-dna.update
@@ -1,3 +1,13 @@
# Enable the DNA plugin
dn: cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
only:nsslapd-pluginEnabled: on
+
+# Change the magic value to -1
+dn: cn=Posix IDs,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
+only:dnaMagicRegen: -1
+
+dn: cn=ipa-winsync,cn=plugins,cn=config
+remove:ipaWinSyncUserAttr: uidNumber 999
+remove:ipaWinSyncUserAttr: gidNumber 999
+add:ipaWinSyncUserAttr: uidNumber -1
+add:ipaWinSyncUserAttr: gidNumber -1
diff --git a/ipalib/capabilities.py b/ipalib/capabilities.py
index 751b93e2b..6fcc436d5 100644
--- a/ipalib/capabilities.py
+++ b/ipalib/capabilities.py
@@ -35,6 +35,12 @@ capabilities = dict(
# http://freeipa.org/page/V3/Messages
messages=u'2.52',
+ # optional_uid_params: Before this version, UID & GID parameter defaults
+ # were 999, which meant "assign dynamically", so was not possible to get
+ # a user with UID=999. With the capability, these parameters are optional
+ # and 999 really means 999.
+ # https://fedorahosted.org/freeipa/ticket/2886
+ optional_uid_params=u'2.54'
)
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 923a019dd..1e71a64f4 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -34,6 +34,8 @@ from ipalib.text import _
from ipalib.util import json_serialize, validate_hostname
from ipapython.dn import DN, RDN
+DNA_MAGIC = -1
+
global_output_params = (
Flag('has_password',
label=_('Password'),
diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py
index 19b127e16..bde002a8d 100644
--- a/ipalib/plugins/group.py
+++ b/ipalib/plugins/group.py
@@ -21,6 +21,7 @@
from ipalib import api
from ipalib import Int, Str
from ipalib.plugins.baseldap import *
+from ipalib.plugins import baseldap
from ipalib import _, ngettext
if api.env.in_server and api.env.context in ['lite', 'server']:
try:
@@ -202,7 +203,7 @@ class group_add(LDAPCreate):
elif not options['nonposix']:
entry_attrs['objectclass'].append('posixgroup')
if not 'gidnumber' in options:
- entry_attrs['gidnumber'] = 999
+ entry_attrs['gidnumber'] = baseldap.DNA_MAGIC
return dn
@@ -281,7 +282,7 @@ class group_mod(LDAPUpdate):
old_entry_attrs['objectclass'].append('posixgroup')
entry_attrs['objectclass'] = old_entry_attrs['objectclass']
if not 'gidnumber' in options:
- entry_attrs['gidnumber'] = 999
+ entry_attrs['gidnumber'] = baseldap.DNA_MAGIC
if options['external']:
if is_protected_group:
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 13f36ce29..32fda68e8 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -18,23 +18,25 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from time import gmtime, strftime, strptime
+from time import gmtime, strftime
import string
+import posixpath
+import os
from ipalib import api, errors
-from ipalib import Flag, Int, Password, Str, Bool, Bytes
+from ipalib import Flag, Int, Password, Str, Bool
from ipalib.plugins.baseldap import *
+from ipalib.plugins import baseldap
from ipalib.request import context
from ipalib import _, ngettext
from ipalib import output
from ipapython.ipautil import ipa_generate_password
from ipapython.ipavalidate import Email
-import posixpath
+from ipalib.capabilities import client_has_capability
from ipalib.util import (normalize_sshpubkey, validate_sshpubkey,
convert_sshpubkey_post)
if api.env.in_server and api.env.context in ['lite', 'server']:
from ipaserver.plugins.ldap2 import ldap2
- import os
__doc__ = _("""
Users
@@ -81,7 +83,6 @@ EXAMPLES:
NO_UPG_MAGIC = '__no_upg__'
-DNA_MAGIC = 999
user_output_params = (
Flag('has_keytab',
@@ -300,20 +301,16 @@ class user(LDAPObject):
label=_('Random password'),
flags=('no_create', 'no_update', 'no_search', 'virtual_attribute'),
),
- Int('uidnumber',
+ Int('uidnumber?',
cli_name='uid',
label=_('UID'),
doc=_('User ID Number (system will assign one if not provided)'),
- autofill=True,
- default=DNA_MAGIC,
minvalue=1,
),
- Int('gidnumber',
+ Int('gidnumber?',
label=_('GID'),
doc=_('Group ID Number'),
minvalue=1,
- default=DNA_MAGIC,
- autofill=True,
),
Str('street?',
cli_name='street',
@@ -468,6 +465,19 @@ class user_add(LDAPCreate):
entry_attrs.setdefault('description', [])
entry_attrs['description'].append(NO_UPG_MAGIC)
+ entry_attrs.setdefault('uidnumber', baseldap.DNA_MAGIC)
+
+ if not client_has_capability(
+ options['version'], 'optional_uid_params'):
+ # https://fedorahosted.org/freeipa/ticket/2886
+ # Old clients say 999 (OLD_DNA_MAGIC) when they really mean
+ # "assign a value dynamically".
+ OLD_DNA_MAGIC = 999
+ if entry_attrs.get('uidnumber') == OLD_DNA_MAGIC:
+ entry_attrs['uidnumber'] = baseldap.DNA_MAGIC
+ if entry_attrs.get('gidnumber') == OLD_DNA_MAGIC:
+ entry_attrs['gidnumber'] = baseldap.DNA_MAGIC
+
validate_nsaccountlock(entry_attrs)
config = ldap.get_ipa_config()[1]
if 'ipamaxusernamelength' in config:
@@ -493,7 +503,7 @@ class user_add(LDAPCreate):
api.env.basedn))
entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm))
- if entry_attrs.get('gidnumber', DNA_MAGIC) == DNA_MAGIC:
+ if entry_attrs.get('gidnumber') is None:
# gidNumber wasn't specified explicity, find out what it should be
if not options.get('noprivate', False) and ldap.has_upg():
# User Private Groups - uidNumber == gidNumber
diff --git a/tests/test_install/1_add.update b/tests/test_install/1_add.update
index ecb419513..2543a71f2 100644
--- a/tests/test_install/1_add.update
+++ b/tests/test_install/1_add.update
@@ -16,7 +16,7 @@ add:homedirectory: /home/tuser
add:loginshell: /bin/bash
add:sn: User
add:uid: tuser
-add:uidnumber: 999
-add:gidnumber: 999
+add:uidnumber: -1
+add:gidnumber: -1
add:cn: Test User
diff --git a/tests/test_xmlrpc/test_user_plugin.py b/tests/test_xmlrpc/test_user_plugin.py
index a61db23d5..7e992224c 100644
--- a/tests/test_xmlrpc/test_user_plugin.py
+++ b/tests/test_xmlrpc/test_user_plugin.py
@@ -1748,4 +1748,90 @@ class test_user(Declarative):
),
),
),
+
+ dict(
+ desc='Create "%s" with UID 999' % user1,
+ command=(
+ 'user_add', [user1], dict(
+ givenname=u'Test', sn=u'User1', uidnumber=999)
+ ),
+ expected=dict(
+ value=user1,
+ summary=u'Added user "%s"' % user1,
+ result=dict(
+ gecos=[u'Test User1'],
+ givenname=[u'Test'],
+ homedirectory=[u'/home/tuser1'],
+ krbprincipalname=[u'tuser1@' + api.env.realm],
+ loginshell=[u'/bin/sh'],
+ objectclass=objectclasses.user,
+ sn=[u'User1'],
+ uid=[user1],
+ uidnumber=[u'999'],
+ gidnumber=[u'999'],
+ displayname=[u'Test User1'],
+ cn=[u'Test User1'],
+ mail=[u'%s@%s' % (user1, api.env.domain)],
+ initials=[u'TU'],
+ ipauniqueid=[fuzzy_uuid],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[get_group_dn(user1)],
+ memberof_group=[u'ipausers'],
+ has_keytab=False,
+ has_password=False,
+ dn=get_user_dn(user1),
+ ),
+ ),
+ extra_check = upg_check,
+ ),
+
+ dict(
+ desc='Delete "%s"' % user1,
+ command=('user_del', [user1], {}),
+ expected=dict(
+ result=dict(failed=u''),
+ summary=u'Deleted user "%s"' % user1,
+ value=user1,
+ ),
+ ),
+
+ dict(
+ desc='Create "%s" with old DNA_MAGIC uid 999' % user1,
+ command=(
+ 'user_add', [user1], dict(
+ givenname=u'Test', sn=u'User1', uidnumber=999,
+ version=u'2.49')
+ ),
+ expected=dict(
+ value=user1,
+ summary=u'Added user "%s"' % user1,
+ result=dict(
+ gecos=[u'Test User1'],
+ givenname=[u'Test'],
+ homedirectory=[u'/home/tuser1'],
+ krbprincipalname=[u'tuser1@' + api.env.realm],
+ loginshell=[u'/bin/sh'],
+ objectclass=objectclasses.user,
+ sn=[u'User1'],
+ uid=[user1],
+ uidnumber=[lambda v: int(v) != 999],
+ gidnumber=[lambda v: int(v) != 999],
+ displayname=[u'Test User1'],
+ cn=[u'Test User1'],
+ mail=[u'%s@%s' % (user1, api.env.domain)],
+ initials=[u'TU'],
+ ipauniqueid=[fuzzy_uuid],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[get_group_dn(user1)],
+ memberof_group=[u'ipausers'],
+ has_keytab=False,
+ has_password=False,
+ dn=get_user_dn(user1),
+ ),
+ ),
+ extra_check = upg_check,
+ ),
+
]