diff options
-rw-r--r-- | API.txt | 13 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | daemons/ipa-sam/ipa_sam.c | 2 | ||||
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-winsync/ipa-winsync-conf.ldif | 4 | ||||
-rw-r--r-- | install/share/default-smb-group.ldif | 2 | ||||
-rw-r--r-- | install/share/dna.ldif | 2 | ||||
-rw-r--r-- | install/updates/20-dna.update | 10 | ||||
-rw-r--r-- | ipalib/capabilities.py | 6 | ||||
-rw-r--r-- | ipalib/plugins/baseldap.py | 2 | ||||
-rw-r--r-- | ipalib/plugins/group.py | 5 | ||||
-rw-r--r-- | ipalib/plugins/user.py | 34 | ||||
-rw-r--r-- | tests/test_install/1_add.update | 4 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_user_plugin.py | 86 |
13 files changed, 144 insertions, 28 deletions
@@ -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 @@ -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, + ), + ] |