def get_allocated_domain_quota(domain, conn=None): domain = web.safestr(domain).strip().lower() if not iredutils.is_domain(domain): return (False, 'INVALID_DOMAIN_NAME') dn = ldaputils.rdn_value_to_domain_dn(domain) allocated_quota = 0 if not conn: _wrap = LDAPWrap() conn = _wrap.conn try: # Use '(!([email protected]))' to exclude catch-all account. qr = conn.search_s(attrs.DN_BETWEEN_USER_AND_DOMAIN + dn, ldap.SCOPE_SUBTREE, '(objectClass=mailUser)', ['mailQuota']) for (_dn, _ldif) in qr: _ldif = iredutils.bytes2str(_ldif) quota = _ldif.get('mailQuota', ['0'])[0] if quota.isdigit(): allocated_quota += int(quota) return (True, allocated_quota) except ldap.NO_SUCH_OBJECT: return (False, 'NO_SUCH_ACCOUNT') except ldap.SIZELIMIT_EXCEEDED: return (False, 'EXCEEDED_LDAP_SERVER_SIZELIMIT') except Exception as e: return (False, repr(e))
def __update_num_domain_current_accounts(domain, increase=False, decrease=False, step_number=1, account_type='user', conn=None): """Increase or decrease number of existing accounts in domain profile.""" if not isinstance(step_number, int): step_number = 1 if step_number <= 0: step_number = 1 attr_map = { 'user': '******', 'alias': 'domainCurrentAliasNumber', 'maillist': 'domainCurrentListNumber', } attr_count = attr_map[account_type] if not conn: _wrap = LDAPWrap() conn = _wrap.conn dn = ldaputils.rdn_value_to_domain_dn(domain) # Get domain profile first try: qr = conn.search_s(dn, ldap.SCOPE_BASE, '(&(objectClass=mailDomain)(domainName=%s))' % domain, [attr_count]) except Exception as e: log_traceback() return (False, repr(e)) if qr: _ldif = iredutils.bytes2str(qr[0][1]) _current = int(_ldif.get(attr_count, [0])[0]) _num = _current if increase: _num = _current + step_number elif decrease: _num = _current - step_number if _num < 0: _num = 0 # Update count update_attr_with_single_value(dn=dn, attr=attr_count, value=_num, conn=conn) return (True, )
def __num_accounts_under_domain(domain, account_type='user', disabled_only=False, first_char=None, update_statistics=False, conn=None): """Get number of accounts under specified domain. :param domain: domain name you want to query. :param account_type: one of 'user', 'list', 'alias', 'ml', 'mixed_ml'. :param conn: ldap connection cursor. """ domain = str(domain).lower() if not iredutils.is_domain(domain): return (False, 'INVALID_DOMAIN_NAME') dn_domain = ldaputils.rdn_value_to_domain_dn(domain) statistics_attr = None if account_type == 'user': search_filter = '(&(objectClass=mailUser)(!(mail=@%s)))' % domain statistics_attr = 'domainCurrentUserNumber' else: search_filter = '(&(objectClass=mailUser)(!(mail=@%s)))' % domain if disabled_only: search_filter = '(&' + search_filter + '(accountStatus=disabled)' + ')' if first_char: search_filter = '(&' + search_filter + '(|(cn=%s*)(mail=%s*))' + ')' if not conn: _wrap = LDAPWrap() conn = _wrap.conn try: qr = conn.search_s(dn_domain, ldap.SCOPE_SUBTREE, search_filter, ['dn']) num = len(qr) if update_statistics and statistics_attr: mod_attr = ldaputils.mod_replace(statistics_attr, num) try: conn.modify_s(dn_domain, mod_attr) except: log_traceback() return num except: log_traceback() return 0
def get_domain_account_setting(domain, profile=None, conn=None): domain = str(domain).lower() if not iredutils.is_domain(domain): return (False, 'INVALID_DOMAIN_NAME') if profile: dn = None else: dn = ldaputils.rdn_value_to_domain_dn(domain) return __get_account_setting_by_dn(dn=dn, profile=profile, conn=conn)
def reset_forwardings(mail, forwardings=None, conn=None): if forwardings: _addresses = [ str(v).lower() for v in forwardings if iredutils.is_email(v) ] else: _addresses = [] # Remove duplicate addresses if _addresses: _addresses = list(set(_addresses)) # Remove non-existing addresses in same domain. domain = mail.split('@', 1)[-1] addrs_in_domain = set() addrs_not_in_domain = set() for addr in _addresses: if addr.endswith('@' + domain): addrs_in_domain.add(addr) else: addrs_not_in_domain.add(addr) if not conn: _wrap = LDAPWrap() conn = _wrap.conn # Get existing addresses valid_addrs_in_domain = set() if addrs_in_domain: dn = ldaputils.rdn_value_to_domain_dn(domain) _qr = ldap_lib_general.filter_existing_emails(mails=addrs_in_domain, base_dn=dn, conn=conn) valid_addrs_in_domain = set(_qr['exist']) fwd_addrs = list(valid_addrs_in_domain | addrs_not_in_domain) if fwd_addrs: mod_attr = ldaputils.mod_replace('mailForwardingAddress', fwd_addrs) else: mod_attr = ldaputils.mod_replace('mailForwardingAddress', None) try: dn = ldaputils.rdn_value_to_user_dn(mail) conn.modify_s(dn, mod_attr) return (True, ) except Exception as e: return (False, repr(e))
def exclude_non_existing_emails_in_domain(domain, mails, conn=None): """ Remove non-existing addresses in specified domain from given list of mail addresses. Return a list of existing and external addresses. :param domain: mail domain name. :param mails: a list/set/tuple of email addresses :param conn: ldap connection cursor """ domain = domain.lower() mails = {str(v).lower() for v in mails if iredutils.is_email(v)} _internals = {i for i in mails if i.endswith('@' + domain)} _externals = {i for i in mails if not i.endswith('@' + domain)} dn = ldaputils.rdn_value_to_domain_dn(domain) qr = filter_existing_emails(mails=_internals, base_dn=dn, conn=conn) return list(_externals) + qr['exist']
def __unmark_user_as_admin(user, domains=None, all_domains=False, conn=None): user = str(user).lower() if not iredutils.is_email(user): return (False, 'INVALID_MAIL') if not conn: _wrap = LDAPWrap() conn = _wrap.conn if domains: try: for d in domains: domain_dn = ldaputils.rdn_value_to_domain_dn(d) qr = ldap_lib_general.remove_attr_values(dn=domain_dn, attr='domainAdmin', values=[user], conn=conn) if not qr[0]: return qr return (True, ) except Exception as e: return (False, repr(e)) else: if all_domains: # Remove this user admin from all domains by default. qr_filter = '(&(objectClass=mailDomain)(domainAdmin=%s))' % user qr = conn.search_s(settings.ldap_basedn, ldap.SCOPE_ONELEVEL, qr_filter, ['dn']) for (dn, _ldif) in qr: try: ldap_lib_general.remove_attr_values(dn=dn, attr='domainAdmin', values=[user], conn=conn) except Exception as e: return (False, repr(e)) return (True, )
def get_domain_password_lengths(domain, account_settings=None, fallback_to_global_settings=False, db_settings=None, conn=None): das = {} if account_settings: das = account_settings else: if not conn: _wrap = LDAPWrap() conn = _wrap.conn dn = ldaputils.rdn_value_to_domain_dn(domain) _filter = '(&(objectClass=mailDomain)(|(domainName={})(domainAliasName={})))'.format(domain, domain) _qr = conn.search_s(dn, ldap.SCOPE_BASE, _filter, ['domainName', 'accountSetting']) if _qr: das = ldaputils.get_account_settings_from_qr(_qr).get(domain, {}) min_pw_len = das.get('minPasswordLength', 0) max_pw_len = das.get('maxPasswordLength', 0) if fallback_to_global_settings: if not db_settings: db_settings = iredutils.get_settings_from_db(params=['min_passwd_length', 'max_passwd_length']) if min_pw_len < db_settings['min_passwd_length']: min_pw_len = db_settings['min_passwd_length'] if max_pw_len < db_settings['max_passwd_length']: max_pw_len = db_settings['max_passwd_length'] return (min_pw_len, max_pw_len)
def __mark_user_as_admin(user, domains, conn=None): user = str(user).lower() if not iredutils.is_email(user): return (False, 'INVALID_MAIL') if not conn: _wrap = LDAPWrap() conn = _wrap.conn for i in domains: domain_dn = ldaputils.rdn_value_to_domain_dn(i) try: qr = ldap_lib_general.add_attr_values(dn=domain_dn, attr='domainAdmin', values=[user], conn=conn) if not qr[0]: return qr except Exception as e: return (False, repr(e)) return (True, )
def __reset_num_domain_current_accounts(domain, num, account_type='user', conn=None): """Update number of existing accounts in domain profile.""" dn = ldaputils.rdn_value_to_domain_dn(domain) if not isinstance(num, int): return (False, 'INVALID_NUMBER') if num < 0: num = 0 mapping = {'user': '******', 'alias': 'domainCurrentAliasNumber', 'maillist': 'domainCurrentListNumber'} attr_count = mapping[account_type] if not conn: _wrap = LDAPWrap() conn = _wrap.conn qr = update_attr_with_single_value(dn=dn, attr=attr_count, value=num, conn=conn) return qr
def list_accounts(domain, search_filter=None, attrlist=None, email_only=False, disabled_only=False, conn=None): # Update number of existing users in domain profile. update_count = False if not search_filter: # Use '(!([email protected]))' to hide catch-all account. search_filter = '(&(objectClass=mailUser)(!(mail=@%s)))' % domain update_count = True if disabled_only: # use "is True" here to prevent client input invalid value in url. search_filter = '(&' + search_filter + '(accountStatus=disabled)' + ')' if not attrlist: if email_only: attrlist = ['mail'] else: attrlist = list(attrs.USER_SEARCH_ATTRS) dn_domain = ldaputils.rdn_value_to_domain_dn(domain) # Search only admins INSIDE same domain. dn = attrs.DN_BETWEEN_USER_AND_DOMAIN + dn_domain if not conn: _wrap = LDAPWrap() conn = _wrap.conn try: qr = conn.search_s(dn, ldap.SCOPE_ONELEVEL, search_filter, attrlist) if qr: qr = iredutils.bytes2str(qr) _emails = [] if email_only: for (_dn, _ldif) in qr: _emails += _ldif.get('mail', []) _emails.sort() if update_count: # Reset number of existing users in domain profile. ldap_lib_general.reset_num_domain_current_users(domain=domain, num=len(qr), conn=conn) if email_only: return (True, _emails) else: return (True, qr) except ldap.NO_SUCH_OBJECT: return (False, 'NO_SUCH_ACCOUNT') except ldap.SIZELIMIT_EXCEEDED: return (False, 'EXCEEDED_LDAP_SERVER_SIZELIMIT') except Exception as e: return (False, repr(e))
def get_paged_account_list(account_profiles, current_page=1, domain=None, account_type=None, order_name=None, order_by_desc=False, size_limit=None, conn=None): """Sort accounts. Return a dict which contains keys: - total : number of total accounts - account_profiles: list of ldap query result sets ((<dn>: {...}) tuples) - pages: number of total pages show be showed in account list page. @account_profiles -- list of account_profiles (with many account details) @current_page -- offset page @domain -- accounts are under this domain @account_type -- account type @order_name -- order result set by given attribute. @order_by_desc -- order result set descending (desc) @size_limit -- show how many accounts in one page """ if not size_limit: size_limit = settings.PAGE_SIZE_LIMIT current_page = int(current_page) # Initial a dict to set default values. result = { 'total': 0, 'account_profiles': [], 'pages': 0, } # Get total accounts. total = len(account_profiles) result['total'] = total # Get number of actual pages. if total % size_limit == 0: pages = total / size_limit else: pages = (total / size_limit) + 1 result['pages'] = pages if current_page >= pages: current_page = pages _total_quota = 0 if (account_type == 'user') and domain: if order_name == 'quota': # sort accounts by real-time quota usage _all_used_quota = get_all_account_used_quota_under_domain(domain) _dict_all_used_quota = {} for _uq in _all_used_quota: _dict_all_used_quota[str(_uq.username)] = _uq.bytes del _all_used_quota # Generate new list to store quota <-> user map tmp_map = [] for act in account_profiles: _ldif = iredutils.bytes2str(act[1]) _mail = _ldif['mail'][0].lower() _quota = int(_ldif.get('mailQuota', [0])[0]) if _quota > 0: _used_quota = _dict_all_used_quota.get(_mail, 0) _mailbox_usage_percent = '%2f' % (float(_used_quota) / _quota) else: _mailbox_usage_percent = 0 tmp_map.append((_mailbox_usage_percent, act)) # Update total quota size _total_quota += _quota del _dict_all_used_quota if order_by_desc: tmp_map.sort(reverse=True) else: tmp_map.sort() account_profiles = [r[1] for r in tmp_map] del tmp_map elif order_name == 'name': # Generate new list to store name <-> user map tmp_map = [] for act in account_profiles: (_dn, _ldif) = act _mail = _ldif['mail'][0] _name = _ldif.get('cn', [None])[0] if not _name: # If no display name, use username part of email address instead. _name = _mail.split('@', 1)[0] tmp_map.append((_name, act)) if order_by_desc: tmp_map.sort(reverse=True) else: tmp_map.sort() account_profiles = [r[1] for r in tmp_map] del tmp_map else: # Sort accounts in place. account_profiles.sort() # Get account list used to display in current page. if size_limit < total < ((current_page - 1) * size_limit): result['account_profiles'] = account_profiles[-1:-size_limit] else: result['account_profiles'] = account_profiles[int((current_page - 1) * size_limit): int((current_page - 1) * size_limit + size_limit)] # Get total domain mailbox quota if account_type == 'user': if order_name == 'quota' and domain: pass else: counter = 0 for i in account_profiles: # Get total quota of this domain quota = i[1].get('mailQuota', ['0'])[0] if quota.isdigit(): _total_quota += int(quota) counter += 1 # Update number of current domain quota size in LDAP (@attrs.ATTR_DOMAIN_CURRENT_QUOTA_SIZE). if domain: # Update number of current domain quota size in LDAP. dn_domain = ldaputils.rdn_value_to_domain_dn(domain) update_attr_with_single_value(dn=dn_domain, attr=attrs.ATTR_DOMAIN_CURRENT_QUOTA_SIZE, value=str(_total_quota), conn=conn) return result