Diff
214 commits, 147 files changed
+19722 -5677

Updating ES translation
Héctor Daniel Cabrera • 13 years ago  
Remove bash-isms from configure macros
Petter Reinholdtsen • 13 years ago  
Copy-edit and format review sssd.conf
David O'Brien • 13 years ago  
file added
+37
@@ -0,0 +1,37 @@

+ 

+          SSSD - System Security Services Daemon

+          --------------------------------------

+ 

+   Introduction

+   ------------

+   SSSD provides a set of daemons to manage access to remote directories and

+   authentication mechanisms such as LDAP, Kerberos or FreeIPA. It provides

+   an NSS and PAM interface toward the system and a pluggable backend system

+   to connect to multiple different account sources.

+ 

+   More information about SSSD can be found on its project page - 

+   <http://fedorahosted.org/sssd/>

+ 

+   Building and installation

+   -------------------------

+   Please see the file BUILD.txt for details

+ 

+   Documentation

+   -------------

+   The most up-to-date documentation can be found at

+   <http://fedorahosted.org/sssd/wiki/HOWTO_Configure>

+ 

+   Licensing

+   ---------

+   Please see the file called COPYING.

+ 

+   Contacts

+   --------

+   There are several ways to contact us:

+ 

+      * the sssd-devel mailing list:

+        <https://fedorahosted.org/mailman/listinfo/sssd-devel>

+ 

+      * the #freeipa IRC channel on freenode:

+        irc://irc.freenode.net/freeipa

+ 

@@ -41,7 +41,7 @@

      collection_priv.h \

      ../trace/trace.h

  libcollection_la_LDFLAGS = \

-     -version-info 1:0:0

+     -version-info 2:0:0

  

  # Build unit test

  check_PROGRAMS = collection_ut collection_stack_ut collection_queue_ut

@@ -230,8 +230,12 @@

          return ENOMEM;

      }

  

-     /* After we initialize "next" we can use delete_item() in case of error */

+     /* After we initialize members we can use delete_item() in case of error */

      item->next = NULL;

+     item->property = NULL;

+     item->data = NULL;

+     TRACE_INFO_NUMBER("About to set type to:", type);

+     item->type = type;

  

      /* Copy property */

      item->property = strdup(property);
@@ -246,7 +250,6 @@

      TRACE_INFO_NUMBER("Item property length", item->property_len);

      TRACE_INFO_NUMBER("Item property strlen", strlen(item->property));

  

- 

      /* Deal with data */

      item->data = malloc(length);

      if (item->data == NULL) {
@@ -254,11 +257,8 @@

          col_delete_item(item);

          return ENOMEM;

      }

-     memcpy(item->data, item_data, length);

  

-     /* Deal with other properties of the item */

-     TRACE_INFO_NUMBER("About to set type to:", type);

-     item->type = type;

+     memcpy(item->data, item_data, length);

      item->length = length;

  

      /* Make sure that data is NULL terminated in case of string */

@@ -108,7 +108,7 @@

  /* Put an int property into a queue. */

  int col_enqueue_int_property(struct collection_item *queue,

                               const char *property,

-                              int number)

+                              int32_t number)

  {

      int error = EOK;

  
@@ -135,7 +135,7 @@

  /* Put an unsigned int property into a queue. */

  int col_enqueue_unsigned_property(struct collection_item *queue,

                                    const char *property,

-                                   unsigned int number)

+                                   uint32_t number)

  {

      int error = EOK;

  
@@ -163,7 +163,7 @@

  /* Put a long property. */

  int col_enqueue_long_property(struct collection_item *queue,

                                const char *property,

-                               long number)

+                               int64_t number)

  {

      int error = EOK;

  
@@ -190,7 +190,7 @@

  /* Put an unsigned long property. */

  int col_enqueue_ulong_property(struct collection_item *queue,

                                 const char *property,

-                                unsigned long number)

+                                uint64_t number)

  {

      int error = EOK;

  

@@ -144,7 +144,7 @@

   */

  int col_enqueue_int_property(struct collection_item *queue,

                               const char *property,

-                              int number);

+                              int32_t number);

  /**

   * @brief Add unsigned value to the queue.

   *
@@ -167,7 +167,7 @@

   */

  int col_enqueue_unsigned_property(struct collection_item *queue,

                                    const char *property,

-                                   unsigned int number);

+                                   uint32_t number);

  /**

   * @brief Add long integer value to the queue.

   *
@@ -190,7 +190,7 @@

   */

  int col_enqueue_long_property(struct collection_item *queue,

                                const char *property,

-                               long number);

+                               int64_t number);

  /**

   * @brief Add unsigned long value to the queue.

   *
@@ -213,7 +213,7 @@

   */

  int col_enqueue_ulong_property(struct collection_item *queue,

                                 const char *property,

-                                unsigned long number);

+                                uint64_t number);

  /**

   * @brief Add floating point value to the queue.

   *

@@ -106,7 +106,7 @@

  /* Push an int property to stack. */

  int col_push_int_property(struct collection_item *stack,

                            const char *property,

-                           int number)

+                           int32_t number)

  {

      int error = EOK;

  
@@ -133,7 +133,7 @@

  /* Push an unsigned int property to stack. */

  int col_push_unsigned_property(struct collection_item *stack,

                                 const char *property,

-                                unsigned int number)

+                                uint32_t number)

  {

      int error = EOK;

  
@@ -161,7 +161,7 @@

  /* Push a long property. */

  int col_push_long_property(struct collection_item *stack,

                             const char *property,

-                            long number)

+                            int64_t number)

  {

      int error = EOK;

  
@@ -188,7 +188,7 @@

  /* Push an unsigned long property. */

  int col_push_ulong_property(struct collection_item *stack,

                              const char *property,

-                             unsigned long number)

+                             uint64_t number)

  {

      int error = EOK;

  

@@ -145,7 +145,7 @@

   */

  int col_push_int_property(struct collection_item *stack,

                            const char *property,

-                           int number);

+                           int32_t number);

  /**

   * @brief Push unsigned value to the stack.

   *
@@ -168,7 +168,7 @@

   */

  int col_push_unsigned_property(struct collection_item *stack,

                                 const char *property,

-                                unsigned int number);

+                                uint32_t number);

  /**

   * @brief Push long integer value to the stack.

   *
@@ -191,7 +191,7 @@

   */

  int col_push_long_property(struct collection_item *stack,

                             const char *property,

-                            long number);

+                            int64_t number);

  /**

   * @brief Push unsigned long value to the stack.

   *
@@ -214,7 +214,7 @@

   */

  int col_push_ulong_property(struct collection_item *stack,

                              const char *property,

-                             unsigned long number);

+                             uint64_t number);

  /**

   * @brief Push floating point value to the stack.

   *

@@ -1,5 +1,5 @@

  AC_INIT([collection],

-         [0.4.0],

+         [0.5.0],

          [sssd-devel@lists.fedorahosted.org])

  AC_CONFIG_SRCDIR([collection.c])

  AC_CONFIG_AUX_DIR([build])

@@ -21,5 +21,11 @@

                [trace_level="0"])

  AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] ],[AC_SUBST([TRACE_VAR],["-DTRACE_LEVEL=$trace_level"])])

  

+ #Support old versions of autotools that don't provide docdir

+ AC_SUBST([docdir])

+ if test x$docdir = x; then

+     AC_SUBST([docdir], ${datadir}/doc/AC_PACKAGE_NAME)

+ fi

+ 

  AC_CONFIG_FILES([Makefile dhash.pc])

  AC_OUTPUT

file modified
+1 -1
@@ -1,4 +1,4 @@

- AC_INIT([ini_config],[0.4.0],[sssd-devel@lists.fedorahosted.org])

+ AC_INIT([ini_config],[0.5.1],[sssd-devel@lists.fedorahosted.org])

  AC_CONFIG_SRCDIR([ini_config.c])

  AC_CONFIG_AUX_DIR([build])

  AM_INIT_AUTOMAKE([-Wall -Werror foreign])

file modified
+36 -24
@@ -364,20 +364,25 @@

              break;

  

          case RET_ERROR:

-             pe.line = line;

-             pe.error = ext_err;

-             error = col_add_binary_property(*error_list, NULL,

-                                             ERROR_TXT, &pe, sizeof(pe));

-             if (error) {

-                 TRACE_ERROR_NUMBER("Failed to add error to collection", error);

-                 fclose(file);

-                 col_destroy_collection(current_section);

-                 if (created) {

-                     col_destroy_collection(*error_list);

-                     *error_list = NULL;

+             /* Try to add to the error list only if it is present */

+             if (error_list) {

+                 pe.line = line;

+                 pe.error = ext_err;

+                 error = col_add_binary_property(*error_list, NULL,

+                                                 ERROR_TXT, &pe, sizeof(pe));

+                 if (error) {

+                     TRACE_ERROR_NUMBER("Failed to add error to collection",

+                                        error);

+                     fclose(file);

+                     col_destroy_collection(current_section);

+                     if (created) {

+                         col_destroy_collection(*error_list);

+                         *error_list = NULL;

+                     }

+                     return error;

                  }

-                 return error;

              }

+ 

              /* Exit if there was an error parsing file */

              if (error_level != INI_STOP_ON_NONE) {

                  TRACE_ERROR_STRING("Invalid format of the file", "");
@@ -389,20 +394,25 @@

  

          case RET_INVALID:

          default:

-             pe.line = line;

-             pe.error = ext_err;

-             error = col_add_binary_property(*error_list, NULL,

-                                             WARNING_TXT, &pe, sizeof(pe));

-             if (error) {

-                 TRACE_ERROR_NUMBER("Failed to add warning to collection", error);

-                 fclose(file);

-                 col_destroy_collection(current_section);

-                 if (created) {

-                     col_destroy_collection(*error_list);

-                     *error_list = NULL;

+             /* Try to add to the error list only if it is present */

+             if (error_list) {

+                 pe.line = line;

+                 pe.error = ext_err;

+                 error = col_add_binary_property(*error_list, NULL,

+                                                 WARNING_TXT, &pe, sizeof(pe));

+                 if (error) {

+                     TRACE_ERROR_NUMBER("Failed to add warning to collection",

+                                        error);

+                     fclose(file);

+                     col_destroy_collection(current_section);

+                     if (created) {

+                         col_destroy_collection(*error_list);

+                         *error_list = NULL;

+                     }

+                     return error;

                  }

-                 return error;

              }

+ 

              /* Exit if we are told to exit on warnings */

              if (error_level == INI_STOP_ON_ANY) {

                  TRACE_ERROR_STRING("Invalid format of the file", "");
@@ -1832,6 +1842,8 @@

  

      if (error) *error = EOK;

      if (size) *size = count;

+     /* If count is 0 the copy needs to be freed */

+     if (count == 0) free(copy);

      TRACE_FLOW_STRING("get_str_cfg_array", "Exit");

      return array;

  }

@@ -976,6 +976,48 @@

      COLOUT(for (i=0;i<size;i++) printf("Attribute: [%s]\n", prop_array[i]));

      free_attribute_list(prop_array);

  

+     COLOUT(printf("Get empty array item\n"));

+ 

+     item = NULL;

+     error = get_config_item("domains/EXAMPLE.COM",

+                             "empty_value",

+                             ini_config,

+                             &item);

+     if(error) {

+         printf("Expected success but got error! %d\n", error);

+         free_ini_config(ini_config);

+         return error;

+     }

+ 

+     /* Item should be found */

+     if (item == NULL) {

+         printf("Expected success but got NULL.\n");

+         free_ini_config(ini_config);

+         return -1;

+     }

+ 

+     COLOUT(col_debug_item(item));

+ 

+     error = 0;

+     size = 0; /* Here size is not optional!!! */

+     strarray = get_string_config_array(item, ",", &size, &error);

+     if(error) {

+         printf("Expect success got error %d.\n", error);

+         free_ini_config(ini_config);

+         return error;

+     }

+ 

+     if (size != 0) {

+         for (i=0; i<size; i++) printf("%s\n", *(strarray + i));

+         printf("Expected size=0, got size=%d\n", size);

+         free_string_config_array(strarray);

+         free_ini_config(ini_config);

+         return -1;

+     }

+ 

+ 

+     free_string_config_array(strarray);

+ 

      free_ini_config(ini_config);

      COLOUT(printf("Done with get test!\n"));

      return EOK;

@@ -538,6 +538,10 @@

          error = path_concat(entry_path, sizeof(entry_path),

                              path, entry->d_name);

          if (error != SUCCESS) {

+             closedir(dir);

+             /* Don't bother checking the return here.

+              * The path_concat error is more important

+              */

              return error;

          }

  
@@ -551,6 +555,10 @@

                  error = directory_list(entry_path, recursive,

                                         callback, user_data);

                  if (error != SUCCESS) {

+                     closedir(dir);

+                     /* Don't bother checking the return here.

+                      * The directory_list error is more important

+                      */

                      return error;

                  }

              }

file modified
+11 -11
@@ -15,8 +15,8 @@

  

  %define dhash_version 0.4.0

  %define path_utils_version 0.2.0

- %define collection_version 0.4.0

- %define ini_config_version 0.4.0

+ %define collection_version 0.5.0

+ %define ini_config_version 0.5.1

  %define refarray_version 0.1.0

  

  ### Patches ###
@@ -26,10 +26,11 @@

  Requires: libldb >= 0.9.3

  Requires: libtdb >= 1.1.3

  Requires: sssd-client = %{version}-%{release}

- Requires: libdhash = %{dhash_version}-%{release}

- Requires: libcollection = %{collection_version}-%{release}

- Requires: libini_config = %{ini_config_version}-%{release}

+ Requires: libdhash >= %{dhash_version}

+ Requires: libcollection >= %{collection_version}

+ Requires: libini_config >= %{ini_config_version}

  Requires: cyrus-sasl-gssapi

+ Requires: keyutils-libs

  Requires(post): python

  Requires(preun):  initscripts chkconfig

  Requires(postun): /sbin/service
@@ -74,6 +75,8 @@

  BuildRequires: doxygen

  BuildRequires: libselinux-devel

  BuildRequires: libsemanage-devel

+ BuildRequires: keyutils-libs-devel

+ BuildRequires: bind-utils

  

  %description

  Provides a set of daemons to manage access to remote directories and
@@ -156,7 +159,7 @@

  Summary: INI file parser for C

  Group: Development/Libraries

  Version: %{ini_config_version}

- Requires: libcollection = %{collection_version}-%{release}

+ Requires: libcollection >= %{collection_version}

  License: LGPLv3+

  

  %description -n libini_config
@@ -197,8 +200,6 @@

  %setup -q

  

  %build

- NSS_LIBS=-lnss3 \

- KRB5_LIBS=-lkrb5 \

  %configure \

      --with-db-path=%{dbpath} \

      --with-pipe-path=%{pipepath} \
@@ -366,8 +367,8 @@

  %defattr(-,root,root,-)

  %doc common/collection/COPYING

  %doc common/collection/COPYING.LESSER

- %{_libdir}/libcollection.so.1

- %{_libdir}/libcollection.so.1.0.0

+ %{_libdir}/libcollection.so.2

+ %{_libdir}/libcollection.so.2.0.0

  

  %files -n libcollection-devel

  %defattr(-,root,root,-)
@@ -452,4 +453,3 @@

  %changelog

  * Mon Mar 15 2010 Stephen Gallagher <sgallagh@redhat.com> - @PACKAGE_VERSION@-0@PRERELEASE_VERSION@

  - Automated build of the SSSD

- 

@@ -100,8 +100,6 @@

  %setup -q

  

  %build

- NSS_LIBS=-lnss3 \

- KRB5_LIBS=-lkrb5 \

  %configure \

      --without-tests \

      --with-db-path=%{dbpath} \

file modified
+63 -13
@@ -6,6 +6,11 @@

  

  DOXYGEN = @DOXYGEN@

  

+ DISTSETUPOPTS =

+ if HAVE_DEBIAN

+ DISTSETUPOPTS += --install-layout=deb

+ endif

+ 

  sssdlibexecdir = $(libexecdir)/sssd

  sssdlibdir = $(libdir)/sssd

  ldblibdir = @ldblibdir@
@@ -57,7 +62,8 @@

      krb5_child \

      ldap_child \

      $(sssd_pk) \

-     $(sssd_info)

+     $(sssd_info) \

+     proxy_child

  

  dist_sssdlibexec_SCRIPTS = \

      config/upgrade_config.py
@@ -76,7 +82,8 @@

          find_uid-tests \

          auth-tests \

          ipa_ldap_opt-tests \

-         simple_access-tests

+         simple_access-tests \

+         util-tests

  endif

  

  check_PROGRAMS = \
@@ -118,7 +125,8 @@

  libsss_crypt_la_SOURCES = \

      $(SSS_CRYPT_SOURCES)

  libsss_crypt_la_CPPFLAGS = \

-     $(SSS_CRYPT_CFLAGS)

+     $(SSS_CRYPT_CFLAGS) \

+     $(DHASH_CFLAGS)

  libsss_crypt_la_LIBADD = \

      $(SSS_CRYPT_LIBS)

  
@@ -212,7 +220,8 @@

  EXTRA_DIST = build/config.rpath

  

  SSSD_DEBUG_OBJ = \

-     util/debug.c

+     util/debug.c \

+     util/sss_log.c

  

  SSSD_UTIL_OBJ = \

      confdb/confdb.c \
@@ -221,6 +230,7 @@

      db/sysdb_search.c \

      monitor/monitor_sbus.c \

      providers/dp_auth_util.c \

+     providers/dp_pam_data_util.c \

      providers/dp_sbus.c \

      sbus/sbus_client.c \

      sbus/sssd_dbus_common.c \
@@ -238,6 +248,7 @@

      $(SSSD_DEBUG_OBJ)

  

  SSSD_RESPONDER_OBJ = \

+     responder/common/negcache.c \

      responder/common/responder_cmd.c \

      responder/common/responder_common.c \

      responder/common/responder_dp.c \
@@ -252,6 +263,11 @@

  

  SSSD_RESOLV_OBJ = \

      resolv/async_resolv.c

+ if BUILD_ARES_DATA

+     SSSD_RESOLV_OBJ += \

+ 	resolv/ares/ares_parse_srv_reply.c \

+ 	resolv/ares/ares_data.c

+ endif

  

  SSSD_FAILOVER_OBJ = \

      providers/fail_over.c \
@@ -317,7 +333,7 @@

      responder/common/responder_packet.h \

      responder/pam/pamsrv.h \

      responder/nss/nsssrv.h \

-     responder/nss/nsssrv_nc.h \

+     responder/common/negcache.h \

      sbus/sbus_client.h \

      sbus/sssd_dbus.h \

      sbus/sssd_dbus_private.h \
@@ -337,12 +353,15 @@

      providers/krb5/krb5_utils.h \

      providers/ldap/ldap_common.h \

      providers/ldap/sdap.h \

+     providers/ldap/sdap_access.h \

      providers/ldap/sdap_async.h \

      providers/ldap/sdap_async_private.h \

      providers/ipa/ipa_common.h \

      providers/ipa/ipa_access.h \

      providers/ipa/ipa_timerules.h \

      providers/ipa/ipa_auth.h \

+     providers/ipa/ipa_dyndns.h \

+     providers/proxy/proxy.h \

      tools/tools_util.h \

      tools/sss_sync_ops.h \

      resolv/async_resolv.h \
@@ -365,7 +384,6 @@

  sssd_nss_SOURCES = \

      responder/nss/nsssrv.c \

      responder/nss/nsssrv_cmd.c \

-     responder/nss/nsssrv_nc.c \

      $(SSSD_UTIL_OBJ) \

      $(SSSD_RESPONDER_OBJ)

  sssd_nss_LDADD = \
@@ -380,12 +398,14 @@

      $(SSSD_UTIL_OBJ) \

      $(SSSD_RESPONDER_OBJ)

  sssd_pam_LDADD = \

+     $(TDB_LIBS) \

      $(SSSD_LIBS)

  

  sssd_be_SOURCES = \

      providers/data_provider_be.c \

      providers/data_provider_fo.c \

      providers/data_provider_opts.c \

+     providers/data_provider_callbacks.c \

      $(SSSD_FAILOVER_OBJ) \

      $(SSSD_UTIL_OBJ)

  sssd_be_LDADD = $(SSSD_LIBS) $(CARES_LIBS)
@@ -501,6 +521,7 @@

      providers/krb5/krb5_common.c \

      providers/data_provider_fo.c \

      providers/data_provider_opts.c \

+     providers/data_provider_callbacks.c \

      $(SSSD_FAILOVER_OBJ) \

      $(SSSD_UTIL_OBJ)

  krb5_utils_tests_CFLAGS = \
@@ -553,9 +574,7 @@

      $(SSSD_RESOLV_OBJ)

  if BUILD_ARES_DATA

      SSSD_RESOLV_TESTS_OBJ += \

- 	resolv/ares/ares_parse_srv_reply.c \

- 	resolv/ares/ares_parse_txt_reply.c \

- 	resolv/ares/ares_data.c

+ 	resolv/ares/ares_parse_txt_reply.c

  endif

  

  resolv_tests_SOURCES = \
@@ -565,7 +584,7 @@

  resolv_tests_CFLAGS = \

      $(AM_CFLAGS) \

      $(CHECK_CFLAGS) \

-     -DBUILD_TXT_SRV

+     -DBUILD_TXT

  resolv_tests_LDADD = \

      $(SSSD_LIBS) \

      $(CHECK_LIBS) \
@@ -615,6 +634,7 @@

  

  find_uid_tests_SOURCES = \

      tests/find_uid-tests.c \

+     util/strtonum.c \

      util/find_uid.c \

      $(SSSD_DEBUG_OBJ)

  find_uid_tests_CFLAGS = \
@@ -661,6 +681,17 @@

      $(SSSD_LIBS) \

      $(CHECK_LIBS)

  

+ util_tests_SOURCES = \

+     tests/util-tests.c \

+     $(SSSD_UTIL_OBJ)

+ util_tests_CFLAGS = \

+     $(AM_CFLAGS) \

+     $(CHECK_CFLAGS)

+ util_tests_LDADD = \

+     $(SSSD_LIBS) \

+     $(CHECK_LIBS) \

+     libsss_test_common.la

+ 

  endif

  

  stress_tests_SOURCES = \
@@ -715,6 +746,7 @@

      providers/ldap/ldap_id.c \

      providers/ldap/ldap_id_enum.c \

      providers/ldap/ldap_id_cleanup.c \

+     providers/ldap/sdap_access.c \

      providers/ldap/ldap_auth.c \

      providers/ldap/ldap_init.c \

      providers/ldap/ldap_common.c \
@@ -722,6 +754,7 @@

      providers/ldap/sdap_async_accounts.c \

      providers/ldap/sdap_async_connection.c \

      providers/ldap/sdap_child_helpers.c \

+     providers/ldap/sdap_fd_events.c \

      providers/ldap/sdap.c \

      util/user_info_msg.c \

      util/sss_ldap.c \
@@ -738,7 +771,7 @@

      -module

  

  libsss_proxy_la_SOURCES = \

-     providers/proxy.c

+     providers/proxy/proxy.c

  libsss_proxy_la_CFLAGS = \

      $(AM_CFLAGS)

  libsss_proxy_la_LIBADD = \
@@ -762,6 +795,7 @@

      providers/child_common.c \

      providers/krb5/krb5_utils.c \

      providers/krb5/krb5_become_user.c \

+     providers/krb5/krb5_delayed_online_authentication.c \

      providers/krb5/krb5_auth.c \

      providers/krb5/krb5_common.c \

      providers/krb5/krb5_init.c \
@@ -771,6 +805,7 @@

      $(DHASH_CFLAGS)

  libsss_krb5_la_LIBADD = \

      $(DHASH_LIBS) \

+     $(KEYUTILS_LIBS) \

      $(KRB5_LIBS)

  libsss_krb5_la_LDFLAGS = \

      -version-info 1:0:0 \
@@ -784,6 +819,7 @@

      providers/ipa/ipa_auth.c \

      providers/ipa/ipa_access.c \

      providers/ipa/ipa_timerules.c \

+     providers/ipa/ipa_dyndns.c \

      providers/ldap/ldap_id.c \

      providers/ldap/ldap_id_enum.c \

      providers/ldap/ldap_id_cleanup.c \
@@ -793,6 +829,7 @@

      providers/ldap/sdap_async_accounts.c \

      providers/ldap/sdap_async_connection.c \

      providers/ldap/sdap_child_helpers.c \

+     providers/ldap/sdap_fd_events.c \

      providers/ldap/sdap.c \

      util/user_info_msg.c \

      util/sss_ldap.c \
@@ -800,6 +837,7 @@

      util/find_uid.c \

      providers/krb5/krb5_utils.c \

      providers/krb5/krb5_become_user.c \

+     providers/krb5/krb5_delayed_online_authentication.c \

      providers/krb5/krb5_common.c \

      providers/krb5/krb5_auth.c

  libsss_ipa_la_CFLAGS = \
@@ -810,6 +848,7 @@

  libsss_ipa_la_LIBADD = \

      $(OPENLDAP_LIBS) \

      $(DHASH_LIBS) \

+     $(KEYUTILS_LIBS) \

      $(KRB5_LIBS)

  libsss_ipa_la_LDFLAGS = \

      -version-info 1:0:0 \
@@ -820,6 +859,7 @@

      providers/krb5/krb5_become_user.c \

      providers/krb5/krb5_child.c \

      providers/child_common.c \

+     providers/dp_pam_data_util.c \

      util/user_info_msg.c \

      util/sss_krb5.c

  krb5_child_CFLAGS = \
@@ -848,6 +888,16 @@

      $(OPENLDAP_LIBS) \

      $(KRB5_LIBS)

  

+ proxy_child_SOURCES = \

+     $(SSSD_UTIL_OBJ) \

+     providers/proxy/proxy_child.c

+ proxy_child_CFLAGS = \

+     $(AM_CFLAGS) \

+     $(POPT_CFLAGS)

+ proxy_child_LDADD = \

+     $(PAM_LIBS) \

+     $(SSSD_LIBS)

+ 

  memberof_la_SOURCES = \

      ldb_modules/memberof.c

  memberof_la_CFLAGS = \
@@ -975,9 +1025,9 @@

  

  install-exec-hook: installsssddirs

  	if [ "$(DESTDIR)" = "" ]; then \

- 		cd $(srcdir)/config; $(PYTHON) setup.py build --build-base $(abs_builddir)/config install --prefix=$(PYTHON_PREFIX) --record=$(abs_builddir)/config/.files; \

+ 		cd $(srcdir)/config; $(PYTHON) setup.py build --build-base $(abs_builddir)/config install $(DISTSETUPOPTS) --prefix=$(PYTHON_PREFIX) --record=$(abs_builddir)/config/.files; \

  	else \

- 		cd $(srcdir)/config; $(PYTHON) setup.py build --build-base $(abs_builddir)/config install --prefix=$(PYTHON_PREFIX) --root=$(DESTDIR) --record=$(abs_builddir)/config/.files; \

+ 		cd $(srcdir)/config; $(PYTHON) setup.py build --build-base $(abs_builddir)/config install $(DISTSETUPOPTS) --prefix=$(PYTHON_PREFIX) --root=$(DESTDIR) --record=$(abs_builddir)/config/.files; \

  	fi

  	mkdir -p doc $(DESTDIR)/$(docdir); cp -a doc $(DESTDIR)/$(docdir)/

  

file modified
+5 -5
@@ -123,7 +123,7 @@

                  [],

                  with_manpages=yes

                 )

-     if test x"$with_manpages" == xyes; then

+     if test x"$with_manpages" = xyes; then

          HAVE_MANPAGES=1

          AC_SUBST(HAVE_MANPAGES)

      fi
@@ -167,7 +167,7 @@

                  [],

                  with_python_bindings=yes

                 )

-     if test x"$with_python_bindings" == xyes; then

+     if test x"$with_python_bindings" = xyes; then

          HAVE_PYTHON_BINDINGS=1

          AC_SUBST(HAVE_PYTHON_BINDINGS)

      fi
@@ -183,7 +183,7 @@

                  [],

                  with_selinux=yes

                 )

-     if test x"$with_selinux" == xyes; then

+     if test x"$with_selinux" = xyes; then

          HAVE_SELINUX=1

          AC_SUBST(HAVE_SELINUX)

          AC_DEFINE_UNQUOTED(HAVE_SELINUX, 1, [Build with SELinux support])
@@ -212,7 +212,7 @@

                  [],

                  with_nscd=yes

                 )

-     if test x"$with_nscd" == xyes; then

+     if test x"$with_nscd" = xyes; then

          AC_DEFINE_UNQUOTED(HAVE_NSCD, 1, [flush nscd cache after local domain operations])

      fi

    ])
@@ -226,7 +226,7 @@

                  [],

                  with_semanage=yes

                 )

-     if test x"$with_semanage" == xyes; then

+     if test x"$with_semanage" = xyes; then

          HAVE_SEMANAGE=1

          AC_SUBST(HAVE_SEMANAGE)

          AC_DEFINE_UNQUOTED(HAVE_SEMANAGE, 1, [Build with SELinux support])

file modified
+2 -1
@@ -39,7 +39,7 @@

  

  #define CONFDB_FILE "config.ldb"

  #define CONFDB_DEFAULT_CONFIG_FILE SSSD_CONF_DIR"/sssd.conf"

- #define SSSD_MIN_ID 1000

+ #define SSSD_MIN_ID 1

  

  

  /* Configuration options */
@@ -100,6 +100,7 @@

  #define CONFDB_DOMAIN_MPG "magic_private_groups"

  #define CONFDB_DOMAIN_FQ "use_fully_qualified_names"

  #define CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT "entry_cache_timeout"

+ #define CONFDB_DOMAIN_RESOLV_TIMEOUT "dns_resolver_timeout"

  #define CONFDB_DOMAIN_FAMILY_ORDER "lookup_family_order"

  #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration"

  

@@ -203,6 +203,10 @@

  

              const char *value = get_const_string_config_value(attr, &ret);

              if (ret != EOK) goto error;

+             if (value && value[0] == '\0') {

+                 DEBUG(1, ("Attribute '%s' has empty value, ignoring\n", attrs[j]));

+                 continue;

+             }

  

              ldif_attr = talloc_asprintf(tmp_ctx,

                                          "%s: %s\n", attrs[j], value);

file modified
+36 -10
@@ -81,11 +81,14 @@

      'entry_cache_timeout' : _('Entry cache timeout length (seconds)'),

      'lookup_family_order' : _('Restrict or prefer a specific address family when performing DNS lookups'),

      'account_cache_expiration' : _('How long to keep cached entries after last successful login (days)'),

+     'dns_resolver_timeout' : _('How long to wait for replies from DNS when resolving servers (seconds)'),

  

      # [provider/ipa]

      'ipa_domain' : _('IPA domain'),

      'ipa_server' : _('IPA server address'),

      'ipa_hostname' : _('IPA client hostname'),

+     'ipa_dyndns_update' : _("Whether to automatically update the client's DNS entry in FreeIPA"),

+     'ipa_dyndns_iface' : _("The interface whose IP should be used for dynamic DNS updates"),

  

      # [provider/krb5]

      'krb5_kdcip' : _('Kerberos server address'),
@@ -97,9 +100,9 @@

      'krb5_ccname_template' : _("Location of the user's credential cache"),

      'krb5_keytab' : _("Location of the keytab to validate credentials"),

      'krb5_validate' : _("Enable credential validation"),

+     'krb5_store_password_if_offline' : _("Store password if offline for later online authentication"),

  

      # [provider/krb5/chpass]

-     'krb5_changepw_principal' : _('The principal of the change password service'),

      'krb5_kpasswd' : _('Server where the change password service is running if not on the KDC'),

  

      # [provider/ldap]
@@ -111,7 +114,6 @@

      'ldap_default_authtok' : _('The authentication token of the default bind DN'),

      'ldap_network_timeout' : _('Length of time to attempt connection'),

      'ldap_opt_timeout' : _('Length of time to attempt synchronous LDAP operations'),

-     'ldap_offline_timeout' : _('Length of time between attempts to reconnect while offline'),

      'ldap_tls_cacert' : _('File that contains CA certificates'),

      'ldap_tls_cacertdir' : _('Path to CA certificate directory'),

      'ldap_tls_reqcert' : _('Require TLS certificate verification'),
@@ -122,6 +124,7 @@

      'ldap_krb5_keytab' : _('Kerberos service keytab'),

      'ldap_krb5_init_creds' : _('Use Kerberos auth for LDAP connection'),

      'ldap_referrals' : _('Follow LDAP referrals'),

+     'ldap_krb5_ticket_lifetime' : _('Lifetime of TGT for LDAP connection'),

  

      # [provider/ldap/id]

      'ldap_search_timeout' : _('Length of time to wait for a search request'),
@@ -146,6 +149,9 @@

      # [provider/ldap/auth]

      'ldap_pwd_policy' : _('Policy to evaluate the password expiration'),

  

+     # [provider/ldap/access]

+     'ldap_access_filter' : _('LDAP filter to determine access privileges'),

+ 

      # [provider/simple/access]

      'simple_allow_users' : _('Comma separated list of allowed users'),

      'simple_deny_users' : _('Comma separated list of prohibited users'),
@@ -937,7 +943,10 @@

          is_provider = option.rfind('_provider')

          if (is_provider > 0):

              provider = option[:is_provider]

-             self.add_provider(value, provider)

+             try:

+                 self.add_provider(value, provider)

+             except NoSuchProviderError:

+                 raise NoOptionError

          else:

              self.options[option] = value

  
@@ -1244,8 +1253,13 @@

              raise NoServiceError

  

          service = SSSDService(name, self.schema)

-         [service.set_option(opt['name'], opt['value'])

-          for opt in self.strip_comments_empty(self.options(name)) ]

+         for opt in self.strip_comments_empty(self.options(name)):

+             try:

+                 service.set_option(opt['name'], opt['value'])

+             except NoOptionError:

+                 # If we come across an option that we don't recognize,

+                 # we should just ignore it and continue

+                 pass

  

          return service

  
@@ -1441,12 +1455,24 @@

          # errors trying to read in their options

          providers = [ (x['name'],x['value']) for x in self.strip_comments_empty(self.options('domain/%s' % name))

                       if x['name'].rfind('_provider') > 0]

-         [domain.set_option(option, value)

-          for (option, value) in providers]

  

-         [domain.set_option(opt['name'], opt['value'])

-          for opt in self.strip_comments_empty(self.options('domain/%s' % name))

-          if (opt['name'], opt['value']) not in providers]

+         for (option, value) in providers:

+             try:

+                 domain.set_option(option, value)

+             except NoOptionError:

+                 # If we come across an option that we don't recognize,

+                 # we should just ignore it and continue

+                 pass

+ 

+         # Read in all the options from the configuration

+         for opt in self.strip_comments_empty(self.options('domain/%s' % name)):

+             if (opt['name'], opt['value']) not in providers:

+                 try:

+                     domain.set_option(opt['name'], opt['value'])

+                 except NoOptionError:

+                     # If we come across an option that we don't recognize,

+                     # we should just ignore it and continue

+                     pass

  

          # Determine if this domain is currently active

          domain.active = self.is_domain_active(name)

file modified
+41 -14
@@ -27,7 +27,6 @@

          self.assertTrue('sssd' in services)

          self.assertTrue('nss' in services)

          self.assertTrue('pam' in services)

-         self.assertTrue('dp' in services)

  

          #Verify service attributes

          sssd_service = sssdconfig.get_service('sssd')
@@ -478,6 +477,7 @@

              'entry_cache_timeout',

              'lookup_family_order',

              'account_cache_expiration',

+             'dns_resolver_timeout',

              'id_provider',

              'auth_provider',

              'access_provider',
@@ -542,10 +542,12 @@

          control_list.extend(

              ['krb5_kdcip',

               'krb5_realm',

+              'krb5_kpasswd',

               'krb5_ccachedir',

               'krb5_ccname_template',

               'krb5_keytab',

               'krb5_validate',

+              'krb5_store_password_if_offline',

               'krb5_auth_timeout'])

  

          options = domain.list_options()
@@ -592,7 +594,6 @@

          options = domain.list_mandatory_options()

          control_list = [

              'cache_credentials',

-             'min_id',

              'id_provider',

              'auth_provider']

  
@@ -639,9 +640,7 @@

          domain.add_provider('krb5', 'auth')

  

          backup_list = control_list[:]

-         control_list.extend(

-             ['krb5_kdcip',

-              'krb5_realm'])

+         control_list.extend(['krb5_realm'])

  

          options = domain.list_mandatory_options()

  
@@ -686,7 +685,7 @@

          control_provider_dict = {

              'ipa': ['id', 'auth', 'access', 'chpass'],

              'local': ['id', 'auth', 'chpass'],

-             'ldap': ['id', 'auth', 'chpass'],

+             'ldap': ['id', 'auth', 'access', 'chpass'],

              'krb5': ['auth', 'chpass'],

              'proxy': ['id', 'auth'],

              'simple': ['access'],
@@ -714,10 +713,12 @@

          control_list = [

              'krb5_kdcip',

              'krb5_realm',

+             'krb5_kpasswd',

              'krb5_ccachedir',

              'krb5_ccname_template',

              'krb5_keytab',

              'krb5_validate',

+             'krb5_store_password_if_offline',

              'krb5_auth_timeout']

  

          self.assertTrue(type(options) == dict,
@@ -737,8 +738,7 @@

  

          #Test looking up all provider values

          options = domain.list_provider_options('krb5')

-         control_list.extend(['krb5_changepw_principal',

-                              'krb5_kpasswd'])

+         control_list.extend(['krb5_kpasswd'])

  

          self.assertTrue(type(options) == dict,

                          "Options should be a dictionary")
@@ -794,6 +794,7 @@

              'entry_cache_timeout',

              'account_cache_expiration',

              'lookup_family_order',

+             'dns_resolver_timeout',

              'id_provider',

              'auth_provider',

              'access_provider',
@@ -858,10 +859,12 @@

          control_list.extend(

              ['krb5_kdcip',

               'krb5_realm',

+              'krb5_kpasswd',

               'krb5_ccachedir',

               'krb5_ccname_template',

               'krb5_keytab',

               'krb5_validate',

+              'krb5_store_password_if_offline',

               'krb5_auth_timeout'])

  

          options = domain.list_options()
@@ -983,9 +986,9 @@

          domain = SSSDConfig.SSSDDomain('sssd', self.schema)

  

          # Positive test - Remove existing option

-         self.assertTrue('min_id' in domain.get_all_options().keys())

-         domain.remove_option('min_id')

-         self.assertFalse('min_id' in domain.get_all_options().keys())

+         self.assertTrue('cache_credentials' in domain.get_all_options().keys())

+         domain.remove_option('cache_credentials')

+         self.assertFalse('cache_credentials' in domain.get_all_options().keys())

  

          # Positive test - Remove unset but valid option

          self.assertFalse('max_id' in domain.get_all_options().keys())
@@ -1045,11 +1048,12 @@

              'sssd',

              'nss',

              'pam',

-             'dp',

              'domain/PROXY',

              'domain/IPA',

              'domain/LOCAL',

              'domain/LDAP',

+             'domain/INVALIDPROVIDER',

+             'domain/INVALIDOPTION',

              ]

  

          for section in control_list:
@@ -1188,6 +1192,11 @@

          # Negative Test - No such service

          self.assertRaises(SSSDConfig.NoServiceError, sssdconfig.get_service, 'nosuchservice')

  

+         # Positive test - Service with invalid option loads

+         # but ignores the invalid option

+         service = sssdconfig.get_service('pam')

+         self.assertFalse(service.options.has_key('nosuchoption'))

+ 

      def testNewService(self):

          sssdconfig = SSSDConfig.SSSDConfig(srcdir + "/etc/sssd.api.conf",

                                             srcdir + "/etc/sssd.api.d")
@@ -1272,7 +1281,10 @@

  

          control_list = [

              'PROXY',

-             'LDAP']

+             'LDAP',

+             'INVALIDPROVIDER',

+             'INVALIDOPTION',

+             ]

          inactive_domains = sssdconfig.list_inactive_domains()

  

          for domain in control_list:
@@ -1298,7 +1310,10 @@

              'IPA',

              'LOCAL',

              'PROXY',

-             'LDAP']

+             'LDAP',

+             'INVALIDPROVIDER',

+             'INVALIDOPTION',

+             ]

          domains = sssdconfig.list_domains()

  

          for domain in control_list:
@@ -1333,6 +1348,18 @@

          # Negative Test - No such domain

          self.assertRaises(SSSDConfig.NoDomainError, sssdconfig.get_domain, 'nosuchdomain')

  

+         # Positive Test - Domain with unknown provider

+         # Expected result: Domain is imported, but does not contain the

+         # unknown provider entry

+         domain = sssdconfig.get_domain('INVALIDPROVIDER')

+         self.assertFalse(domain.options.has_key('chpass_provider'))

+ 

+         # Positive Test - Domain with unknown option

+         # Expected result: Domain is imported, but does not contain the

+         # unknown option entry

+         domain = sssdconfig.get_domain('INVALIDOPTION')

+         self.assertFalse(domain.options.has_key('nosuchoption'))

+ 

      def testNewDomain(self):

          sssdconfig = SSSDConfig.SSSDConfig(srcdir + "/etc/sssd.api.conf",

                                             srcdir + "/etc/sssd.api.d")

file modified
+2 -1
@@ -46,7 +46,7 @@

  debug_level = int, None, false, 0

  debug_timestamps = bool, None, false

  command = str, None, false

- min_id = int, None, true, 1000

+ min_id = int, None, false

  max_id = int, None, false

  timeout = int, None, false

  enumerate = bool, None, false
@@ -58,6 +58,7 @@

  account_cache_expiration = int, None, false

  filter_users = list, str, false

  filter_groups = list, str, false

+ dns_resolver_timeout = int, None, false

  

  # Special providers

  [provider/permit]

@@ -1,7 +1,9 @@

  [provider/ipa]

  ipa_domain = str, None, true

- ipa_server = str, None, true

+ ipa_server = str, None, false

  ipa_hostname = str, None, false

+ ipa_dyndns_update = bool, None, false

+ ipa_dyndns_iface = str, None, false

  ldap_uri = str, None, false

  ldap_search_base = str, None, false

  ldap_schema = str, None, false
@@ -10,19 +12,22 @@

  ldap_default_authtok = str, None, false

  ldap_network_timeout = int, None, false

  ldap_opt_timeout = int, None, false

- ldap_offline_timeout = int, None, false

  ldap_tls_cacert = str, None, false

+ ldap_tls_cacertdir = str, None, false

  ldap_tls_reqcert = str, None, false

  ldap_sasl_mech = str, None, false

  ldap_sasl_authid = str, None, false

  krb5_kdcip = str, None, false

  krb5_realm = str, None, false

  krb5_auth_timeout = int, None, false

+ krb5_kpasswd = str, None, false

  ldap_krb5_keytab = str, None, false

  ldap_krb5_init_creds = bool, None, false

  ldap_entry_usn = str, None, false

  ldap_rootdse_last_usn = str, None, false

  ldap_referrals = bool, None, false

+ ldap_krb5_ticket_lifetime = int, None, false

+ ldap_dns_service_name = str, None, false

  

  [provider/ipa/id]

  ldap_search_timeout = int, None, false
@@ -70,8 +75,9 @@

  krb5_ccname_template = str, None, false

  krb5_keytab = str, None, false

  krb5_validate = bool, None, false

+ ldap_pwd_policy = str, None, false

  

  [provider/ipa/access]

  

  [provider/ipa/chpass]

- krb5_changepw_principal = str, None, false

+ 

@@ -1,14 +1,15 @@

  [provider/krb5]

- krb5_kdcip = str, None, true

+ krb5_kdcip = str, None, false

  krb5_realm = str, None, true

  krb5_auth_timeout = int, None, false

+ krb5_kpasswd = str, None, false

  

  [provider/krb5/auth]

  krb5_ccachedir = str, None, false

  krb5_ccname_template = str, None, false

  krb5_keytab = str, None, false

  krb5_validate = bool, None, false

+ krb5_store_password_if_offline = bool, None, false

  

  [provider/krb5/chpass]

- krb5_changepw_principal = str, None, false

- krb5_kpasswd = str, None, false

+ 

@@ -1,5 +1,5 @@

  [provider/ldap]

- ldap_uri = str, None, true

+ ldap_uri = str, None, false

  ldap_search_base = str, None, true

  ldap_schema = str, None, true, rfc2307

  ldap_default_bind_dn = str, None, false
@@ -7,7 +7,6 @@

  ldap_default_authtok = str, None, false

  ldap_network_timeout = int, None, false

  ldap_opt_timeout = int, None, false

- ldap_offline_timeout = int, None, false

  ldap_tls_cacert = str, None, false

  ldap_tls_cacertdir = str, None, false

  ldap_tls_reqcert = str, None, false
@@ -20,6 +19,8 @@

  ldap_entry_usn = str, None, false

  ldap_rootdse_last_usn = str, None, false

  ldap_referrals = bool, None, false

+ ldap_krb5_ticket_lifetime = int, None, false

+ ldap_dns_service_name = str, None, false

  

  [provider/ldap/id]

  ldap_search_timeout = int, None, false
@@ -65,5 +66,8 @@

  [provider/ldap/auth]

  ldap_pwd_policy = str, None, false

  

+ [provider/ldap/access]

+ ldap_access_filter = str, None, false

+ 

  [provider/ldap/chpass]

  

@@ -36,9 +36,22 @@

  auth_provider=ldap

  debug_level = 0

  

- [pam]

+ # Domain containing an invalid provider

+ [domain/INVALIDPROVIDER]

+ ldap_id_use_start_tls = true

+ id_provider  =    ldap

+ auth_provider=ldap

  debug_level = 0

+ chpass_provider = chpass

  

- [dp]

+ # Domain containing an invalid option

+ [domain/INVALIDOPTION]

+ ldap_id_use_start_tls = true

+ id_provider  =    ldap

+ auth_provider=ldap

  debug_level = 0

+ nosuchoption = True

  

+ [pam]

+ debug_level = 0

+ nosuchoption = True

@@ -73,6 +73,10 @@

          for domain in [ s for s in self.sections() if s['name'].startswith("domain/") ]:

              self.delete_option_subtree(domain['value'], 'option', 'magic_private_groups')

  

+         # remove ldap_offline_timeout from all domains

+         for domain in [ s for s in self.sections() if s['name'].startswith("domain/") ]:

+             self.delete_option_subtree(domain['value'], 'option', 'ldap_offline_timeout')

+ 

      def _update_option(self, to_section_name, from_section_name, opts):

          to_section = [ s for s in self.sections() if s['name'].strip() == to_section_name ]

          from_section = [ s for s in self.sections() if s['name'].strip() == from_section_name ]

file modified
+3 -1
@@ -64,7 +64,6 @@

  WITH_PUBCONF_PATH

  WITH_PIPE_PATH

  WITH_INIT_DIR

- WITH_SHADOW_UTILS_PATH

  WITH_TEST_DIR

  WITH_MANPAGES

  WITH_XML_CATALOG
@@ -95,6 +94,8 @@

  m4_include([external/selinux.m4])

  m4_include([external/crypto.m4])

  m4_include([external/nscd.m4])

+ m4_include([external/libkeyutils.m4])

+ m4_include([external/nsupdate.m4])

  m4_include([util/signal.m4])

  

  PKG_CHECK_MODULES([DBUS],[dbus-1])
@@ -153,6 +154,7 @@

  

  abs_build_dir=`pwd`

  AC_DEFINE_UNQUOTED([ABS_BUILD_DIR], ["$abs_build_dir"], [Absolute path to the build directory])

+ AC_SUBST([abs_builddir], $abs_build_dir)

  

  AC_CONFIG_FILES([Makefile examples/rwtab doxy.config po/Makefile.in])

  AC_OUTPUT

file modified
+174
@@ -20,6 +20,7 @@

  */

  

  #include "util/util.h"

+ #include "util/strtonum.h"

  #include "db/sysdb_private.h"

  #include "confdb/confdb.h"

  #include <time.h>
@@ -52,6 +53,36 @@

      return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_GROUP, name, domain);

  }

  

+ errno_t sysdb_group_dn_name(struct sysdb_ctx *ctx, void *memctx,

+                             const char *_dn, char **_name)

+ {

+     struct ldb_dn *dn;

+     const struct ldb_val *val;

+     *_name = NULL;

+ 

+     dn = ldb_dn_new_fmt(memctx, ctx->ldb, "%s", _dn);

+     if (dn == NULL) {

+         return ENOMEM;

+     }

+ 

+     val = ldb_dn_get_rdn_val(dn);

+     if (val == NULL) {

+         talloc_zfree(dn);

+         return EINVAL;

+     }

+ 

+     *_name = talloc_strndup(memctx, (char *) val->data, val->length);

+ 

+     if (!*_name) {

+         talloc_zfree(dn);

+         return ENOMEM;

+     }

+ 

+     talloc_zfree(dn);

+ 

+     return EOK;

+ }

+ 

  struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx,

                                const char *domain)

  {
@@ -140,6 +171,64 @@

      return EOK;

  }

  

+ int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name,

+                              uint32_t *value)

+ {

+     struct ldb_message_element *el;

+     int ret;

+     char *endptr;

+     uint32_t val;

+ 

+     ret = sysdb_attrs_get_el_int(attrs, name, false, &el);

+     if (ret) {

+         return ret;

+     }

+ 

+     if (el->num_values != 1) {

+         return ERANGE;

+     }

+ 

+     val = strtouint32((const char *) el->values[0].data, &endptr, 0);

+     if (errno != 0) return errno;

+     if (*endptr) return EINVAL;

+ 

+     *value = val;

+     return EOK;

+ }

+ 

+ int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,

+                                  TALLOC_CTX *mem_ctx, const char ***string)

+ {

+     struct ldb_message_element *el;

+     int ret;

+     unsigned int u;

+     const char **a;

+ 

+     ret = sysdb_attrs_get_el_int(attrs, name, false, &el);

+     if (ret) {

+         return ret;

+     }

+ 

+     a = talloc_array(mem_ctx, const char *, el->num_values + 1);

+     if (a == NULL) {

+         return ENOMEM;

+     }

+ 

+     memset(a, 0, sizeof(const char *) * (el->num_values + 1));

+ 

+     for(u = 0; u < el->num_values; u++) {

+         a[u] = talloc_strndup(a, (const char *)el->values[u].data,

+                               el->values[u].length);

+         if (a[u] == NULL) {

+             talloc_free(a);

+             return ENOMEM;

+         }

+     }

+ 

+     *string = a;

+     return EOK;

+ }

+ 

  int sysdb_attrs_add_val(struct sysdb_attrs *attrs,

                          const char *name, const struct ldb_val *val)

  {
@@ -176,6 +265,16 @@

      return sysdb_attrs_add_val(attrs, name, &v);

  }

  

+ int sysdb_attrs_add_bool(struct sysdb_attrs *attrs,

+                          const char *name, bool value)

+ {

+     if(value) {

+         return sysdb_attrs_add_string(attrs, name, "TRUE");

+     }

+ 

+     return sysdb_attrs_add_string(attrs, name, "FALSE");

+ }

+ 

  int sysdb_attrs_steal_string(struct sysdb_attrs *attrs,

                               const char *name, char *str)

  {
@@ -1881,3 +1980,78 @@

  

      return EOK;

  }

+ 

+ /* Search for all incidences of attr_name in a list of

+  * sysdb_attrs and add their value to a list

+  *

+  * TODO: Currently only works for single-valued

+  * attributes. Multi-valued attributes will return

+  * only the first entry

+  */

+ errno_t sysdb_attrs_to_list(TALLOC_CTX *memctx,

+                             struct sysdb_attrs **attrs,

+                             int attr_count,

+                             const char *attr_name,

+                             char ***_list)

+ {

+     int attr_idx;

+     int i;

+     char **list;

+     char **tmp_list;

+     int list_idx;

+ 

+     *_list = NULL;

+ 

+     /* Assume that every attrs entry contains the attr_name

+      * This may waste a little memory if some entries don't

+      * have the attribute, but it will save us the trouble

+      * of continuously resizing the array.

+      */

+     list = talloc_array(memctx, char *, attr_count+1);

+     if (!list) {

+         return ENOMEM;

+     }

+ 

+     list_idx = 0;

+     /* Loop through all entries in attrs */

+     for (attr_idx = 0; attr_idx < attr_count; attr_idx++) {

+         /* Examine each attribute within the entry */

+         for (i = 0; i < attrs[attr_idx]->num; i++) {

+             if (strcasecmp(attrs[attr_idx]->a[i].name, attr_name) == 0) {

+                 /* Attribute name matches the requested name

+                  * Copy it to the output list

+                  */

+                 list[list_idx] = talloc_strdup(

+                         list,

+                         (const char *)attrs[attr_idx]->a[i].values[0].data);

+                 if (!list[list_idx]) {

+                     talloc_free(list);

+                     return ENOMEM;

+                 }

+                 list_idx++;

+ 

+                 /* We only support single-valued attributes

+                  * Break here and go on to the next entry

+                  */

+                 break;

+             }

+         }

+     }

+ 

+     list[list_idx] = NULL;

+ 

+     /* if list_idx < attr_count, do a realloc to

+      * reclaim unused memory

+      */

+     if (list_idx < attr_count) {

+         tmp_list = talloc_realloc(memctx, list, char *, list_idx+1);

+         if (!tmp_list) {

+             talloc_zfree(list);

+             return ENOMEM;

+         }

+         list = tmp_list;

+     }

+ 

+     *_list = list;

+     return EOK;

+ }

file modified
+52 -3
@@ -162,6 +162,8 @@

                          const char *name, const struct ldb_val *val);

  int sysdb_attrs_add_string(struct sysdb_attrs *attrs,

                             const char *name, const char *str);

+ int sysdb_attrs_add_bool(struct sysdb_attrs *attrs,

+                          const char *name, bool value);

  int sysdb_attrs_add_long(struct sysdb_attrs *attrs,

                           const char *name, long value);

  int sysdb_attrs_add_uint32(struct sysdb_attrs *attrs,
@@ -174,6 +176,10 @@

                               const char *name, char *str);

  int sysdb_attrs_get_string(struct sysdb_attrs *attrs, const char *name,

                             const char **string);

+ int sysdb_attrs_get_string_array(struct sysdb_attrs *attrs, const char *name,

+                                  TALLOC_CTX *mem_ctx, const char ***string);

+ int sysdb_attrs_get_uint32_t(struct sysdb_attrs *attrs, const char *name,

+                              uint32_t *value);

  

  int sysdb_attrs_replace_name(struct sysdb_attrs *attrs, const char *oldname,

                                   const char *newname);
@@ -196,6 +202,8 @@

                               const char *domain, const char *name);

  struct ldb_dn *sysdb_group_dn(struct sysdb_ctx *ctx, void *memctx,

                                const char *domain, const char *name);

+ errno_t sysdb_group_dn_name(struct sysdb_ctx *ctx, void *memctx,

+                             const char *dn_str, char **name);

  struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx,

                                 const char *domain);

  struct ldb_dn *sysdb_custom_dn(struct sysdb_ctx *ctx, void *memctx,
@@ -445,6 +453,14 @@

                                               const char *shell);

  int sysdb_add_basic_user_recv(struct tevent_req *req);

  

+ /* Add fake (expired) user */

+ struct tevent_req *sysdb_add_fake_user_send(TALLOC_CTX *mem_ctx,

+                                             struct tevent_context *ev,

+                                             struct sysdb_handle *handle,

+                                             struct sss_domain_info *domain,

+                                             const char *name);

+ int sysdb_add_fake_user_recv(struct tevent_req *req);

+ 

  /* Add user (all checks) */

  struct tevent_req *sysdb_add_user_send(TALLOC_CTX *mem_ctx,

                                         struct tevent_context *ev,
@@ -477,6 +493,14 @@

                                          int cache_timeout);

  int sysdb_add_group_recv(struct tevent_req *req);

  

+ /* Add a incomplete, expired group */

+ struct tevent_req *sysdb_add_incomplete_group_send(TALLOC_CTX *mem_ctx,

+                                              struct tevent_context *ev,

+                                              struct sysdb_handle *handle,

+                                              struct sss_domain_info *domain,

+                                              const char *name, gid_t gid);

+ int sysdb_add_incomplete_group_recv(struct tevent_req *req);

+ 

  /* mod_op must be either LDB_FLAG_MOD_ADD or LDB_FLAG_MOD_DELETE */

  struct tevent_req *sysdb_mod_group_member_send(TALLOC_CTX *mem_ctx,

                                                 struct tevent_context *ev,
@@ -515,12 +539,18 @@

                                            uint64_t cache_timeout);

  int sysdb_store_group_recv(struct tevent_req *req);

  

+ enum sysdb_member_type {

+     SYSDB_MEMBER_USER,

+     SYSDB_MEMBER_GROUP

+ };

+ 

  struct tevent_req *sysdb_add_group_member_send(TALLOC_CTX *mem_ctx,

                                                 struct tevent_context *ev,

                                                 struct sysdb_handle *handle,

                                                 struct sss_domain_info *domain,

                                                 const char *group,

-                                                const char *member);

+                                                const char *member,

+                                                enum sysdb_member_type type);

  int sysdb_add_group_member_recv(struct tevent_req *req);

  

  struct tevent_req *sysdb_remove_group_member_send(TALLOC_CTX *mem_ctx,
@@ -528,9 +558,21 @@

                                                    struct sysdb_handle *handle,

                                                    struct sss_domain_info *domain,

                                                    const char *group,

-                                                   const char *member);

+                                                   const char *member,

+                                                   enum sysdb_member_type type);

  int sysdb_remove_group_member_recv(struct tevent_req *req);

  

+ 

+ struct tevent_req *sysdb_update_members_send(TALLOC_CTX *mem_ctx,

+                                              struct tevent_context *ev,

+                                              struct sysdb_handle *handle,

+                                              struct sss_domain_info *domain,

+                                              const char *member,

+                                              enum sysdb_member_type type,

+                                              char **add_groups,

+                                              char **del_groups);

+ errno_t sysdb_update_members_recv(struct tevent_req *req);

+ 

  /* Password caching function.

   * If you are in a transaction ignore sysdb and pass in the handle.

   * If you are not in a transaction pass NULL in handle and provide sysdb,
@@ -557,7 +599,8 @@

                                           const char *name,

                                           const uint8_t *authtok,

                                           size_t authtok_size,

-                                          struct confdb_ctx *cdb);

+                                          struct confdb_ctx *cdb,

+                                          bool just_check);

  int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date,

                            time_t *delayed_until);

  
@@ -647,4 +690,10 @@

                                             const char *name, gid_t gid);

  int sysdb_delete_group_recv(struct tevent_req *req);

  

+ errno_t sysdb_attrs_to_list(TALLOC_CTX *memctx,

+                             struct sysdb_attrs **attrs,

+                             int attr_count,

+                             const char *attr_name,

+                             char ***_list);

+ 

  #endif /* __SYS_DB_H__ */

file modified
+602 -11
@@ -2061,6 +2061,191 @@

      return sysdb_op_default_recv(req);

  }

  

+ /* =Add-A-Fake-User====================================================== */

+ 

+ struct sysdb_add_fake_user_state {

+     struct tevent_context *ev;

+     struct sysdb_handle *handle;

+     struct sss_domain_info *domain;

+ 

+     const char *name;

+ };

+ 

+ static void sysdb_add_fake_user_group_check(struct tevent_req *subreq);

+ static int sysdb_add_fake_user_op(struct tevent_req *req);

+ static void sysdb_add_fake_user_op_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *sysdb_add_fake_user_send(TALLOC_CTX *mem_ctx,

+                                             struct tevent_context *ev,

+                                             struct sysdb_handle *handle,

+                                             struct sss_domain_info *domain,

+                                             const char *name)

+ {

+     struct tevent_req *req, *subreq;

+     struct sysdb_add_fake_user_state *state;

+     int ret;

+ 

+     req = tevent_req_create(mem_ctx, &state,

+                             struct sysdb_add_fake_user_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->handle = handle;

+     state->domain = domain;

+     state->name = name;

+ 

+     if (handle->ctx->mpg) {

+         /* In MPG domains you can't have groups with the same name as users,

+          * search if a user with the same name exists.

+          * Don't worry about users, if we try to add a user with the same

+          * name the operation will fail */

+         subreq = sysdb_search_group_by_name_send(state, ev, NULL, handle,

+                                                  domain, name, NULL);

+         if (!subreq) {

+             ERROR_OUT(ret, ENOMEM, fail);

+         }

+         tevent_req_set_callback(subreq, sysdb_add_fake_user_group_check, req);

+         return req;

+     }

+ 

+     /* try to add the user */

+     ret = sysdb_add_fake_user_op(req);

+     if (ret != EOK) goto fail;

+ 

+     return req;

+ 

+ fail:

+     DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+     tevent_req_error(req, ret);

+     tevent_req_post(req, ev);

+     return req;

+ }

+ 

+ static void sysdb_add_fake_user_group_check(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sysdb_add_fake_user_state *state = tevent_req_data(req,

+                                            struct sysdb_add_fake_user_state);

+     struct ldb_message *msg;

+     int ret;

+ 

+     /* We can succeed only if we get an ENOENT error, which means no users

+      * with the same name exist.

+      * If any other error is returned fail as well. */

+     ret = sysdb_search_user_recv(subreq, state, &msg);

+     talloc_zfree(subreq);

+     if (ret != ENOENT) {

+         if (ret == EOK) ret = EEXIST;

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* try to add the user */

+     ret = sysdb_add_fake_user_op(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+     }

+ }

+ 

+ static int sysdb_add_fake_user_op(struct tevent_req *req)

+ {

+     struct sysdb_add_fake_user_state *state = tevent_req_data(req,

+                                            struct sysdb_add_fake_user_state);

+     struct ldb_message *msg;

+     struct tevent_req *subreq;

+     struct ldb_request *ldbreq;

+     int ret;

+     time_t now;

+ 

+     msg = ldb_msg_new(state);

+     if (!msg) {

+         return ENOMEM;

+     }

+ 

+     /* user dn */

+     msg->dn = sysdb_user_dn(state->handle->ctx, msg,

+                             state->domain->name, state->name);

+     if (!msg->dn) {

+         return ENOMEM;

+     }

+ 

+     now = time(NULL);

+ 

+     ret = add_string(msg, LDB_FLAG_MOD_ADD, "objectClass", SYSDB_USER_CLASS);

+     if (ret) return ret;

+ 

+     ret = add_string(msg, LDB_FLAG_MOD_ADD, SYSDB_NAME, state->name);

+     if (ret) return ret;

+ 

+     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CREATE_TIME,

+                     (unsigned long) now);

+     if (ret) return ret;

+ 

+     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_LAST_UPDATE,

+                     (unsigned long) now);

+     if (ret) return ret;

+ 

+     /* set last login so that the fake entry does not get cleaned up

+      * immediately */

+     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_LAST_LOGIN,

+                     (unsigned long) now);

+     if (ret) return ret;

+ 

+     ret = add_ulong(msg, LDB_FLAG_MOD_ADD, SYSDB_CACHE_EXPIRE,

+                     (unsigned long) now-1);

+     if (ret) return ret;

+ 

+     ret = ldb_build_add_req(&ldbreq, state->handle->ctx->ldb, state, msg,

+                             NULL, NULL, NULL, NULL);

+     if (ret != LDB_SUCCESS) {

+         DEBUG(1, ("Failed to build modify request: %s(%d)[%s]\n",

+                   ldb_strerror(ret), ret, ldb_errstring(state->handle->ctx->ldb)));

+         return sysdb_error_to_errno(ret);

+     }

+ 

+     subreq = sldb_request_send(state, state->ev,

+                                state->handle->ctx->ldb, ldbreq);

+     if (!subreq) {

+         return ENOMEM;

+     }

+     tevent_req_set_callback(subreq, sysdb_add_fake_user_op_done, req);

+ 

+     return EOK;

+ }

+ 

+ static void sysdb_add_fake_user_op_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                   struct tevent_req);

+     struct sysdb_add_fake_user_state *state = tevent_req_data(req,

+                                             struct sysdb_add_fake_user_state);

+     struct ldb_reply *ldbreply;

+     int ret;

+ 

+     ret = sldb_request_recv(subreq, state, &ldbreply);

+     talloc_zfree(subreq);

+     if (ret) {

+         DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (ldbreply->type != LDB_REPLY_DONE) {

+         DEBUG(6, ("Error: %d (%s)\n", EIO, strerror(EIO)));

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ int sysdb_add_fake_user_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

  

  /* =Add-Basic-Group-NO-CHECKS============================================= */

  
@@ -2448,6 +2633,181 @@

  }

  

  

+ /* =Add-A-Incomplete-Group====================================================== */

+ 

+ struct sysdb_add_incomplete_group_state {

+     struct tevent_context *ev;

+     struct sysdb_handle *handle;

+     struct sss_domain_info *domain;

+ 

+     const char *name;

+     gid_t gid;

+ };

+ 

+ static void sysdb_add_incomplete_group_user_check(struct tevent_req *subreq);

+ static void sysdb_add_incomplete_group_basic_done(struct tevent_req *subreq);

+ static void sysdb_add_incomplete_group_set_attrs_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *sysdb_add_incomplete_group_send(TALLOC_CTX *mem_ctx,

+                                              struct tevent_context *ev,

+                                              struct sysdb_handle *handle,

+                                              struct sss_domain_info *domain,

+                                              const char *name, gid_t gid)

+ {

+     struct tevent_req *req, *subreq;

+     struct sysdb_add_incomplete_group_state *state;

+     int ret;

+ 

+     req = tevent_req_create(mem_ctx, &state,

+                             struct sysdb_add_incomplete_group_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->handle = handle;

+     state->domain = domain;

+     state->name = name;

+     state->gid = gid;

+ 

+     if (handle->ctx->mpg) {

+         /* In MPG domains you can't have groups with the same name as users,

+          * search if a user with the same name exists.

+          * Don't worry about groups, if we try to add a group with the same

+          * name the operation will fail */

+ 

+         subreq = sysdb_search_user_by_name_send(state, ev, NULL, handle,

+                                                 domain, name, NULL);

+         if (!subreq) {

+             ERROR_OUT(ret, ENOMEM, fail);

+         }

+         tevent_req_set_callback(subreq, sysdb_add_incomplete_group_user_check, req);

+         return req;

+     }

+ 

+     /* try to add the group */

+     subreq = sysdb_add_basic_group_send(state, ev, handle,

+                                         domain, name, gid);

+     if (!subreq) {

+         ERROR_OUT(ret, ENOMEM, fail);

+     }

+     tevent_req_set_callback(subreq, sysdb_add_incomplete_group_basic_done, req);

+     return req;

+ 

+ fail:

+     DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+     tevent_req_error(req, ret);

+     tevent_req_post(req, ev);

+     return req;

+ }

+ 

+ static void sysdb_add_incomplete_group_user_check(struct tevent_req *subreq)

+ {

+ 

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sysdb_add_incomplete_group_state *state = tevent_req_data(req,

+                                            struct sysdb_add_incomplete_group_state);

+     struct ldb_message *msg;

+     int ret;

+ 

+     /* We can succeed only if we get an ENOENT error, which means no users

+      * with the same name exist.

+      * If any other error is returned fail as well. */

+     ret = sysdb_search_user_recv(subreq, state, &msg);

+     talloc_zfree(subreq);

+     if (ret != ENOENT) {

+         if (ret == EOK) ret = EEXIST;

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* try to add the group */

+     subreq = sysdb_add_basic_group_send(state, state->ev,

+                                         state->handle, state->domain,

+                                         state->name, state->gid);

+     if (!subreq) {

+         DEBUG(6, ("Error: Out of memory\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sysdb_add_incomplete_group_basic_done, req);

+ }

+ 

+ static void sysdb_add_incomplete_group_basic_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sysdb_add_incomplete_group_state *state = tevent_req_data(req,

+                                            struct sysdb_add_incomplete_group_state);

+     int ret;

+     struct sysdb_attrs *attrs;

+     time_t now;

+ 

+     ret = sysdb_add_basic_group_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret) {

+         DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     attrs = sysdb_new_attrs(state);

+     if (!attrs) {

+         DEBUG(6, ("Error: Out of memory\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     now = time(NULL);

+ 

+     ret = sysdb_attrs_add_time_t(attrs, SYSDB_LAST_UPDATE, now);

+     if (ret) {

+         DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     ret = sysdb_attrs_add_time_t(attrs, SYSDB_CACHE_EXPIRE,

+                                  now-1);

+     if (ret) {

+         DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     subreq = sysdb_set_group_attr_send(state, state->ev,

+                                        state->handle, state->domain,

+                                        state->name, attrs,

+                                        SYSDB_MOD_REP);

+     if (!subreq) {

+         DEBUG(6, ("Error: Out of memory\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sysdb_add_incomplete_group_set_attrs_done, req);

+ }

+ 

+ static void sysdb_add_incomplete_group_set_attrs_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     int ret;

+ 

+     ret = sysdb_set_group_attr_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret) {

+         DEBUG(6, ("Error: %d (%s)\n", ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ int sysdb_add_incomplete_group_recv(struct tevent_req *req)

+ {

+     return sysdb_op_default_recv(req);

+ }

+ 

  /* =Add-Or-Remove-Group-Memeber=========================================== */

  

  /* mod_op must be either SYSDB_MOD_ADD or SYSDB_MOD_DEL */
@@ -2967,11 +3327,12 @@

                                                 struct sysdb_handle *handle,

                                                 struct sss_domain_info *domain,

                                                 const char *group,

-                                                const char *user)

+                                                const char *member,

+                                                enum sysdb_member_type type)

  {

      struct tevent_req *req, *subreq;

      struct sysdb_op_state *state;

-     struct ldb_dn *group_dn, *user_dn;

+     struct ldb_dn *group_dn, *member_dn;

      int ret;

  

      req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state);
@@ -2987,13 +3348,24 @@

          ERROR_OUT(ret, ENOMEM, fail);

      }

  

-     user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user);

-     if (!user_dn) {

+     if (type == SYSDB_MEMBER_USER) {

+         member_dn = sysdb_user_dn(handle->ctx, state,

+                                   domain->name,

+                                   member);

+     } else if (type == SYSDB_MEMBER_GROUP) {

+         member_dn = sysdb_group_dn(handle->ctx, state,

+                                    domain->name,

+                                    member);

+     } else {

+         ERROR_OUT(ret, EINVAL, fail);

+     }

+ 

+     if (!member_dn) {

          ERROR_OUT(ret, ENOMEM, fail);

      }

  

      subreq = sysdb_mod_group_member_send(state, ev, handle,

-                                          user_dn, group_dn,

+                                          member_dn, group_dn,

                                           SYSDB_MOD_ADD);

      if (!subreq) {

          ERROR_OUT(ret, ENOMEM, fail);
@@ -3041,11 +3413,12 @@

                                                    struct sysdb_handle *handle,

                                                    struct sss_domain_info *domain,

                                                    const char *group,

-                                                   const char *user)

+                                                   const char *member,

+                                                   enum sysdb_member_type type)

  {

      struct tevent_req *req, *subreq;

      struct sysdb_op_state *state;

-     struct ldb_dn *group_dn, *user_dn;

+     struct ldb_dn *group_dn, *member_dn;

      int ret;

  

      req = tevent_req_create(mem_ctx, &state, struct sysdb_op_state);
@@ -3061,13 +3434,20 @@

          ERROR_OUT(ret, ENOMEM, fail);

      }

  

-     user_dn = sysdb_user_dn(handle->ctx, state, domain->name, user);

-     if (!user_dn) {

+     if (type == SYSDB_MEMBER_USER) {

+         member_dn = sysdb_user_dn(handle->ctx, state, domain->name, member);

+     } else if (type == SYSDB_MEMBER_GROUP) {

+         member_dn = sysdb_group_dn(handle->ctx, state, domain->name, member);

+     } else {

+         ERROR_OUT(ret, EINVAL, fail);

+     }

+ 

+     if (!member_dn) {

          ERROR_OUT(ret, ENOMEM, fail);

      }

  

      subreq = sysdb_mod_group_member_send(state, ev, handle,

-                                          user_dn, group_dn,

+                                          member_dn, group_dn,

                                           SYSDB_MOD_DEL);

      if (!subreq) {

          ERROR_OUT(ret, ENOMEM, fail);
@@ -4645,6 +5025,7 @@

      struct sss_domain_info *domain;

      struct sysdb_ctx *sysdb;

      struct confdb_ctx *cdb;

+     bool just_check;

      struct sysdb_attrs *update_attrs;

      bool authentication_successful;

      struct sysdb_handle *handle;
@@ -4724,7 +5105,8 @@

                                           const char *name,

                                           const uint8_t *authtok,

                                           size_t authtok_size,

-                                          struct confdb_ctx *cdb)

+                                          struct confdb_ctx *cdb,

+                                          bool just_check)

  {

      struct tevent_req *req;

      struct tevent_req *subreq;
@@ -4774,6 +5156,7 @@

      state->domain = domain;

      state->sysdb = sysdb;

      state->cdb = cdb;

+     state->just_check = just_check;

      state->update_attrs = NULL;

      state->authentication_successful = false;

      state->handle = NULL;
@@ -4888,6 +5271,11 @@

          DEBUG(4, ("Hashes do match!\n"));

          state->authentication_successful = true;

  

+         if (state->just_check) {

+             ret = EOK;

+             goto done;

+         }

+ 

          ret = sysdb_attrs_add_time_t(state->update_attrs, SYSDB_LAST_LOGIN,

                                       time(NULL));

          if (ret != EOK) {
@@ -5057,3 +5445,206 @@

  

      return (state->authentication_successful ? EOK : EINVAL);

  }

+ 

+ struct sysdb_update_members_ctx {

+     char *member;

+     struct sss_domain_info *domain;

+     struct tevent_context *ev;

+     struct sysdb_handle *handle;

+ 

+     enum sysdb_member_type membertype;

+ 

+     char **add_groups;

+     int add_group_iter;

+ 

+     char **del_groups;

+     int del_group_iter;

+ };

+ 

+ static char **empty_string_list(TALLOC_CTX *mem_ctx)

+ {

+     char **empty;

+     empty = talloc_array(mem_ctx, char *, 1);

+     if (!empty) {

+         return NULL;

+     }

+ 

+     empty[0] = NULL;

+ 

+     return empty;

+ }

+ 

+ static errno_t

+ sysdb_update_members_step(struct tevent_req *req);

+ 

+ struct tevent_req *sysdb_update_members_send(TALLOC_CTX *mem_ctx,

+                                              struct tevent_context *ev,

+                                              struct sysdb_handle *handle,

+                                              struct sss_domain_info *domain,

+                                              const char *member,

+                                              enum sysdb_member_type type,

+                                              char **add_groups,

+                                              char **del_groups)

+ {

+     errno_t ret;

+     struct tevent_req *req;

+     struct sysdb_update_members_ctx *state;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct sysdb_update_members_ctx);

+     if (!req) {

+         return NULL;

+     }

+ 

+     state->member = talloc_strdup(state, member);

+     if (!state->member) {

+         goto error;

+     }

+ 

+     state->domain = domain;

+     state->ev = ev;

+     state->handle = handle;

+     state->membertype = type;

+ 

+     if (add_groups) {

+         state->add_groups = dup_string_list(state, (const char**)add_groups);

+     }

+     else {

+         state->add_groups = empty_string_list(state);

+     }

+     if (!state->add_groups) {

+         goto error;

+     }

+     state->add_group_iter = 0;

+ 

+     if (del_groups) {

+         state->del_groups = dup_string_list(state, (const char **)del_groups);

+     }

+     else {

+         state->del_groups = empty_string_list(state);

+     }

+     if (!state->del_groups) {

+         goto error;

+     }

+     state->del_group_iter = 0;

+ 

+     if (state->add_groups[state->add_group_iter] == NULL &&

+         state->del_groups[state->del_group_iter] == NULL) {

+         /* Nothing to do */

+         tevent_req_done(req);

+         tevent_req_post(req, state->ev);

+         return req;

+     }

+ 

+     ret = sysdb_update_members_step(req);

+     if (ret != EOK) {

+         /* Nothing to do. Finish up */

+         tevent_req_error(req, ret);

+         tevent_req_post(req, state->ev);

+     }

+ 

+     return req;

+ 

+ error:

+     talloc_free(req);

+     return NULL;

+ }

+ 

+ static void

+ sysdb_update_members_add_done(struct tevent_req *subreq);

+ static void

+ sysdb_update_members_del_done(struct tevent_req *subreq);

+ 

+ static errno_t

+ sysdb_update_members_step(struct tevent_req *req)

+ {

+     struct tevent_req *subreq;

+     struct sysdb_update_members_ctx *state;

+ 

+     state = tevent_req_data(req, struct sysdb_update_members_ctx);

+ 

+     if (state->add_groups[state->add_group_iter]) {

+         subreq = sysdb_add_group_member_send(

+                 state, state->ev, state->handle,

+                 state->domain,

+                 state->add_groups[state->add_group_iter],

+                 state->member, state->membertype);

+         if (!subreq) {

+             return EIO;

+         }

+ 

+         tevent_req_set_callback(subreq, sysdb_update_members_add_done, req);

+         return EOK;

+     }

+ 

+     if (state->del_groups[state->del_group_iter]) {

+         subreq = sysdb_remove_group_member_send(

+                 state, state->ev,

+                 state->handle, state->domain,

+                 state->del_groups[state->del_group_iter],

+                 state->member, state->membertype);

+         if (!subreq) {

+             return EIO;

+         }

+ 

+         tevent_req_set_callback(subreq, sysdb_update_members_del_done, req);

+         return EOK;

+     }

+ 

+     /* No more members to handle */

+     tevent_req_done(req);

+     return EOK;

+ }

+ 

+ static void

+ sysdb_update_members_add_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sysdb_update_members_ctx *state =

+             tevent_req_data(req, struct sysdb_update_members_ctx);

+ 

+     ret = sysdb_add_group_member_recv(subreq);

+     talloc_zfree(subreq);

+     if(ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->add_group_iter++;

+     ret = sysdb_update_members_step(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ }

+ 

+ static void

+ sysdb_update_members_del_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sysdb_update_members_ctx *state =

+             tevent_req_data(req, struct sysdb_update_members_ctx);

+ 

+     ret = sysdb_remove_group_member_recv(subreq);

+     talloc_zfree(subreq);

+     if(ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->del_group_iter++;

+     ret = sysdb_update_members_step(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ }

+ 

+ errno_t

+ sysdb_update_members_recv(struct tevent_req *req)

+ {

+     return sysdb_op_default_recv(req);

+ }

file modified
+34 -17
@@ -1,40 +1,49 @@

  [sssd]

  config_file_version = 2

+ 

  # Number of times services should attempt to reconnect in the

  # event of a crash or restart before they give up

  reconnection_retries = 3

- # if a backend is particularly slow you can raise this timeout here

+ 

+ # If a back end is particularly slow you can raise this timeout here

  sbus_timeout = 30

  services = nss, pam

- ; domains = LOCAL,LDAP

- # SSSD will not start if you don't configure any domain.

- # Add new domains condifgurations as [domain/<NAME>] sections.

- # Then add the list of domains (in the order you want them to be

- # queried in the 'domains" attribute above and uncomment it

  

+ # SSSD will not start if you do not configure any domains.

+ # Add new domain configurations as [domain/<NAME>] sections, and

+ # then add the list of domains (in the order you want them to be

+ # queried) to the "domains" attribute below and uncomment it.

+ ; domains = LOCAL,LDAP

  

  [nss]

- # the following prevents sssd for searching for the root user/group in

- # all domains (you can add here a comma separated list of system accounts are

- # always going to be /etc/passwd users, or that you want to filter out)

+ # The following prevents SSSD from searching for the root user/group in

+ # all domains (you can add here a comma-separated list of system accounts that

+ # are always going to be /etc/passwd users, or that you want to filter out).

  filter_groups = root

  filter_users = root

  reconnection_retries = 3

  

- # The EntryCacheTimeout indicates the number of seconds to retain before

- # an entry in cache is considered stale and must block to refresh.

- # The EntryCacheNoWaitRefreshTimeout indicates the number of seconds to

+ # The entry_cache_timeout indicates the number of seconds to retain an

+ # entry in cache before it is considered stale and must block to refresh.

+ # The entry_cache_nowait_timeout indicates the number of seconds to

  # wait before updating the cache out-of-band. (NSS requests will still

- # be returned from cache until the full EntryCacheTimeout). Setting this

- # value to 0 turns this feature off (default)

+ # be returned from cache until the full entry_cache_timeout). Setting this

+ # value to 0 turns this feature off (default).

  ; entry_cache_timeout = 600

  ; entry_cache_nowait_timeout = 300

  

  [pam]

  reconnection_retries = 3

  

+ # Example domain configurations

+ # Note that enabling enumeration in the following configurations will have a

+ # moderate performance impact while enumerations are actually running, and

+ # may increase the time necessary to detect network disconnection.

+ # Consequently, the default value for enumeration is FALSE.

+ # Refer to the sssd.conf man page for full details.

+ 

  # Example LOCAL domain that stores all users natively in the SSSD internal

- # directory. These local users and groups are not visibile in /etc/passwd, it

+ # directory. These local users and groups are not visible in /etc/passwd; it

  # now contains only root and system accounts.

  ; [domain/LOCAL]

  ; description = LOCAL Users domain
@@ -44,14 +53,21 @@

  ; max_id = 999

  

  # Example native LDAP domain

+ # ldap_schema can be set to "rfc2307", which uses the "memberuid" attribute

+ # for group membership, or to "rfc2307bis", which uses the "member" attribute

+ # to denote group membership. Changes to this setting affect only how we

+ # determine the groups a user belongs to and will have no negative effect on

+ # data about the user itself. If you do not know this value, ask an

+ # administrator.

  ; [domain/LDAP]

  ; id_provider = ldap

  ; auth_provider = ldap

+ ; ldap_schema = rfc2307

  ; ldap_uri = ldap://ldap.mydomain.org

- ; ldap_user_search_base = dc=mydomain,dc=org

+ ; ldap_search_base = dc=mydomain,dc=org

  ; ldap_tls_reqcert = demand

  ; cache_credentials = true

- ; enumerate = true

+ ; enumerate = False

  

  # Example LDAP domain where the LDAP server is an Active Directory server.

  
@@ -79,3 +95,4 @@

  ; ldap_group_object_class = group

  ; ldap_group_name = msSFU30Name

  ; ldap_group_gid_number = msSFU30GidNumber

+ ; ldap_force_upper_case_realm = True

file modified
+1 -1
@@ -58,5 +58,5 @@

                  [have_locate_plugin=no]

                  [AC_MSG_NOTICE([Kerberos locator plugin cannot be build])])

  AM_CONDITIONAL([BUILD_KRB5_LOCATOR_PLUGIN],

-                [test x$have_locate_plugin == xyes -a x$build_locator == xyes])

+                [test x$have_locate_plugin = xyes -a x$build_locator = xyes])

  

@@ -0,0 +1,11 @@

+ AC_SUBST(KEYUTILS_LIBS)

+ 

+ AC_CHECK_HEADERS([keyutils.h],

+                  [AC_CHECK_LIB([keyutils], [add_key],

+                                [AC_DEFINE(USE_KEYRING, 1, [Define if the keyring should be used])

+                                 KEYUTILS_LIBS="-lkeyutils"

+                                ],

+                                [AC_MSG_WARN([No usable keyutils library found])]

+                               )],

+                  [AC_MSG_WARN([keyutils header files are not available])]

+ )

@@ -0,0 +1,8 @@

+ AC_PATH_PROG(NSUPDATE, nsupdate)

+ AC_MSG_CHECKING(for nsupdate)

+ if test -x "$NSUPDATE"; then

+   AC_DEFINE_UNQUOTED([NSUPDATE_PATH], ["$NSUPDATE"], [The path to nsupdate])

+   AC_MSG_RESULT(yes)

+ else

+   AC_MSG_ERROR([no. nsupdate is not available])

+ fi

file modified
+11 -7
@@ -3,9 +3,10 @@

             )

  osname=""

  if test x"$with_os" != x ; then

-     if test x"$with_os" == xfedora -o \

-             x"$with_os" == xredhat -o \

-             x"$with_os" == xsuse ; then

+     if test x"$with_os" = xfedora || \

+        test x"$with_os" = xredhat || \

+        test x"$with_os" = xsuse || \

+        test x"$with_os" = xdebian ; then

          osname=$with_os

      else

          AC_MSG_ERROR([Illegal value -$with_os- for option --with-os])
@@ -19,14 +20,17 @@

          osname="redhat"

      elif test -f /etc/SuSE-release ; then

          osname="suse"

+     elif test -f /etc/debian_version ; then

+         osname="debian"

      fi

  

-     AC_MSG_NOTICE([Detected operation system type: $osname])

+     AC_MSG_NOTICE([Detected operating system type: $osname])

  fi

  

- AM_CONDITIONAL([HAVE_FEDORA], [test x"$osname" == xfedora])

- AM_CONDITIONAL([HAVE_REDHAT], [test x"$osname" == xredhat])

- AM_CONDITIONAL([HAVE_SUSE], [test x"$osname" == xsuse])

+ AM_CONDITIONAL([HAVE_FEDORA], [test x"$osname" = xfedora])

+ AM_CONDITIONAL([HAVE_REDHAT], [test x"$osname" = xredhat])

+ AM_CONDITIONAL([HAVE_SUSE], [test x"$osname" = xsuse])

+ AM_CONDITIONAL([HAVE_DEBIAN], [test x"$osname" = xdebian])

  

  AC_CHECK_MEMBERS([struct ucred.pid, struct ucred.uid, struct ucred.gid], , ,

                   [[#define _GNU_SOURCE

@@ -67,13 +67,12 @@

      va_start(ap, format);

  

      ret = vasprintf(&s, format, ap);

+     va_end(ap);

      if (ret < 0) {

          /* ENOMEM */

          return;

      }

  

-     va_end(ap);

- 

      fprintf(stderr, DEBUG_KEY "%s", s);

      free(s);

  }
@@ -133,7 +132,7 @@

      memset(buf, 0, BUFSIZE+1);

      while (len != 0 && (ret = read(fd, p, len)) != 0) {

          if (ret == -1) {

-             if (errno == EINTR) continue;

+             if (errno == EINTR || errno == EAGAIN) continue;

              PLUGIN_DEBUG(("read failed [%d][%s].\n", errno, strerror(errno)));

              close(fd);

              goto done;
@@ -223,7 +222,7 @@

      const char *dummy;

  

      ctx = calloc(1,sizeof(struct sssd_ctx));

-     if (ctx == NULL) return ENOMEM;

+     if (ctx == NULL) return KRB5_PLUGIN_NO_HANDLE;

  

      dummy = getenv(SSSD_KRB5_LOCATOR_DEBUG);

      if (dummy == NULL) {
@@ -280,7 +279,7 @@

          ctx->sssd_realm = strdup(realm);

          if (ctx->sssd_realm == NULL) {

              PLUGIN_DEBUG(("strdup failed.\n"));

-             return ENOMEM;

+             return KRB5_PLUGIN_NO_HANDLE;

          }

  

          ret = get_krb5info(realm, ctx, locate_service_kdc);
@@ -326,7 +325,7 @@

          case locate_service_krb524:

              return KRB5_PLUGIN_NO_HANDLE;

          default:

-             return EINVAL;

+             return KRB5_PLUGIN_NO_HANDLE;

      }

  

      switch (family) {
@@ -343,7 +342,7 @@

          case SOCK_DGRAM:

              break;

          default:

-             return EINVAL;

+             return KRB5_PLUGIN_NO_HANDLE;

      }

  

      if (strcmp(realm, ctx->sssd_realm) != 0)
@@ -353,7 +352,7 @@

      ret = snprintf(port_str, PORT_STR_SIZE-1, "%u", port);

      if (ret < 0 || ret >= (PORT_STR_SIZE-1)) {

          PLUGIN_DEBUG(("snprintf failed.\n"));

-         return EFAULT;

+         return KRB5_PLUGIN_NO_HANDLE;

      }

  

      memset(&ai_hints, 0, sizeof(struct addrinfo));
@@ -368,7 +367,7 @@

              PLUGIN_DEBUG(("getaddrinfo failed [%d][%s].\n", errno,

                                                              strerror(errno)));

          }

-         return EFAULT;

+         return KRB5_PLUGIN_NO_HANDLE;

      }

  

      PLUGIN_DEBUG(("addr[%s:%s] family[%d] socktype[%d]\n", addr, port_str,

@@ -0,0 +1,36 @@

+ <refsect1 id='service_discovery'>

+     <title>SERVICE DISCOVERY</title>

+     <para>

+         The service discovery feature allows back ends to automatically

+         find the appropriate servers to connect to using a special DNS

+         query.

+     </para>

+     <refsect2 id='configuration'>

+         <title>Configuration</title>

+         <para>

+             If no servers are specified, the back end automatically

+             uses service discovery to try to find a server. Optionally,

+             the user may choose to use both fixed server addresses

+             and service discovery by inserting a special keyword,

+             <quote>_srv_</quote>, in the list of servers. The order

+             of preference is maintained. This feature is useful if, for

+             example, the user prefers to use service discovery whenever

+             possible, and fall back to a specific server when no servers

+             can be discovered using DNS.

+         </para>

+     </refsect2>

+     <refsect2 id='domain_name'>

+         <title>The domain name</title>

+         <para>

+             The name of the SSSD domain is used as the domain part of the

+             service discovery DNS query.

+         </para>

+     </refsect2>

+     <refsect2 id='reference'>

+         <title>See Also</title>

+         <para>

+             For more information on the service discovery mechanism,

+             refer to RFC 2782.

+         </para>

+     </refsect2>

+ </refsect1>

file modified
+39
@@ -31,6 +31,9 @@

              <arg choice='opt'>

                  <replaceable>use_authtok</replaceable>

              </arg>

+             <arg choice='opt'>

+                 <replaceable>retry=N</replaceable>

+             </arg>

          </cmdsynopsis>

      </refsynopsisdiv>

  
@@ -75,6 +78,20 @@

                      password module.</para>

                  </listitem>

              </varlistentry>

+             <varlistentry>

+                 <term>

+                     <option>retry=N</option>

+                 </term>

+                 <listitem>

+                     <para>If specified the user is asked another N times for a

+                     password if authentication fails. Default is 0.</para>

+                     <para>Please note that this option might not work as

+                     expected if the application calling PAM handles the user

+                     dialog on its own. A typical example is

+                     <command>sshd</command> with

+                     <option>PasswordAuthentication</option>.</para>

+                 </listitem>

+             </varlistentry>

          </variablelist>

      </refsect1>

  
@@ -85,6 +102,28 @@

          </para>

      </refsect1>

  

+     <refsect1 id='files'>

+         <title>FILES</title>

+         <para>If a password reset by root fails, because the corresponding SSSD

+         provider does not support password resets, an individual message can be

+         displayed. This message can e.g. contain instructions about how to reset

+         a password.</para>

+ 

+         <para>The message is read from the file

+         <filename>pam_sss_pw_reset_message.LOC</filename> where LOC stands for a

+         locale string returned by <citerefentry>

+         <refentrytitle>setlocale</refentrytitle><manvolnum>3</manvolnum>

+         </citerefentry>. If there is no matching file the content of

+         <filename>pam_sss_pw_reset_message.txt</filename> is displayed. Root

+         must be the owner of the files and only root may have read and write

+         permissions while all other users must have only read

+         permisssions.</para>

+ 

+         <para>These files are searched in the directory

+         <filename>/etc/sssd/customize/DOMAIN_NAME/</filename>. If no matching

+         file is present a generic message is displayed.</para>

+     </refsect1>

+ 

      <refsect1 id='see_also'>

          <title>SEE ALSO</title>

          <para>

file modified
-13
@@ -52,19 +52,6 @@

              </varlistentry>

              <varlistentry>

                  <term>

-                     <option>-g</option>,<option>--gid</option>

-                     <replaceable>GID</replaceable>

-                 </term>

-                 <listitem>

-                     <para>

-                         Set the GID or group membership of the user to the value

-                         of <replaceable>GID</replaceable>. If not given, it is

-                         chosen automatically.

-                     </para>

-                 </listitem>

-             </varlistentry>

-             <varlistentry>

-                 <term>

                      <option>-c</option>,<option>--gecos</option>

                      <replaceable>COMMENT</replaceable>

                  </term>

file modified
+32
@@ -82,6 +82,8 @@

                              on failover and server redundancy, see the

                              <quote>FAILOVER</quote> section.

                              This is optional if autodiscovery is enabled.

+                             For more information on service discovery, refer

+                             to the the <quote>SERVICE DISCOVERY</quote> section.

                          </para>

                      </listitem>

                  </varlistentry>
@@ -98,6 +100,34 @@

                  </varlistentry>

  

                  <varlistentry>

+                     <term>ipa_dyndns_update (boolean)</term>

+                     <listitem>

+                         <para>

+                             Optional. This option tells SSSD to automatically

+                             update the DNS server built into FreeIPA v2 with

+                             the IP address of this client.

+                         </para>

+                         <para>

+                             Default: false

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

+                 <varlistentry>

+                     <term>ipa_dyndns_iface (string)</term>

+                     <listitem>

+                         <para>

+                             Optional. Applicable only when ipa_dyndns_update

+                             is true. Choose the interface whose IP address

+                             should be used for dynamic DNS updates.

+                         </para>

+                         <para>

+                             Default: Use the IP address of the IPA LDAP connection

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

+                 <varlistentry>

                      <term>krb5_validate (boolean)</term>

                      <listitem>

                          <para>
@@ -120,6 +150,8 @@

  

      <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/failover.xml" />

  

+     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/service_discovery.xml" />

+ 

      <refsect1 id='example'>

          <title>EXAMPLE</title>

          <para>

file modified
+28 -16
@@ -72,6 +72,9 @@

                              see the <quote>FAILOVER</quote> section. An optional

                              port number (preceded by a colon) may be appended to

                              the addresses or hostnames.

+                             If empty, service discovery is enabled -

+                             for more information, refer to the

+                             <quote>SERVICE DISCOVERY</quote> section.

                          </para>

                      </listitem>

                  </varlistentry>
@@ -80,22 +83,8 @@

                      <term>krb5_realm (string)</term>

                      <listitem>

                          <para>

-                             The name of the Kerberos realm.

-                         </para>

-                     </listitem>

-                 </varlistentry>

- 

-                 <varlistentry>

-                     <term>krb5_changepw_principal (string)</term>

-                     <listitem>

-                         <para>

-                             The priciple of the change password service.

-                             If only the 'identifier/instance' part of the

-                             principal are given the realm part is added

-                             automatically.

-                         </para>

-                         <para>

-                             Default: kadmin/changepw

+                             The name of the Kerberos realm. This option is required

+                             and must be specified.

                          </para>

                      </listitem>

                  </varlistentry>
@@ -116,6 +105,9 @@

                              servers to try the back end is not switch to offline

                              if authentication against the KDC is still possible.

                          </para>

+                         <para>

+                             Default: Use the KDC

+                         </para>

                      </listitem>

                  </varlistentry>

  
@@ -238,12 +230,32 @@

                      </listitem>

                  </varlistentry>

  

+                 <varlistentry>

+                     <term>krb5_store_password_if_offline (boolean)</term>

+                     <listitem>

+                         <para>

+                             Store the password of the user if the provider is

+                             offline and use it to request a TGT when the

+                             provider gets online again.

+                         </para>

+                         <para>

+                             Please note that this feature currently only

+                             available on a Linux plattform.

+                         </para>

+                         <para>

+                             Default: false

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

              </variablelist>

          </para>

      </refsect1>

  

      <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/failover.xml" />

  

+     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/service_discovery.xml" />

+ 

      <refsect1 id='example'>

          <title>EXAMPLE</title>

          <para>

file modified
+114 -4
@@ -61,9 +61,8 @@

                              Specifies the list of URIs of the LDAP servers to which

                              SSSD should connect in the order of preference. Refer to the

                              <quote>FAILOVER</quote> section for more information on failover and server redundancy.

-                         </para>

-                         <para>

-                             Default: ldap://localhost

+                             If not specified, service discovery is enabled. For more information, refer

+                             to the <quote>SERVICE DISCOVERY</quote> section.

                          </para>

                      </listitem>

                  </varlistentry>
@@ -258,7 +257,7 @@

                      <listitem>

                          <para>

                              The LDAP attribute that contains the user's Kerberos

-                             User Principle Name (UPN).

+                             User Principal Name (UPN).

                          </para>

                          <para>

                              Default: krbPrincipalName
@@ -296,6 +295,25 @@

                  </varlistentry>

  

                  <varlistentry>

+                     <term>ldap_purge_cache_timeout</term>

+                     <listitem>

+                         <para>

+                             Determine how often to check the cache for

+                             inactive entries (such as groups with no

+                             members and users who have never logged in) and

+                             remove them to save space.

+                         </para>

+                         <para>

+                             Setting this option to zero will disable the

+                             cache cleanup operation.

+                         </para>

+                         <para>

+                             Default: 0 (disabled)

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

+                 <varlistentry>

                      <term>ldap_user_member_of (string)</term>

                      <listitem>

                          <para>
@@ -387,6 +405,31 @@

                  </varlistentry>

  

                  <varlistentry>

+                     <term>ldap_search_timeout (integer)</term>

+                     <listitem>

+                         <para>

+                             Specifies the timeout (in seconds) that ldap

+                             searches are allowed to run before they are

+                             cancelled and cached results are returned (and

+                             offline mode is entered)

+                         </para>

+                         <para>

+                             Default: 5 (When enumerate = False)

+                         </para>

+                         <para>

+                             Default: 30 (When enumerate = True - this option

+                             will be forced to a minumum of 30s in this case)

+                         </para>

+                         <para>

+                             Note: this option is subject to change in future

+                             versions of the SSSD. It will likely be replaced

+                             at some point by a series of timeouts for

+                             specific lookup types.

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

+                 <varlistentry>

                      <term>ldap_network_timeout (integer)</term>

                      <listitem>

                          <para>
@@ -570,6 +613,19 @@

                  </varlistentry>

  

                  <varlistentry>

+                     <term>ldap_krb5_ticket_lifetime (integer)</term>

+                     <listitem>

+                         <para>

+                             Specifies the lifetime in seconds of the TGT if

+                             GSSAPI is used.

+                         </para>

+                         <para>

+                             Default: 86400 (24 hours)

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

+                 <varlistentry>

                      <term>krb5_realm (string)</term>

                      <listitem>

                          <para>
@@ -632,12 +688,66 @@

                      </listitem>

                  </varlistentry>

  

+                 <varlistentry>

+                     <term>ldap_dns_service_name (string)</term>

+                     <listitem>

+                         <para>

+                             Specifies the service name to use when service

+                             discovery is enabled.

+                         </para>

+                         <para>

+                             Default: ldap

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

+                 <varlistentry>

+                     <term>ldap_access_filter (string)</term>

+                     <listitem>

+                         <para>

+                             If using access_provider = ldap, this option is

+                             mandatory. It specifies an LDAP search filter

+                             criteria that must be met for the user to be

+                             granted access on this host. If

+                             access_provider = ldap and this option is

+                             not set, it will result in all users being

+                             denied access. Use access_provider = allow to

+                             change this default behavior.

+                         </para>

+                         <para>

+                             Example:

+                         </para>

+                         <programlisting>

+ access_provider = ldap

+ ldap_access_filter = memberOf=cn=allowedusers,ou=Groups,dc=example,dc=com

+                         </programlisting>

+                         <para>

+                             This example means that access to this host is

+                             restricted to members of the "allowedusers" group

+                             in ldap.

+                         </para>

+                         <para>

+                             Offline caching for this feature is limited to

+                             determining whether the user's last online login

+                             was granted access permission. If they were

+                             granted access during their last login, they will

+                             continue to be granted access while offline and

+                             vice-versa.

+                         </para>

+                         <para>

+                             Default: Empty

+                         </para>

+                     </listitem>

+                 </varlistentry>

+ 

              </variablelist>

          </para>

      </refsect1>

  

      <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/failover.xml" />

  

+     <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="include/service_discovery.xml" />

+ 

      <refsect1 id='example'>

          <title>EXAMPLE</title>

          <para>

file modified
+46 -5
@@ -289,7 +289,7 @@

                      <term>entry_negative_timeout (integer)</term>

                      <listitem>

                          <para>

-                             Specifies for how long nss_sss should cache

+                             Specifies for how many seconds nss_sss should cache

                              negative cache hits (that is, queries for

                              invalid database entries, like nonexistent ones)

                              before asking the back end again.
@@ -396,11 +396,19 @@

                      <term>min_id,max_id (integer)</term>

                      <listitem>

                          <para>

-                             UID limits for the domain. If a domain contains

-                             entry that is outside these limits, it is ignored

+                             UID and GID limits for the domain. If a domain

+                             contains an entry that is outside these limits, it

+                             is ignored.

                          </para>

                          <para>

-                             Default: 1000 for min_id, 0 (no limit) for max_id

+                             For users, this affects the primary GID limit. The

+                             user will not be returned to NSS if either the

+                             UID or the primary GID is outside the range. For

+                             non-primary group memberships, those that are in

+                             range will be reported as expected.

+                         </para>

+                         <para>

+                             Default: 1 for min_id, 0 (no limit) for max_id

                          </para>

                      </listitem>

                  </varlistentry>
@@ -435,6 +443,24 @@

                          <para>

                              Default: FALSE

                          </para>

+                         <para>

+                             Note: Enabling enumeration has a moderate

+                             performance impact on SSSD while enumeration

+                             is running. It may take up to several minutes

+                             after SSSD startup to fully complete enumerations.

+                             During this time, individual requests for

+                             information will go directly to LDAP, though it

+                             may be slow, due to the heavy enumeration

+                             processing.

+                         </para>

+                         <para>

+                             Further, enabling enumeration may increase the time

+                             necessary to detect network disconnection, as

+                             longer timeouts are required to ensure that

+                             enumeration lookups are completed successfully.

+                             For more information, refer to the man pages for

+                             the specific id_provider in use.

+                         </para>

                      </listitem>

                  </varlistentry>

  
@@ -641,6 +667,21 @@

                          </para>

                      </listitem>

                  </varlistentry>

+ 

+                 <varlistentry>

+                     <term>dns_resolver_timeout (integer)</term>

+                     <listitem>

+                         <para>

+                             Defines the amount of time (in seconds) to wait for a reply from

+                             the DNS resolver before assuming that it is unreachable. If this

+                             timeout is reached, the domain will continue to operate in

+                             offline mode.

+                         </para>

+                         <para>

+                             Default: 5

+                         </para>

+                     </listitem>

+                 </varlistentry>

              </variablelist>

          </para>

  
@@ -833,7 +874,7 @@

  

  min_id = 10000

  max_id = 20000

- enumerate = true

+ enumerate = False

  </programlisting>

          </para>

      </refsect1>

file modified
+113 -135
@@ -1145,16 +1145,91 @@

                           void *siginfo,

                           void *private_data)

  {

+     struct mt_ctx *mt_ctx = talloc_get_type(private_data, struct mt_ctx);

+     struct mt_svc *svc;

+     pid_t pid;

+     int status;

+     errno_t error;

+     int kret;

+     bool killed;

+ 

      DEBUG(8, ("Received shutdown command\n"));

-     monitor_cleanup();

+ 

+     DEBUG(0, ("Monitor received %s: terminating children\n",

+               strsignal(signum)));

+ 

+     /* Kill all of our known children manually */

+     DLIST_FOR_EACH(svc, mt_ctx->svc_list) {

+         if (svc->pid == 0) {

+             /* The local provider has no PID */

+             continue;

+         }

+ 

+         killed = false;

+         DEBUG(1, ("Terminating [%s][%d]\n", svc->name, svc->pid));

+         do {

+             errno = 0;

+             kret = kill(svc->pid, SIGTERM);

+             if (kret < 0) {

+                 error = errno;

+                 DEBUG(1, ("Couldn't kill [%s][%d]: [%s]\n",

+                           svc->name, svc->pid, strerror(error)));

+             }

+ 

+             do {

+                 errno = 0;

+                 pid = waitpid(svc->pid, &status, WNOHANG);

+                 if (pid == -1) {

+                     /* An error occurred while waiting */

+                     error = errno;

+                     if (error != EINTR) {

+                         DEBUG(0, ("[%d][%s] while waiting for [%s]\n",

+                                   error, strerror(error), svc->name));

+                         /* Forcibly kill this child */

+                         kill(svc->pid, SIGKILL);

+                         break;

+                     }

+                 } else if (pid != 0) {

+                     error = 0;

+                     if WIFEXITED(status) {

+                         DEBUG(1, ("Child [%s] exited gracefully\n", svc->name));

+                     } else if WIFSIGNALED(status) {

+                         DEBUG(1, ("Child [%s] terminated with a signal\n", svc->name));

+                     } else {

+                         DEBUG(0, ("Child [%s] did not exit cleanly\n", svc->name));

+                         /* Forcibly kill this child */

+                         kill(svc->pid, SIGKILL);

+                     }

+                     killed = true;

+                 }

+             } while (error == EINTR);

+             if (!killed) {

+                 /* Sleep 10ms and try again */

+                 usleep(10000);

+             }

+         } while (!killed);

+     }

  

  #if HAVE_GETPGRP

+     /* Kill any remaining children in our process group, just in case

+      * we have any leftover children we don't expect. For example, if

+      * a krb5_child or ldap_child is running at the same moment.

+      */

+     error = 0;

      if (getpgrp() == getpid()) {

-         DEBUG(0,("%s: killing children\n", strsignal(signum)));

          kill(-getpgrp(), SIGTERM);

+         do {

+             errno = 0;

+             pid = waitpid(0, &status, 0);

+             if (pid == -1) {

+                 error = errno;

+             }

+         } while (error == EINTR || pid > 0);

      }

  #endif

  

+     monitor_cleanup();

+ 

      exit(0);

  }

  
@@ -1371,7 +1446,8 @@

      while (total_len < event_size) {

          len = read(file_ctx->mt_ctx->inotify_fd, buf+total_len,

                     event_size-total_len);

-         if (len == -1 && errno != EINTR) {

+         if (len == -1) {

+             if (errno == EINTR || errno == EAGAIN) continue;

              DEBUG(0, ("Critical error reading inotify file descriptor.\n"));

              goto done;

          }
@@ -1391,7 +1467,8 @@

          total_len = 0;

          while (total_len < in_event->len) {

              len = read(file_ctx->mt_ctx->inotify_fd, &name, in_event->len);

-             if (len == -1 && errno != EINTR) {

+             if (len == -1) {

+                 if (errno == EINTR || errno == EAGAIN) continue;

                  DEBUG(0, ("Critical error reading inotify file descriptor.\n"));

                  goto done;

              }
@@ -1433,7 +1510,7 @@

          rw_ctx->file_ctx = file_ctx;

  

          tev = tevent_add_timer(ev, rw_ctx, tv, rewatch_config_file, rw_ctx);

-         if (te == NULL) {

+         if (tev == NULL) {

              DEBUG(0, ("Could not restore inotify watch. Quitting!\n"));

              close(file_ctx->mt_ctx->inotify_fd);

              kill(getpid(), SIGTERM);
@@ -1486,7 +1563,7 @@

                    cb->filename, err, strerror(err)));

  

          tev = tevent_add_timer(ev, ev, tv, rewatch_config_file, rw_ctx);

-         if (te == NULL) {

+         if (tev == NULL) {

              DEBUG(0, ("Could not restore inotify watch. Quitting!\n"));

              close(file_ctx->mt_ctx->inotify_fd);

              kill(getpid(), SIGTERM);
@@ -1692,6 +1769,36 @@

      int num_providers;

      int ret;

  

+     /* Set up an event handler for a SIGHUP */

+     tes = tevent_add_signal(ctx->ev, ctx, SIGHUP, 0,

+                             monitor_hup, ctx);

+     if (tes == NULL) {

+         return EIO;

+     }

+ 

+     /* Set up an event handler for a SIGINT */

+     BlockSignals(false, SIGINT);

+     tes = tevent_add_signal(ctx->ev, ctx, SIGINT, 0,

+                             monitor_quit, ctx);

+     if (tes == NULL) {

+         return EIO;

+     }

+ 

+     /* Set up an event handler for a SIGTERM */

+     tes = tevent_add_signal(ctx->ev, ctx, SIGTERM, 0,

+                             monitor_quit, ctx);

+     if (tes == NULL) {

+         return EIO;

+     }

+ 

+     /* Handle SIGUSR1 (tell all providers to go offline) */

+     BlockSignals(false, SIGUSR1);

+     tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,

+                             signal_offline, ctx);

+     if (tes == NULL) {

+         return EIO;

+     }

+ 

  #if 0

      This feature is incomplete and can leave the SSSD in a bad state if the

      config file is changed while the SSSD is running.
@@ -1769,35 +1876,6 @@

      /* now start checking for global events */

      set_global_checker(ctx);

  

-     /* Set up an event handler for a SIGHUP */

-     tes = tevent_add_signal(ctx->ev, ctx, SIGHUP, 0,

-                             monitor_hup, ctx);

-     if (tes == NULL) {

-         return EIO;

-     }

- 

-     /* Set up an event handler for a SIGINT */

-     tes = tevent_add_signal(ctx->ev, ctx, SIGINT, 0,

-                             monitor_quit, ctx);

-     if (tes == NULL) {

-         return EIO;

-     }

- 

-     /* Set up an event handler for a SIGTERM */

-     tes = tevent_add_signal(ctx->ev, ctx, SIGTERM, 0,

-                             monitor_quit, ctx);

-     if (tes == NULL) {

-         return EIO;

-     }

- 

-     /* Handle SIGUSR1 (tell all providers to go offline) */

-     BlockSignals(false, SIGUSR1);

-     tes = tevent_add_signal(ctx->ev, ctx, SIGUSR1, 0,

-                             signal_offline, ctx);

-     if (tes == NULL) {

-         return EIO;

-     }

- 

      return EOK;

  }

  
@@ -1989,106 +2067,6 @@

      return ECHILD;

  }

  

- static void free_args(char **args)

- {

-     int i;

- 

-     if (args) {

-         for (i = 0; args[i]; i++) free(args[i]);

-         free(args);

-     }

- }

- 

- 

- /* parse a string into arguments.

-  * arguments are separated by a space

-  * '\' is an escape character and can be used only to escape

-  * itself or the white space.

-  */

- static char **parse_args(const char *str)

- {

-     const char *p;

-     char **ret, **r;

-     char *tmp;

-     int num;

-     int i, e;

- 

-     tmp = malloc(strlen(str) + 1);

-     if (!tmp) return NULL;

- 

-     ret = NULL;

-     num = 0;

-     e = 0;

-     i = 0;

-     p = str;

-     while (*p) {

-         switch (*p) {

-         case '\\':

-             if (e) {

-                 tmp[i] = '\\';

-                 i++;

-                 e = 0;

-             } else {

-                 e = 1;

-             }

-             break;

-         case ' ':

-             if (e) {

-                 tmp[i] = ' ';

-                 i++;

-                 e = 0;

-             } else {

-                 tmp[i] = '\0';

-                 i++;

-             }

-             break;

-         default:

-             if (e) {

-                 tmp[i] = '\\';

-                 i++;

-                 e = 0;

-             }

-             tmp[i] = *p;

-             i++;

-             break;

-         }

- 

-         p++;

- 

-         /* check if this was the last char */

-         if (*p == '\0') {

-             if (e) {

-                 tmp[i] = '\\';

-                 i++;

-                 e = 0;

-             }

-             tmp[i] = '\0';

-             i++;

-         }

-         if (tmp[i-1] != '\0' || strlen(tmp) == 0) {

-             /* check next char and skip multiple spaces */

-             continue;

-         }

- 

-         r = realloc(ret, (num + 2) * sizeof(char *));

-         if (!r) goto fail;

-         ret = r;

-         ret[num+1] = NULL;

-         ret[num] = strdup(tmp);

-         if (!ret[num]) goto fail;

-         num++;

-         i = 0;

-     }

- 

-     free(tmp);

-     return ret;

- 

- fail:

-     free(tmp);

-     free_args(ret);

-     return NULL;

- }

- 

  static void service_startup_handler(struct tevent_context *ev,

                                      struct tevent_timer *te,

                                      struct timeval t, void *ptr);

file modified
+252 -163
@@ -8,10 +8,11 @@

  msgstr ""

  "Project-Id-Version: SSS\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2009-12-09 11:13+0100\n"

  "Last-Translator: Fabian Affolter <fab@fedoraproject.org>\n"

  "Language-Team: German <fedora-trans-de@redhat.com>\n"

+ "Language: de\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=utf-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -160,436 +161,498 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "IPA-Domain"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "IPA-Serveradresse"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "IPA-Client-Rechnername"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Kerberos-Serveradresse"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Kerberos Realm"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr ""

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr ""

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr ""

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr ""

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

+ #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

- #: config/SSSDConfig.py:103

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr ""

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr ""

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr ""

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr ""

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

  msgstr ""

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

  msgstr ""

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr ""

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr ""

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr ""

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr ""

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr ""

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr ""

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr ""

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr ""

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Benutzername-Attribut"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "UID-Attribut"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "GECOS-Attribut"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Shell-Attribut"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "UUID-Attribut"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr ""

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Vollständiger Name"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr ""

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr ""

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr ""

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr ""

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr ""

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr ""

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr ""

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr ""

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr ""

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr ""

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr ""

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr ""

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr ""

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr ""

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr ""

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

  msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ""

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

  msgstr ""

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr ""

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr ""

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr ""

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr ""

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr ""

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr ""

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr ""

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr ""

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Bneutzerverzeichnis"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Anmelde-Shell"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Gruppen"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr ""

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr ""

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr ""

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr ""

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr ""

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr ""

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr ""

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr ""

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr ""

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr ""

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr ""

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr ""

  
@@ -658,8 +721,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr ""

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -678,143 +741,169 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, fuzzy, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "Gruppen"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr ""

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr ""

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr ""

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr ""

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr ""

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr ""

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr ""

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr ""

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr ""

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr ""

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr ""

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Das Konto sperren"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Das Konto entsperren"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr ""

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"

  msgstr ""

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr ""

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr ""

  
@@ -823,6 +912,6 @@

  msgid "%s must be run as root\n"

  msgstr ""

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

file modified
+285 -170
@@ -8,10 +8,11 @@

  msgstr ""

  "Project-Id-Version: sss_daemon 0.4.0\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

- "PO-Revision-Date: 2010-03-15 11:40-0300\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

+ "PO-Revision-Date: 2010-08-24 12:56-0300\n"

  "Last-Translator: Héctor Daniel Cabrera <logan@fedoraproject.org>\n"

  "Language-Team: Fedora Spanish <trans-es@lists.fedoraproject.org>\n"

+ "Language: \n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -173,237 +174,263 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr "Por cuánto tiempo permitir ingresos cacheados luego del último (días)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ "Cantidad de tiempo (en segundos) a esperar respuestas desde DNS cuando se "

+ "estén resolviendo servidores"

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "Dominio IPA"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "Dirección del servidor IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "Nombre de equipo del cliente IPA"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ "Si actualizar automáticamente, o no, la entrada DNS del cliente en FreeIPA "

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ "La interfaz cuya IP debería ser utilizada para actualizaciones DNS dinámicas"

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Dirección del servidor Kerberos"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Reinado Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Expiración de la autenticación"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "Directorio donde almacenar las credenciales cacheadas"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Ubicación del caché de credenciales del usuario"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Ubicación de la tabla de claves para validar las credenciales"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Habilitar la validación de credenciales"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "El principal del servicio de cambio de contraseña"

- 

  #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

+ msgstr ""

+ "Si se encuentra desconectado, almacena contraseñas para realizar luego "

+ "autenticaciones en línea "

+ 

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  "El servidor en donde está ejecutándose el servicio de modificación de "

  "contraseña, en caso de no ser KDC. "

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, El URI del servidor LDAP"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "DN base predeterminado"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "El Tipo de Esquema a usar en el servidor LDAP, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "El DN Bind predeterminado"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "El tipo del token de autenticación del DN bind predeterminado"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "El token de autenticación del DN bind predeterminado"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Tiempo durante el que se intentará la conexión"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Tiempo durante el que se intentará operaciones LDAP sincrónicas"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Tiempo entre intentos de reconexión cuando esté fuera de línea"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

+ msgstr "Archivo que contiene los certificados CA"

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

- msgstr "archivo que contiene los certificados CA"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr "Ruta al directorio de certificaciones CA"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Requiere la verificación de certificado TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Especificar el mecanismo sasl a usar"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Especifique el id de autorización sasl a usar"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Tabla de clave del servicio Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Usar auth Kerberos para la conexión LDAP"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr "Seguir referencias LDAP"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Período de vida de TGT para la conexión LDAP"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Tiempo máximo a esperar un pedido de búsqueda"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Tiempo en segundos entre las actualizaciones de enumeración"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

- msgstr "Requiere TLS para búsquedas de ID, falso"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

+ msgstr "Se necesita TLS para búsquedas de ID"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "DN base para búsquedas de usuario"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Ambito de las búsquedas del usuario"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Filtro para las búsquedas del usuario"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Objectclass para los usuarios"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Atributo Username"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Atributo UID"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Atributo GID primario"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Atributo GECOS"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Atributo Directorio de inicio"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Atributo shell"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Atributo UUID"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Atributo principal del usuario (para Kerberos) "

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Nombre completo"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Atributo memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Atributo hora de modificación"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Política para evaluar el vencimiento de la contraseña"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr "Filtro LDAP para determinar privilegios de acceso"

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Lista separada por comas de usuarios autorizados"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Lista separada por comas de usuarios prohibidos"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Shell predeterminado, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Base de los directorios de inicio"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "Nombre de la biblioteca NSS a usar"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "Pila PAM a usar"

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "Convertirse en demonio (predeterminado)"

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "Ejecutarse en forma interactiva (no un demonio)"

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "Indicar un archivo de configuración diferente al predeterminado"

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd debe ejecutarse como root\n"

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"
@@ -412,7 +439,7 @@

  "nscd pueden entrar en conflicto con SSSD, se recomienda no ejecutar nscd en "

  "forma paralalea con SSSD\n"

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "
@@ -421,198 +448,242 @@

  "No es posible leer el archivo de configuración %s, por favor verifique que "

  "los permisos sean 0600, y que su deueño sea root.root\n"

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr "No es posible cargar base de datos de configuración\n"

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "Nive de depuración"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "Agregar marcas de tiempo de depuración"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr "Un arhivo abierto de descriptor para los registros de depuración"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr "Dominio del proveedor de información (obligatorio)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr "El zócalo privilegiado posee pertenencia o permisos incorrectos."

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr "El zócalo público posee pertenencia o permisos incorrectos."

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr "Formato no esperado de mensaje de credencial del servidor."

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr "SSSD no está siendo ejecutado por el usuario root."

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr "Ha ocurrido un error, pero no se ha encontrado una descripción."

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ "Ha ocurrido un error no esperado mientras se buscaba una descripción del "

+ "error."

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Las contraseñas no coinciden"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Autenticación fuera de línea."

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr "No existe soporte para el reinicio de contraseña por el usuario root."

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr "Autenticado con credenciales cacheadas"

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ", su contraseña cacheada vencerá el:"

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

- msgstr "Autenticación fuera de línea, la autenticación se deniega hasta:"

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr "Su contraseña ha expirado. Le quedan %d registros excepcionales."

+ 

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr "Su contraseña vencerá en %d %s."

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr "La autenticación ha sido negada hasta:"

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "El sistema está fuera de línea, no se puede cambiar la contraseña"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Falló el cambio de contraseña."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Mensaje del servidor:"

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nueva contraseña: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Reingrese la contraseña nueva:"

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Contraseña: "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Contraseña actual: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "La contraseña ha expirado. Modifíquela en este preciso momento."

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr "Nivel de depuración en que se debe ejecutar"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "El UID del usuario"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "El GID o nombre de grupo del usuario"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "La cadena de comentarios"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Directorio de inicio"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Shell de ingreso"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Grupos"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Crear el directorio del usuario si no existe"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr ""

  "La opción de nunca crear el directorio del usuario, anula la configurada"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Debe especificar un directorio esqueleto alternativo"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr "El usuario SELinux para el registro del usuario"

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "Error al poner la región\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Especifique el usuario a agregar\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "Error al inicializar las herramientas -  no hay dominio local\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Error al inicializar las herramientas\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "Dominio inválido especificado en FQDN\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Error interno al analizar sintácticamente los parámetros.\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Los grupos deben estar en el mismo dominio que el usuario\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "No se pudo encontrar el grupo %s en el dominio local\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "No se pudo obtener la información del grupo del usuario\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "No se pudieron establecer los valores predeterminados\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "El UID seleccionado está fuera del rango permitido\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr "No es posible definir contexto de registro SELinux\n"

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "No se pudo obtener información del usuario\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  "El directorio de inicio del usuario ya existe, no copiar datos desde el "

  "esqueleto\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "No se pudo crear el directorio personal del usuario: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "No se pudo crear el receptor de correo del usuario: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "No se pudo asignar el ID para el usuario - ¿el dominio estará lleno?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "Ya existe un usuario o grupo con el mismo nombre o ID\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Error en la transacción. No se pudo agregar el usuario.\n"

  
@@ -686,8 +757,8 @@

  msgstr ""

  "Los grupos miembro deben estar en el mismo dominio que el grupo padre\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -711,26 +782,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Error de transacción. No se pudo modificar el grupo.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%sGrupo: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "Magia privada"

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sGID número: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr "%sMember usuarios: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"
@@ -739,7 +810,7 @@

  "\n"

  "%sEs miembro de: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"
@@ -748,19 +819,19 @@

  "\n"

  "%sGrupos de miembro: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "Imprime miembros de grupo indirecto en forma recursiva"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "Especifica el grupo a mostrar\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "No es posible iniciar la búsqueda\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"
@@ -768,76 +839,105 @@

  "No existe tal grupo en el dominio local. Imprimir los grupos está permitido "

  "únicamente en el dominio local.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "Error interno. No se pudo imprimir el grupo.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Eliminar el directorio de inicio y el receptor de correo"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "No eliminar el directorio de inicio y el receptor de correo"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Forzar la eliminación de los archivos que no pertenecen al usuario"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr "FInaliza los procesos del usuario antes de eliminarlo"

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Especifique el usuario a borrar\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr "El usuario %s está fuera del rango de ID para el dominio\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr "No es posible reiniciar contexto de registro SELinux\n"

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ "ADVERTENCIA: El usuario (uid %lu) aún se encontraba registrado cuando fue "

+ "eliminado.\n"

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ "No es posible determinar si el usuario estaba registrado en esta plataforma"

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr "Error al verificar si el usuario estaba registrado\n"

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr "El comando post-delete ha fallado: %s\n"

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "No eliminando el directorio de inicio - no pertenece al usuario\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr " Imposible eliminar el directorio de inicio: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  "No existe ese usuario en el dominio local. La eliminación de usuarios se "

  "permite en el dominio local.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Error interno. No se pudo eliminar el usuario.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "El GID del Usuario"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Grupos a los que se debe agregar este usuario"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Grupos desde los que hay que eliminar este usuario"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Bloquear la cuenta"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Desbloquear la cuenta"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Especifique el usuario a modificar\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -845,22 +945,22 @@

  "No se pudo encontrar el usuario en el dominio local, la modificación de los "

  "usuarios se permite solamente en el dominio local\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "No se pudo modificar el usuario - verifique si los nombres de grupo son "

  "correctos\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  "No se pudo modificar el usuario - ¿no será ya miembro de esos grupos?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Error de transacción. No se pudo modificar el usuario.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Falta memoria\n"

  
@@ -869,9 +969,24 @@

  msgid "%s must be run as root\n"

  msgstr "%s se debe ejecutar como root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr "Envia el resultado de la depuración hacia archivos en lugar de stderr"

  

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "El principal del servicio de cambio de contraseña"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "El GID o nombre de grupo del usuario"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "No se pudo obtener la información del grupo del usuario\n"

+ 

+ #~ msgid "Length of time between attempts to reconnect while offline"

+ #~ msgstr "Tiempo entre intentos de reconexión cuando esté fuera de línea"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "Autenticación fuera de línea."

+ 

  #~ msgid "Password has expired."

  #~ msgstr "La contraseña ha expirado."

file modified
+252 -166
@@ -7,10 +7,11 @@

  msgstr ""

  "Project-Id-Version: fr\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2009-11-17 21:05+0100\n"

  "Last-Translator: Pablo Martin-Gomez <pablo.martin-gomez@laposte.net>\n"

  "Language-Team: Français <fedora-trans-fr@redhat.com>\n"

+ "Language: \n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -159,438 +160,500 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

- msgid "IPA domain"

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

  msgstr ""

  

  #: config/SSSDConfig.py:87

- msgid "IPA server address"

+ msgid "IPA domain"

  msgstr ""

  

  #: config/SSSDConfig.py:88

+ msgid "IPA server address"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr ""

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr ""

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr ""

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr ""

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr ""

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr ""

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr ""

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

+ #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

- #: config/SSSDConfig.py:103

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr ""

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr ""

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr ""

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr ""

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

  msgstr ""

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

  msgstr ""

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr ""

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr ""

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr ""

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr ""

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr ""

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr ""

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr ""

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr ""

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr ""

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr ""

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr ""

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr ""

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr ""

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr ""

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr ""

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr ""

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr ""

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr ""

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr ""

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr ""

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr ""

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr ""

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr ""

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr ""

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Les mots de passe ne correspondent pas"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

  msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ""

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

  msgstr ""

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:674

+ #, fuzzy, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr "Le mot de passe a expiré."

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr ""

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  #, fuzzy

  msgid "Password change failed. "

  msgstr "Le mot de passe a expiré."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr ""

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nouveau mot de passe : "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Retaper le nouveau mot de passe : "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Mot de passe : "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  #, fuzzy

  msgid "Current Password: "

  msgstr "Nouveau mot de passe : "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr ""

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr ""

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr ""

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr ""

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr ""

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr ""

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr ""

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr ""

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr ""

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr ""

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr ""

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr ""

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr ""

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr ""

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr ""

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr ""

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr ""

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr ""

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr ""

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr ""

  
@@ -659,8 +722,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr ""

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -679,143 +742,169 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr ""

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr ""

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr ""

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr ""

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr ""

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr ""

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr ""

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr ""

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr ""

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr ""

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr ""

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr ""

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"

  msgstr ""

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr ""

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr ""

  
@@ -824,9 +913,6 @@

  msgid "%s must be run as root\n"

  msgstr ""

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

- 

- #~ msgid "Password has expired."

- #~ msgstr "Le mot de passe a expiré."

file modified
+272 -168
@@ -6,14 +6,14 @@

  msgstr ""

  "Project-Id-Version: sssd\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2010-03-09 10:34+0700\n"

  "Last-Translator: Teguh DC <dheche@songolimo.net>\n"

  "Language-Team: Fedora Indonesia <trans-id@lists.fedoraproject.org>\n"

+ "Language: id\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"

- "Language: id\n"

  "Plural-Forms: nplurals=1; plural=0;\n"

  "X-Generator: Virtaal 0.5.1\n"

  
@@ -160,439 +160,505 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "Domain IPA"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "Alamat server IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "Nama host klien IPA"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Alamat server Kerberos"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Realm Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr ""

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr ""

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr ""

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr ""

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

+ #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

- #: config/SSSDConfig.py:103

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, URI server LDAP"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "Jenis Skema yang digunakan pada server LDAP, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Lamanya waktu untuk mencoba koneksi"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Lamanya waktu untuk mencoba operasi LDAP yang sinkron"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Lamanya waktu antara upaya untuk menyambung kembali saat luring"

- 

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:117

+ #, fuzzy

+ msgid "File that contains CA certificates"

  msgstr "berkas yang berisi sertifikat CA"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Membutuhkan verifikasi sertifikat TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Tentukan mekanisme sasl yang digunakan"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Tentukan id otorisasi sasl yang digunakan"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Keytab layanan Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Gunakan otentikasi Kerberos untuk koneksi LDAP"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ #, fuzzy

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Gunakan otentikasi Kerberos untuk koneksi LDAP"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr ""

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr ""

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

- msgstr ""

+ #: config/SSSDConfig.py:132

+ #, fuzzy

+ msgid "Require TLS for ID lookups"

+ msgstr "Filter pencarian pengguna"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Lingkup pencarian pengguna"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Filter pencarian pengguna"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Objectclass untuk pengguna"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Atribut Nama pengguna"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Atribut UID"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Atribut GID Primer"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Atribut GECOS"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Atribut direktori Home"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Atribut Shell"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Atribut UUID"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Atribut utama pengguna (untuk Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Nama Lengkap"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Atribut memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Atribut waktu modifikasi"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr ""

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Daftar pengguna yang diijinkan dalam format yang dipisahkan koma"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Daftar pengguna yang tidak diijinkan dalam format yang dipisahkan koma"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Shell default, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr ""

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr ""

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr ""

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr ""

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr ""

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr ""

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  #, fuzzy

  msgid "sssd must be run as root\n"

  msgstr "%s harus dijalankan sebagai root\n"

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  #, fuzzy

  msgid "An open file descriptor for the debug logs"

  msgstr "Mengatur verbosity dari pencatatan debug"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr ""

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr ""

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Kata sandi tidak cocok"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Otentikasi luring"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ""

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:723

+ #, fuzzy

+ msgid "Authentication is denied until: "

  msgstr "Otentikasi luring, otentikasi ditolak sampai:"

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "Sistem sedang luring, perubahan kata sandi tidak dimungkinkan"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Perubahan kata sandi gagal."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Pesan server:"

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Kata Sandi Baru: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Masukkan lagi kata sandi baru:"

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Kata sandi:"

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Kata sandi saat ini:"

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr ""

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr ""

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "UID dari pengguna"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "GID atau nama grup pengguna"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "String komentar"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Direktori Home"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Shell login"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Grup"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Buat direktori pengguna jika tidak ada"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "Jangan pernah buat direktori pengguna, timpa konfigurasi"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Tentukan direktori kerangka alternatif"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr ""

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Tentukan pengguna untuk ditambahkan\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Gagal saat menginisialisasi perkakas\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "Domain yang ditentukan dalam FQDN tidak valid\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Terjadi kesalahan internal ketika mengurai parameter\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Grup harus berada dalam domain yang sama dengan pengguna\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Tidak dapat menemukan grup %s dalam domain lokal\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Tidak bisa mendapatkan informasi grup untuk pengguna\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Tidak dapat menetapkan nilai default\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "UID yang dipilih berada di luar rentang yang diizinkan\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Tidak bisa mendapatkan info tentang pengguna\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  "Direktori home milik pengguna sudah ada, tidak menyalin data dari skeldir\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Tidak dapat membuat direktori home milik pengguna: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Tidak dapat membuat spool mail milik pengguna: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "Tidak dapat mengalokasikan ID untuk pengguna - domain penuh?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "Pengguna atau grup dengan nama atau ID yang sama sudah ada\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Kesalahan transaksi. Tidak dapat menambahkan pengguna.\n"

  
@@ -668,8 +734,8 @@

  "Anggota kelompok harus berada dalam domain yang sama sebagaimana kelompok "

  "induknya\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -691,54 +757,54 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Kesalahan transaksi. Tidak bisa memodifikasi grup.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, fuzzy, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "Grup"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr ""

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr ""

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr ""

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  #, fuzzy

  msgid "Specify group to show\n"

  msgstr "Tentukan grup untuk ditambahkan\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  #, fuzzy

  msgid "Cannot initiate search\n"

  msgstr "Tidak bisa mendapatkan info tentang pengguna\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  #, fuzzy

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "
@@ -747,78 +813,104 @@

  "Tidak ada grup seperti itu di domain lokal. Menghapus grup hanya "

  "diperbolehkan dalam domain lokal.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  #, fuzzy

  msgid "Internal error. Could not print group.\n"

  msgstr "Kesalahan internal. Tidak dapat menghapus grup.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Hapus direktori home, dan spool mail"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Jangan hapus direktori home dan spool mail"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Paksa penghapusan berkas yang tidak dimiliki oleh pengguna"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Tentukan pengguna yang akan dihapus\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  "Pengguna %s berada di luar rentang ID yang telah didefinisikan untuk domain\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "Tidak menghapus home dir - tidak dimiliki oleh pengguna\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Tidak dapat menghapus homedir: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  "Tidak ada pengguna seperti itu di domain lokal. Menghapus pengguna hanya "

  "diperbolehkan dalam domain lokal.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Kesalahan internal. Tidak dapat menghapus pengguna.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "GID pengguna"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Pengguna ini akan ditambahkan ke grup"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Pengguna ini akan dihapus dari grup"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Kunci akun"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Buka kunci akun"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Tentukan pengguna untuk dimodifikasi\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -826,21 +918,21 @@

  "Tidak dapat menemukan pengguna dalam domain lokal, memodifikasi pengguna "

  "hanya diperbolehkan dalam domain lokal\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "Tidak bisa memodifikasi pengguna - periksa apakah nama grup sudah benar\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  "Tidak bisa memodifikasi pengguna - pengguna sudah menjadi anggota kelompok?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Kesalahan transaksi. Pengguna tidak dapat dimodifikasi.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Kehabisan memori\n"

  
@@ -849,6 +941,18 @@

  msgid "%s must be run as root\n"

  msgstr "%s harus dijalankan sebagai root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "GID atau nama grup pengguna"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Tidak bisa mendapatkan informasi grup untuk pengguna\n"

+ 

+ #~ msgid "Length of time between attempts to reconnect while offline"

+ #~ msgstr "Lamanya waktu antara upaya untuk menyambung kembali saat luring"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "Otentikasi luring"

file modified
+290 -178
@@ -8,13 +8,15 @@

  msgstr ""

  "Project-Id-Version: it\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

- "PO-Revision-Date: 2010-04-08 16:50+0200\n\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

+ "PO-Revision-Date: 2010-04-08 16:50+0200\n"

  "Last-Translator: Guido Grazioli <guido.grazioli@gmail.com>\n"

  "Language-Team: Italian <trans-it@lists.fedoraproject.org>\n"

+ "Language: it\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"

+ "\n"

  "X-Poedit-Language: Italian\n"

  "X-Poedit-Country: ITALY\n"

  "X-Poedit-SourceCharset: utf-8\n"
@@ -89,7 +91,8 @@

  

  #: config/SSSDConfig.py:60

  msgid "The value of the password field the NSS provider should return"

- msgstr "Il valore del campo password che deve essere ritornato dal provider NSS"

+ msgstr ""

+ "Il valore del campo password che deve essere ritornato dal provider NSS"

  

  #: config/SSSDConfig.py:63

  msgid "How long to allow cached logins between online logins (days)"
@@ -159,8 +162,8 @@

  msgid ""

  "Restrict or prefer a specific address family when performing DNS lookups"

  msgstr ""

- "Restringere o preferire una specifica famiglia di indirizzi per "

- "l'esecuzione di lookup DNS"

+ "Restringere o preferire una specifica famiglia di indirizzi per l'esecuzione "

+ "di lookup DNS"

  

  #: config/SSSDConfig.py:83

  msgid "How long to keep cached entries after last successful login (days)"
@@ -168,236 +171,259 @@

  "Per quanto tempo tenere in cache gli elementi dopo un login che ha avuto "

  "successo (giorni)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "Dominio IPA"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "Indirizzo del server IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "Hostname del client IPA"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Indirizzo del server Kerberos"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Realm Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Timeout di autenticazione"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "Directory in cui salvare le credenziali"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Percorso della cache delle credenziali utente"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Percorso del keytab per la validazione delle credenziali"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Abilita la validazione delle credenziali"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "Il principal del servizio di cambio password"

- 

  #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  "Server dove viene eseguito il servizio di cambio password, se non nel KDC"

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, l'indirizzo del server LDAP"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "Il base DN predefinito"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "Lo Schema Type utilizzato dal server LDAP, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "Il bind DN predefinito"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "Il tipo di token di autenticazione del bind DN predefinito"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "Il token di autenticazione del bind DN predefinito"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Durata del tentativo di connessione"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Durata del tentativo di esecuzione di operazioni LDAP sincrone"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Durata tra tentativi di riconnessione quando offline"

- 

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:117

+ #, fuzzy

+ msgid "File that contains CA certificates"

  msgstr "file che contiene certificati CA"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Richiedere la verifica del certificato TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Specificare il meccanismo sasl da usare"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Specificare l'id di autorizzazione sasl da usare"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Keytab del servizio Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Usare autorizzazione Kerberos per la connessione LDAP"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr "Seguire i referral LDAP"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ #, fuzzy

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Usare autorizzazione Kerberos per la connessione LDAP"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Durata attesa per le richieste di ricerca"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Durata tra gli aggiornamenti alle enumeration"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ #, fuzzy

+ msgid "Require TLS for ID lookups"

  msgstr "Richiedere TLS per gli ID lookup, false"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "Base DN per i lookup utente"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Ambito di applicazione dei lookup utente"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Filtro per i lookup utente"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Objectclass per gli utenti"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Attributo del nome utente"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Attributo UID"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Attributo del GID primario"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Attributo GECOS"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Attributo della home directory"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Attributo della shell"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Attributo UUID"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Attributo user principal (per Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Nome completo"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Attributo memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Attributo data di modifica"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Politica per controllare la scadenza della password"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Lista separata da virgola degli utenti abilitati"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Lista separata da virgola degli utenti non abilitati"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Shell predefinita, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Base delle home directory"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "Il nome della libreria NSS da usare"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "Stack PAM da usare"

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "Esegui come demone (default)"

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "Esegui interattivamente (non come demone)"

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "Specificare un file di configurazione specifico"

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd deve essere eseguito come root\n"

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"
@@ -406,7 +432,7 @@

  "potrebbero generare conflitti con SSSD, non è consigliato eseguirlo in "

  "parallelo a SSSD\n"

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "
@@ -415,198 +441,242 @@

  "Impossibile leggere il file di configurazione %s, controllare che i permessi "

  "siano impostati a 0600 e che il file sia proprietà di root.root\n"

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "Livello debug"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "Includi timestamp di debug"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr "Un descrittore di file aperto per l'output di debug"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr "Dominio del provider di informazioni (obbligatorio)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ #, fuzzy

+ msgid "Unexpected format of the server credential message."

+ msgstr "Percorso della cache delle credenziali utente"

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Le password non coincidono"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Autenticazione offline"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ", la password in cache scadrà il: "

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:674

+ #, fuzzy, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ", la password in cache scadrà il: "

+ 

+ #: sss_client/pam_sss.c:723

+ #, fuzzy

+ msgid "Authentication is denied until: "

  msgstr "Autenticazione offline, l'autenticazione sarà negata fino a:"

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "Il sistema è offline, non è possibile richiedere un cambio password"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Cambio password fallito."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Messaggio del server:"

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nuova password: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Conferma nuova password: "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Password: "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Password corrente: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "Password scaduta. Cambiare la password ora."

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr "Il livello di debug da utilizzare"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "L'UID dell'utente"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "Il GID o il nome del gruppo dell'utente"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "La stringa di commento"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Home directory"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Shell di login"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Gruppi"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Creare la directory utente se non esiste"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "Non creare mai le directory utente, forza la configurazione"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Specificare una directory skeleton alternativa"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

  # locale nel senso di LANG=C, LANG=it_IT.utf8

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "Errore di impostazione del locale\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Specificare un utente da aggiungere\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "Errore durante l'inizializzazione degli strumenti - nessun dominio\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Errore durante l'inizializzazione degli strumenti\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "Il dominio specificato nel FQDN non è valido\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Errore interno nel parsing dei parametri\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "I gruppi devono essere nello stesso dominio dell'utente\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Impossibile trovare il gruppo %s nel dominio locale\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Impossibile determinare i gruppi dell'utente\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Impossibile impostare i valori predefiniti\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "L'UID specificato non rientra nel range permesso\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Impossibile determinare le informazioni dell'utente\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

- "La directory home dell'utente esiste, non vengono copiati dati dalla directory "

- "skeleton\n"

+ "La directory home dell'utente esiste, non vengono copiati dati dalla "

+ "directory skeleton\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Impossibile creare la directory home dell'utente: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Impossibile creare lo spool di mail dell'utente: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "Impossibile allocare l'ID utente - dominio pieno?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "Utente o gruppo con lo stesso nome o ID già presente\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Errore nella transazione. L'utente non è stato aggiunto.\n"

  
@@ -641,7 +711,8 @@

  #: tools/sss_groupdel.c:107

  #, c-format

  msgid "Group %s is outside the defined ID range for domain\n"

- msgstr "Il gruppo %s è al di fuori del range di ID specificato per il dominio\n"

+ msgstr ""

+ "Il gruppo %s è al di fuori del range di ID specificato per il dominio\n"

  

  #: tools/sss_groupdel.c:136

  msgid ""
@@ -680,15 +751,15 @@

  msgstr ""

  "I gruppi membri devono appartenere allo stesso dominio del gruppo radice\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "

  "allowed\n"

  msgstr ""

- "Impossibile trovare il gruppo %s nel dominio locale, solo i gruppi nel dominio "

- "locale sono permessi\n"

+ "Impossibile trovare il gruppo %s nel dominio locale, solo i gruppi nel "

+ "dominio locale sono permessi\n"

  

  #: tools/sss_groupmod.c:222

  msgid "Could not modify group - check if member group names are correct\n"
@@ -706,26 +777,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Errore della transazione. Impossibile modificare il gruppo.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%sGruppo: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "Magic Private "

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sNumero GID: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr "%sUtenti membri: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"
@@ -734,7 +805,7 @@

  "\n"

  "%sE' membro di: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"
@@ -743,19 +814,19 @@

  "\n"

  "%sGruppi membro: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "Mostra ricorsivamente i membri indiretti del gruppo"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "Specificare il gruppo da mostrate\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "Impossibile iniziare la ricerca\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"
@@ -763,76 +834,102 @@

  "Gruppo non presente nel dominio locale. La stampa dei gruppi è permessa solo "

  "nel dominio locale.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "Errore interno. Impossibile stampare il gruppo.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Eliminare home directory e spool di mail"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Non eliminare la home directory e lo spool di mail"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Forza la rimozione dei file non di proprietà dell'utente"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Specificare l'utente da cancellare\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr "L'utente %s è all'interno del range di ID definito per il dominio\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "Home directory non eliminata - non appartiene all'utente\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Impossibile rimuovere la home directory: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

- "Utente non presente nel dominio locale. L'eliminazione degli utenti è permessa "

- "solo nel dominio locale.\n"

+ "Utente non presente nel dominio locale. L'eliminazione degli utenti è "

+ "permessa solo nel dominio locale.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Errore interno. Impossibile rimuovere l'utente.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "Il GID dell'utente"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Gruppi a cui aggiungere questo utente"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Gruppi da cui rimuovere questo utente"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Bloccare l'account"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Sbloccare l'account"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Specificare l'utente da modificare\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -840,21 +937,21 @@

  "Utente non presente nel dominio locale. La modifica degli utenti è permessa "

  "solo nel dominio locale.\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "Impossibile modificare l'utente - controllare che i nomi dei gruppi siano "

  "corretti\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr "Impossibile modificare l'utente - utente già membro di gruppi?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Errore nella transazione. Impossibile modificare l'utente.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Memoria esaurita\n"

  
@@ -863,9 +960,24 @@

  msgid "%s must be run as root\n"

  msgstr "%s deve essere eseguito come root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr "Redirigere l'output di debug su file anzichè stderr"

  

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "Il principal del servizio di cambio password"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "Il GID o il nome del gruppo dell'utente"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Impossibile determinare i gruppi dell'utente\n"

+ 

+ #~ msgid "Length of time between attempts to reconnect while offline"

+ #~ msgstr "Durata tra tentativi di riconnessione quando offline"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "Autenticazione offline"

+ 

  #~ msgid "Password has expired."

  #~ msgstr "La password è scaduta."

file modified
+252 -163
@@ -7,10 +7,11 @@

  msgstr ""

  "Project-Id-Version: sss_daemon_ja\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2009-11-18 09:48+1000\n"

  "Last-Translator: Noriko Mizumoto <noriko@fedoraproject.org>\n"

  "Language-Team: Japanese <fedora-trans-ja@redhat.com>\n"

+ "Language: ja\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -160,436 +161,498 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

- msgid "IPA domain"

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

  msgstr ""

  

  #: config/SSSDConfig.py:87

- msgid "IPA server address"

+ msgid "IPA domain"

  msgstr ""

  

  #: config/SSSDConfig.py:88

+ msgid "IPA server address"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr ""

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr ""

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr ""

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr ""

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr ""

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr ""

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr ""

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

+ #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

- #: config/SSSDConfig.py:103

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr ""

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr ""

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr ""

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr ""

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

  msgstr ""

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

  msgstr ""

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr ""

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr ""

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr ""

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr ""

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr ""

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr ""

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr ""

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr ""

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr ""

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr ""

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr ""

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr ""

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr ""

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr ""

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr ""

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr ""

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr ""

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr ""

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr ""

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr ""

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr ""

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr ""

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr ""

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr ""

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr ""

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

  msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ""

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

  msgstr ""

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr ""

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr ""

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr ""

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr ""

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr ""

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr ""

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr ""

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr ""

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr ""

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr ""

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr ""

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr ""

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr ""

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr ""

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr ""

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr ""

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr ""

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr ""

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr ""

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr ""

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr ""

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr ""

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr ""

  
@@ -658,8 +721,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr ""

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -678,143 +741,169 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr ""

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr ""

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr ""

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr ""

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr ""

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr ""

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr ""

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr ""

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr ""

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr ""

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr ""

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr ""

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"

  msgstr ""

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr ""

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr ""

  
@@ -823,6 +912,6 @@

  msgid "%s must be run as root\n"

  msgstr ""

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

file modified
+252 -166
@@ -7,10 +7,11 @@

  msgstr ""

  "Project-Id-Version: sssd.master.sss_daemon\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2009-11-19 12:19+0100\n"

  "Last-Translator: Richard van der Luit <nippur@fedoraproject.org>\n"

  "Language-Team: Dutch <nl@li.org>\n"

+ "Language: nl\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -160,438 +161,500 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

- msgid "IPA domain"

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

  msgstr ""

  

  #: config/SSSDConfig.py:87

- msgid "IPA server address"

+ msgid "IPA domain"

  msgstr ""

  

  #: config/SSSDConfig.py:88

+ msgid "IPA server address"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr ""

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr ""

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr ""

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr ""

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr ""

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr ""

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr ""

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

+ #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

- #: config/SSSDConfig.py:103

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr ""

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr ""

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr ""

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr ""

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

  msgstr ""

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

  msgstr ""

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr ""

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr ""

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr ""

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr ""

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr ""

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr ""

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr ""

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr ""

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr ""

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr ""

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr ""

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr ""

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr ""

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr ""

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr ""

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr ""

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr ""

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr ""

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr ""

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr ""

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr ""

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr ""

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr ""

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr ""

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Wachtwoorden komen niet overeen"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

  msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ""

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

  msgstr ""

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:674

+ #, fuzzy, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr "Wachtwoord is verlopen."

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr ""

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  #, fuzzy

  msgid "Password change failed. "

  msgstr "Wachtwoord is verlopen."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr ""

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nieuw Wachtwoord: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Voer nieuw wachtwoord nogmaals in: "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Wachtwoord: "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  #, fuzzy

  msgid "Current Password: "

  msgstr "Nieuw Wachtwoord: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr ""

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr ""

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr ""

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr ""

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr ""

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr ""

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr ""

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr ""

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr ""

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr ""

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr ""

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr ""

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr ""

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr ""

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr ""

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr ""

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr ""

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr ""

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr ""

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr ""

  
@@ -660,8 +723,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr ""

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -680,143 +743,169 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr ""

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr ""

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr ""

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr ""

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr ""

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr ""

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr ""

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr ""

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr ""

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr ""

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr ""

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr ""

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"

  msgstr ""

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr ""

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr ""

  
@@ -825,9 +914,6 @@

  msgid "%s must be run as root\n"

  msgstr ""

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

- 

- #~ msgid "Password has expired."

- #~ msgstr "Wachtwoord is verlopen."

file modified
+276 -171
@@ -5,10 +5,11 @@

  msgstr ""

  "Project-Id-Version: pl\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

- "PO-Revision-Date: 2010-03-15 14:21+0100\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

+ "PO-Revision-Date: 2010-05-18 23:10+0200\n"

  "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"

  "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"

+ "Language: pl\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -164,238 +165,264 @@

  "Jak długo utrzymywać wpisy logowania w pamięci podręcznej po ostatnim udanym "

  "zalogowaniu (dni)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ "Jak długo czekać na odpowiedzi od DNS podczas rozwiązywania serwerów "

+ "(sekundy)"

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "Domena IPA"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "Adres serwera IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "Nazwa komputera klienta IPA"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr "Czy automatycznie aktualizować wpis DNS klienta w FreeIPA"

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ "Interfejs, którego adres IP powinien być używany do dynamicznych "

+ "aktualizacji DNS"

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Adres serwera Kerberos"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Obszar Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Czas oczekiwania na uwierzytelnienie"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  "Katalog do przechowywania pamięci podręcznych danych uwierzytelniających"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Położenie pamięci podręcznej danych uwierzytelniających użytkownika"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Położenie tablicy kluczy do sprawdzania danych uwierzytelniających"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Włącza sprawdzanie danych uwierzytelniających"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "Główna usługa zmiany hasła"

- 

  #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

+ msgstr ""

+ "Przechowuje hasło, jeśli znajduje się w trybie offline do dalszego "

+ "uwierzytelnienia w trybie online"

+ 

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  "Serwer, w którym jest uruchomiona usługa zmiany haseł, jeśli nie znajduje "

  "się w KDC"

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, adres URI serwera LDAP"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "Domyślna podstawowa DN"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "Typ Schema do użycia na serwerze LDAP, RFC2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "Domyślne DN dowiązania"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "Typ tokenu uwierzytelniania domyślnego DN dowiązania"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "Token uwierzytelniania domyślnego DN dowiązania"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Czas do próby połączenia"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Czas do próby synchronicznych działań LDAP"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Czas między próbami ponownego połączenia w trybie offline"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

+ msgstr "Plik zawierający certyfikaty CA"

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

- msgstr "plik zawierający certyfikaty CA"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr "Ścieżka do katalogu certyfikatów CA"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Wymaga sprawdzenia certyfikatu TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Podaje używany mechanizm SASL"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Podaje używany identyfikator upoważnienia SASL"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Tablica kluczy usługi Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Używa uwierzytelniania Kerberos dla połączenia LDAP"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr "Podąża za odsyłaniami LDAP"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Czas trwania TGT dla połączenia LDAP"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Czas oczekiwania na żądanie wyszukiwania"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Czas między aktualizacjami wyliczania"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

- msgstr "Wymaga TLS dla wyszukiwania identyfikatorów, fałsz"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

+ msgstr "Wymaga TLS dla wyszukiwania identyfikatorów"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "Podstawowe DN dla wyszukiwania użytkowników"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Zakres wyszukiwania użytkowników"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Filtruje wyszukiwania użytkowników"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Klasa obiektów dla użytkowników"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Atrybut nazwy użytkownika"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Atrybut UID"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Pierwszy atrybut GID"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Atrybut GECOS"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Atrybut katalogu domowego"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Atrybut powłoki"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Atrybut UUID"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Atrybut głównego użytkownika (dla Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Imię i nazwisko"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Atrybut memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Atrybut czasu modyfikacji"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Polityka do oszacowania wygaszenia hasła"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr "Filtr LDAP do określenia uprawnień dostępu"

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Lista dozwolonych użytkowników oddzielonych przecinkami"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Lista zabronionych użytkowników oddzielonych przecinkami"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Domyślna powłoka, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Podstawa katalogów domowych"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "Nazwa używanej biblioteki NSS"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "Używany stos PAM"

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "Uruchamia jako demon (domyślnie)"

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "Uruchamia interaktywnie (nie jako demon)"

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "Podaje niedomyślny plik konfiguracji"

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd musi zostać uruchomione jako root\n"

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"
@@ -403,7 +430,7 @@

  "Wykryto gniazdo nscd. Możliwości pamięci podręcznej nscd mogą konfliktować z "

  "SSSD, więc nie jest zalecane uruchamianie nscd jednocześnie z SSSD\n"

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "
@@ -412,200 +439,242 @@

  "Nie można odczytać pliku konfiguracji %s. Proszę sprawdzić, czy uprawnienia "

  "wynoszą 0600, a właścicielem pliku jest root.root\n"

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr "Nie można wczytać bazy danych konfiguracji\n"

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "Poziom debugowania"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "Dodaje czasy debugowania"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr "Otwiera deskryptor pliku dla dzienników debugowania"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr "Domena dostawcy informacji (wymagane)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr "Uprawnione gniazdo posiada błędnego właściciela lub uprawnienia."

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr "Publiczne gniazdo posiada błędnego właściciela lub uprawnienia."

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr "Nieoczekiwany format komunikatu uwierzytelniającego serwera."

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr "SSSD nie zostało uruchomione jako root."

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr "Wystąpił błąd, ale nie można odnaleźć opisu."

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr "Nieoczekiwany błąd podczas wyszukiwania opisu błędu"

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Hasła nie zgadzają się"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Uwierzytelnienie w trybie offline"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr "Przywrócenie hasło przez roota nie jest obsługiwane."

+ 

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ "Uwierzytelniono za pomocą danych uwierzytelniających w pamięci podręcznej"

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ", hasło w pamięci podręcznej wygaśnie za: "

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

- msgstr ""

- "Uwierzytelnianie w trybie offline, uwierzytelnianie jest zabronione do: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr "Hasło wygasło. Pozostało %d możliwych logowań."

+ 

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr "Hasło wygaśnie za %d %s."

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr "Uwierzytelnianie jest zabronione do: "

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "System jest w trybie offline, zmiana hasła nie jest możliwa"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Zmiana hasła nie powiodła się. "

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Komunikat serwera: "

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nowe hasło: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Proszę ponownie podać nowe hasło: "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Hasło: "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Bieżące hasło: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "Hasło wygasło. Proszę je zmienić teraz."

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr "Poziom debugowania, z jakim uruchomić"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "UID użytkownika"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "GID nazwy grupy użytkownika"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "Ciąg komentarza"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Katalog domowy"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Powłoka logowania"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Grupy"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Utworzy katalog użytkownika, jeśli nie istnieje"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "Nigdy nie tworzy katalogu użytkownika, zastępuje konfigurację"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Proszę podać alternatywny katalog szkieletu"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr "Użytkownik SELinuksa dla loginu użytkownika"

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "Błąd podczas ustawiania lokalizacji\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Proszę podać użytkownika do dodania\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "Błąd podczas inicjowania narzędzi - brak lokalnej domeny\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Błąd podczas inicjowania narzędzi\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "Podano nieprawidłową domenę w FQDN\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Wewnętrzny błąd podczas przetwarzania parametrów\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Grupy muszą być w tej samej domenie co użytkownik\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Nie można odnaleźć grupy %s w lokalnej domenie\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Nie można uzyskać informacji o grupie dla użytkownika\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Nie można ustawić domyślnych wartości\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "Wybrany UID jest spoza dozwolonego zakresu\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr "Nie można ustawić kontekstu logowania SELinuksa\n"

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Nie można uzyskać informacji o użytkowniku\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  "Katalog domowy użytkownika już istnieje, dane z katalogu szkieletu nie "

  "zostaną skopiowane\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Nie można utworzyć katalogu domowego użytkownika: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Nie można utworzyć buforu poczty użytkownika: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  "Nie można przydzielić identyfikatora użytkownikowi - czy domena jest pełna?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  "Użytkownik lub grupa o tej samej nazwie lub identyfikatorze już istnieje\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Błąd transakcji. Nie można dodać użytkownika.\n"

  
@@ -678,8 +747,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr "Członkowie grupy muszą być w tej samej domenie co grupa nadrzędna\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -704,26 +773,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Błąd transakcji. Nie można zmodyfikować grupy.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%sGrupa: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "Prywatne magic "

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sNumer GID: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr "%sUżytkownicy będący członkami: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"
@@ -732,7 +801,7 @@

  "\n"

  "%sJest członkiem: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"
@@ -741,19 +810,19 @@

  "\n"

  "%sGrupy będące członkami: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "Rekursywnie drukuje niebezpośrednich członków grupy"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "Proszę podać grupę do wyświetlenia\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "Nie można zainicjować wyszukiwania\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"
@@ -761,78 +830,105 @@

  "Nie ma takiej grupy w lokalnej domenie. Drukowanie grup jest dozwolone tylko "

  "w lokalnej domenie.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "Wewnętrzny błąd. Nie można wydrukować grupy.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Usuwa katalog domowy i bufor poczty"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Nie usuwa katalogu domowego i bufora poczty"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Wymusza usunięcie plików, których właścicielem nie jest użytkownik"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr "Usuwa procesy użytkownika przed jego usunięciem"

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Proszę podać użytkownika do usunięcia\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  "Użytkownik %s jest poza określonym zakresem identyfikatorów dla domeny\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr "Nie można przywrócić kontekstu logowania SELinuksa\n"

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ "OSTRZEŻENIE: użytkownik (UID %lu) był zalogowany podczas jego usuwania.\n"

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr "Nie można określić, czy użytkownik był zalogowany na tej platformie"

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr "Błąd podczas sprawdzania, czy użytkownik był zalogowany\n"

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr "Polecenie po usunięciu się nie powiodło: %s\n"

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr ""

  "Katalog domowy nie zostanie usunięty - użytkownik nie jest właścicielem\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Nie można usunąć katalogu domowego: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  "Nie ma takiego użytkownika w lokalnej domenie. Usuwanie użytkowników jest "

  "dozwolone tylko w lokalnej domenie.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Wewnętrzny błąd. Nie można usunąć użytkownika.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "GID użytkownika"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Grupy, do których dodać tego użytkownika"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Grupy, z których usunąć tego użytkownika"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Zablokowanie konta"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Odblokowanie konta"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Proszę podać użytkownika do zmodyfikowania\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -840,23 +936,23 @@

  "Nie można odnaleźć użytkownika w lokalnej domenie, modyfikowanie "

  "użytkowników jest dozwolone tylko w lokalnej domenie\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "Nie można zmodyfikować użytkownika - proszę sprawdzić, czy nazwy grup są "

  "poprawne\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  "Nie można zmodyfikować użytkownika - czy użytkownik jest już członkiem "

  "grup?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Błąd transakcji. Nie można zmodyfikować użytkownika.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Brak pamięci\n"

  
@@ -865,7 +961,16 @@

  msgid "%s must be run as root\n"

  msgstr "%s musi zostać uruchomione jako root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

  "Wysyła wyjście debugowania do plików, zamiast do standardowego wyjścia błędów"

+ 

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "Główna usługa zmiany hasła"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "GID nazwy grupy użytkownika"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Nie można uzyskać informacji o grupie dla użytkownika\n"

file modified
+276 -168
@@ -6,14 +6,14 @@

  msgstr ""

  "Project-Id-Version: sssd.master.sss_daemon\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-18 15:01-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2010-02-23 13:59+0100\n"

  "Last-Translator: Rui Gouveia <rui.gouveia@gmail.com>\n"

  "Language-Team: fedora-trans-pt@redhat.com\n"

+ "Language: pt\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"

- "Language: pt\n"

  "Plural-Forms: nplurals=2; plural=(n != 1);\n"

  "X-Poedit-Language: Portuguese\n"

  "X-Poedit-Country: PORTUGAL\n"
@@ -171,237 +171,260 @@

  "Durante quanto tempo devem ser permitidas as caches de sessões entre sessões "

  "bem sucedidas (dias)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "Domínio IPA"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "Endereço do servidor IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "Nome da máquina do cliente IPA"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Endereço do servidor Kerberos"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Reino Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Tempo de expiração da autenticação"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "Directório para armazenar as caches de credenciais"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Localização da cache de credenciais dos utilizadores"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Localização da tabela de chaves (keytab) para validar credenciais"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Activar validação de credenciais"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "O principal do serviço de alteração de senha"

- 

  #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  "Servidor onde está em execução o serviço de alteração de senha, se não "

  "coincide com o KDC"

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, O URI do servidor LDAP"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "A base DN por omissão"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "O tipo de Schema em utilização no servidor LDAP, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "O DN por omissão para a ligação"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "O tipo de token de autenticação do bind DN por omissão"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "O token de autenticação do bind DN por omissão"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Período de tempo para tentar ligação"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Tempo de espera para tentar operações LDAP síncronas"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Tempo de espera entre tentativas para re-conectar quando desligado"

- 

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:117

+ #, fuzzy

+ msgid "File that contains CA certificates"

  msgstr "ficheiro que contêm os certificados CA"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Obriga a verificação de certificados TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Especificar mecanismo sasl a utilizar"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Especifique o id sasl para utilizar na autorização"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Separador chave do serviço Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Utilizar autenticação Kerberos para ligações LDAP"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr "Seguir os referrals LDAP"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ #, fuzzy

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Utilizar autenticação Kerberos para ligações LDAP"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Tempo de espera por um pedido de pesquisa"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Período de tempo entre enumeração de actualizações"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ #, fuzzy

+ msgid "Require TLS for ID lookups"

  msgstr "Requer TLS para consultas de ID, falso"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "DN base para pesquisa de utilizadores"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Âmbito das pesquisas do utilizador"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Filtro para as pesquisas do utilizador"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Objectclass para utilizadores"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Atributo do nome do utilizador"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Atributo UID"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Atributo GID primário"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Atributo GECOS"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Atributo da pasta pessoal"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Atributo da Shell"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Atributo UUID"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Atributo principal do utilizador (para Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Nome Completo"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Atributo memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Atributo da alteração da data"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Politica para avaliar a expiração da senha"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Lista de utilizadores autorizados separados por vírgulas"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Lista de utilizadores não autorizados separados por vírgulas"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Shell pré-definida, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Directório base para as pastas pessoais"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "O nome da biblioteca NSS a utilizar"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "Stack PAM a utilizar"

  

- #: monitor/monitor.c:2170

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "Tornar-se num serviço (omissão)"

  

- #: monitor/monitor.c:2172

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "Executar interactivamente (não como serviço)"

  

- #: monitor/monitor.c:2174

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "Especificar um ficheiro de configuração não standard"

  

- #: monitor/monitor.c:2200

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd tem de executar como root\n"

  

- #: monitor/monitor.c:2235

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"
@@ -410,7 +433,7 @@

  "em conflito com o SSSD. Não é recomendado executar o nscd em paralelo com o "

  "SSSD\n"

  

- #: monitor/monitor.c:2245

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "
@@ -419,196 +442,240 @@

  "Incapaz de ler o ficheiro de configuração %s. Por favor, verifique se as "

  "permissões são 0600 e se o ficheiro pertence a root.root\n"

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "Nível de depuração"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "Adicionar tempos na depuração"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr "Um descritor de ficheiro aberto para os registos de depuração"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr "Domínio do fornecedor de informação (obrigatório)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ #, fuzzy

+ msgid "Unexpected format of the server credential message."

+ msgstr "Localização da cache de credenciais dos utilizadores"

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Senhas não coincidem"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Autenticação offline"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ", a sua senha guardada em cache irá expirar em: "

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:674

+ #, fuzzy, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ", a sua senha guardada em cache irá expirar em: "

+ 

+ #: sss_client/pam_sss.c:723

+ #, fuzzy

+ msgid "Authentication is denied until: "

  msgstr "Autenticação offline, a autenticação é negada até: "

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "O sistema está offline, a mudança de senha não é possível"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Alteração da senha falhou."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Mensagem do Servidor: "

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nova Senha: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Digite a senha novamente: "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Senha: "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Senha actual: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "A senha expirou. Altere a sua senha agora."

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr "O nível de depuração a utilizar durante a execução"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "O UID do utilizador"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "O GID ou nome do grupo do utilizador"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "Texto do comentário"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Pasta pessoal"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Shell"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Grupos"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Criar pasta pessoal do utilizador, se ainda não existir"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "Nunca criar pasta pessoal do utilizador. Sobrepõem-se à configuração"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Indique um directório skeleton alternativo"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "Erro ao definir a configuração regional\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Indique utilizador a adicionar\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "Erro ao inicializar as ferramentas - não existe domínio local\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Erro ao inicializar as ferramentas\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "Domínio inválido especificado no FQDN\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Erro interno ao processar parâmetros\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Os grupos têm de pertencer ao mesmo domínio que o utilizador\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Incapaz de encontrar o grupo %s no domínio local\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Incapaz de obter informação do grupo para o utilizador\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Incapaz de definir valores por omissão\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "O UID seleccionado está fora do intervalo permitido\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Incapaz de obter informação acerca do utilizador\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  "A pasta pessoal do utilizador já existe. Conteúdo skeldir não copiado\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Incapaz de criar pasta pessoal do utilizador: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Incapaz de criar o ficheiro de correio do utilizador: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "Incapaz de alocar um ID para o utilizador - domínio cheio?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "Já existe um utilizador ou grupo com o mesmo nome ou ID\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Erro na transacção. Não foi possível adicionar o utilizador.\n"

  
@@ -681,8 +748,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr "Grupos membro têm de estar no mesmo domínio do grupo pai\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -706,26 +773,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Erro de transacção. Não foi possível modificar o grupo.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%sGrupo: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "\"Magic\" Privada"

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sNúmero GID: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr "%sUtilizadores Membros: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"
@@ -734,7 +801,7 @@

  "\n"

  "%sIs um membro de: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"
@@ -743,19 +810,19 @@

  "\n"

  "%sGrupos Membros: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "Imprimir membros de grupos indirectos recursivamente"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "Especifique grupo a apresentar\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "Incapaz de iniciar pesquisa\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"
@@ -763,76 +830,102 @@

  "Grupo não existe no domínio local. Grupos de impressão apenas permitidos no "

  "domínio local.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "Erro interno. Incapaz de imprimir grupo.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Remover pasta pessoal e spool de correio"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Não remover pasta pessoal e spool de correio"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Forçar a remoção de ficheiros não pertencentes ao utilizador"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Especificar o utilizador a remover\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr "O utilizador %s está fora do intervalo de IDs para o domínio\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "Pasta pessoal não removida - não pertence ao utilizador\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Incapaz de remover pasta pessoal: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  "Utilizador não existe no domínio local. Apenas é permitido remover "

  "utilizadores no domínio local.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Erro interno. Incapaz de remover utilizador.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "O GID do utilizador"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Grupos para adicionar este utilizador"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Grupos para remover este utilizador"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Desactivar Conta"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Activar a Conta"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Especifique utilizador a modificar\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -840,21 +933,21 @@

  "Utilizador não foi encontrado no domínio local. Apenas é permitido modificar "

  "utilizadores no domínio local\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "Incapaz de modificar utilizador - verifique se o nome do grupo está "

  "correcto\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr "Incapaz de modificar utilizador - utilizador já é membro de grupos?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Erro na transacção. Não foi possível modificar o utilizador.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Memória esgotada\n"

  
@@ -863,9 +956,24 @@

  msgid "%s must be run as root\n"

  msgstr "%s tem de executar como root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr "Enviar o resultado de depuração para ficheiro em vez do stderr"

  

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "O principal do serviço de alteração de senha"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "O GID ou nome do grupo do utilizador"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Incapaz de obter informação do grupo para o utilizador\n"

+ 

+ #~ msgid "Length of time between attempts to reconnect while offline"

+ #~ msgstr "Tempo de espera entre tentativas para re-conectar quando desligado"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "Autenticação offline"

+ 

  #~ msgid "Password has expired."

  #~ msgstr "Senha expirou."

file modified
+353 -237
@@ -7,10 +7,11 @@

  msgstr ""

  "Project-Id-Version: ru\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2010-04-07 21:39+0300\n"

  "Last-Translator: Dmitry Drozdov <dmi3652@gmail.com>\n"

  "Language-Team: Russian <fedora-trans-ru@redhat.com>\n"

+ "Language: ru\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -92,15 +93,21 @@

  

  #: config/SSSDConfig.py:63

  msgid "How long to allow cached logins between online logins (days)"

- msgstr "Разрешённый интервал кэшированных входов между интерактивными входами (в днях)"

+ msgstr ""

+ "Разрешённый интервал кэшированных входов между интерактивными входами (в "

+ "днях)"

  

  #: config/SSSDConfig.py:64

  msgid "How many failed logins attempts are allowed when offline"

  msgstr "Разрешённое количество неудачных попыток неинтерактивного входа"

  

  #: config/SSSDConfig.py:65

- msgid "How long (minutes) to deny login after offline_failed_login_attempts has been reached"

- msgstr "Временной интервал (в минутах), в течение которого будет запрещён вход после достижения offline_failed_login_attempts"

+ msgid ""

+ "How long (minutes) to deny login after offline_failed_login_attempts has "

+ "been reached"

+ msgstr ""

+ "Временной интервал (в минутах), в течение которого будет запрещён вход после "

+ "достижения offline_failed_login_attempts"

  

  #: config/SSSDConfig.py:68

  msgid "Identity provider"
@@ -151,482 +158,528 @@

  msgstr "Тайм-аут элемента списка кэша (в секундах)"

  

  #: config/SSSDConfig.py:82

- msgid "Restrict or prefer a specific address family when performing DNS lookups"

- msgstr "Ограничивать или предпочитать определённое семейство адресов при выполнении запросов DNS"

+ msgid ""

+ "Restrict or prefer a specific address family when performing DNS lookups"

+ msgstr ""

+ "Ограничивать или предпочитать определённое семейство адресов при выполнении "

+ "запросов DNS"

  

  #: config/SSSDConfig.py:83

  msgid "How long to keep cached entries after last successful login (days)"

- msgstr "Как долго хранить кэшированные элементы списка после последнего успешного входа (в днях)"

+ msgstr ""

+ "Как долго хранить кэшированные элементы списка после последнего успешного "

+ "входа (в днях)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "IPA-домен"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "адрес сервера IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "имя узла клиента IPA"

  

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

  #: config/SSSDConfig.py:91

- #: config/SSSDConfig.py:119

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Имя сервера Kerberos"

  

- #: config/SSSDConfig.py:92

- #: config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Область действия Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Тайм-аут проверки подлинности"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "Каталог для хранения кэшей учётных данных"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Расположения кэша учётных данных пользователей"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Расположение keytab-файла для проверки учётных данных"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Включить проверку учётных данных"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "Основной элемент службы смены пароля"

- 

  #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr "Сервер, на котором запущена служба смены пароля (если не на KDC)"

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, URI сервера LDAP "

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "Base DN по умолчанию"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "Тип схемы, используемой на LDAP-сервере, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "Bind DN по умолчанию"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "Тип маркера проверки подлинности для bind DN по умолчанию"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "Маркер проверки подлинности для bind DN по умолчанию"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Временной интервал для попытки соединения"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Временной интервал для попытки синхронизации операций LDAP"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Временной интервал между попытками возобновления соединения в автономного режиме"

- 

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:117

+ #, fuzzy

+ msgid "File that contains CA certificates"

  msgstr "Файл, содержащий CA сертификаты"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Требуется проверка сертификата TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Укажите механизм sasl"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Укажите идентификатор авторизации sasl"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Keytab-файл службы Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Использовать проверку подлинности Kerberos для LDAP-соединения"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr "Следовать ссылкам LDAP"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ #, fuzzy

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Использовать проверку подлинности Kerberos для LDAP-соединения"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Временной интервал, в течение которого ожидать поискового запроса"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Временной интервал между обновлениями перечисления"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ #, fuzzy

+ msgid "Require TLS for ID lookups"

  msgstr "Требуется TLS для поиска ID"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "Base DN для поиска"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Глубина поиска"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Фильтр поиска"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Objectclass для пользователей"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Атрибут «username»"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Атрибут «UID»"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Атрибут «primary GID»"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Атрибут «GECOS»"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Атрибут домашнего каталога"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Атрибут оболочки"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Атрибут «UUID»"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Атрибут участника-пользователя (для Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Полное имя"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Атрибут memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Атрибут времени изменения"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Политика вычисления окончания срока действия пароля"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Разделённый запятыми список разрешённых пользователей"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Разделённый запятыми список запрещённых пользователей"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Оболочка по умолчанию, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Место для домашних каталогов"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "Имя используемой библиотеки NSS"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "Используемый стек PAM"

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "Запускаться в качестве службы (по умолчанию)"

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "Запускаться интерактивно (не службой)"

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "Указать файл конфигурации"

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd должен выполняться от имени root\n"

  

- #: monitor/monitor.c:2264

- msgid "nscd socket was detected.  As nscd caching capabilities may conflict with SSSD, it is recommended to not run nscd in parallel with SSSD\n"

- msgstr "был обнаружен сокет nscd. Возможности по кэшированию nscd могут конфликтовать с SSSD, поэтому рекомендуется не запускать nscd одновременно с SSSD\n"

+ #: monitor/monitor.c:2154

+ msgid ""

+ "nscd socket was detected.  As nscd caching capabilities may conflict with "

+ "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

+ msgstr ""

+ "был обнаружен сокет nscd. Возможности по кэшированию nscd могут "

+ "конфликтовать с SSSD, поэтому рекомендуется не запускать nscd одновременно с "

+ "SSSD\n"

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

- msgid "Cannot read config file %s, please check if permissions are 0600 and the file is owned by root.root\n"

- msgstr "Не удалось прочитать файл конфигурации %s, убедитесь, что права доступа файла 0600 и владелец - root.root\n"

+ msgid ""

+ "Cannot read config file %s, please check if permissions are 0600 and the "

+ "file is owned by root.root\n"

+ msgstr ""

+ "Не удалось прочитать файл конфигурации %s, убедитесь, что права доступа "

+ "файла 0600 и владелец - root.root\n"

  

- #: providers/krb5/krb5_child.c:929

- #: providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "Уровень отладки"

  

- #: providers/krb5/krb5_child.c:931

- #: providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "Добавить отладочные отметки времени"

  

- #: providers/krb5/krb5_child.c:933

- #: providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr "Открытый дескриптор файла для журналов отладки"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr "Домен поставщика информации (обязательный)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ #, fuzzy

+ msgid "Unexpected format of the server credential message."

+ msgstr "Расположения кэша учётных данных пользователей"

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Пароли не совпадают"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Автономная проверка подлинности"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ", срок действия вашего кэшированного пароль истечёт:"

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:674

+ #, fuzzy, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ", срок действия вашего кэшированного пароль истечёт:"

+ 

+ #: sss_client/pam_sss.c:723

+ #, fuzzy

+ msgid "Authentication is denied until: "

  msgstr "Автономная проверка подлинности, проверка подлинности запрещена до:"

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "Система находится в автономном режиме, невозможно сменить пароль"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Не удалось сменить пароль."

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Сообщение сервера:"

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Новый пароль:"

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Введите новый пароль ещё раз:"

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Пароль:"

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Текущий пароль:"

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "Срок действия пароля истёк. Необходимо сейчас изменить ваш пароль."

  

- #: tools/sss_useradd.c:114

- #: tools/sss_groupadd.c:41

- #: tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42

- #: tools/sss_groupshow.c:1008

- #: tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr "Уровень отладки для запуска"

  

- #: tools/sss_useradd.c:115

- #: tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "UID пользователя"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "GID или имя группы пользователя"

- 

- #: tools/sss_useradd.c:117

- #: tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "Строка комментария"

  

- #: tools/sss_useradd.c:118

- #: tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Домашний каталог"

  

- #: tools/sss_useradd.c:119

- #: tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Исходная оболочка"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Группы"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Создать каталог пользователя, если он не существует"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  #, fuzzy

  msgid "Never create user's directory, overrides config"

  msgstr "Никогда не создавать каталог пользователя"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Укажите альтернативный скелетный каталог"

  

- #: tools/sss_useradd.c:137

- #: tools/sss_groupadd.c:56

- #: tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63

- #: tools/sss_groupshow.c:1019

- #: tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  #, fuzzy

  msgid "Error setting the locale\n"

  msgstr "Ошибка установки локали\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Укажите добавляемого пользователя\n"

  

- #: tools/sss_useradd.c:183

- #: tools/sss_groupadd.c:86

- #: tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111

- #: tools/sss_groupshow.c:1056

- #: tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "Ошибка инициализации инструментов - не найден локальный домен\n"

  

- #: tools/sss_useradd.c:185

- #: tools/sss_groupadd.c:88

- #: tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113

- #: tools/sss_groupshow.c:1058

- #: tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Ошибка инициализации инструментов\n"

  

- #: tools/sss_useradd.c:194

- #: tools/sss_groupadd.c:97

- #: tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121

- #: tools/sss_groupshow.c:1067

- #: tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "В FQDN указан неверный домен\n"

  

- #: tools/sss_useradd.c:203

- #: tools/sss_groupmod.c:143

- #: tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162

- #: tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "При разборе параметров возникла внутренняя ошибка\n"

  

- #: tools/sss_useradd.c:211

- #: tools/sss_usermod.c:170

- #: tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Группы должны быть в том же домене, что и пользователь\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Не удалось найти группу %s в локальном домене\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Не удалось получить информацию о группе для пользователя\n"

- 

- #: tools/sss_useradd.c:244

- #: tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Не удалось установить значения по умолчанию\n"

  

- #: tools/sss_useradd.c:251

- #: tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "Выбранный UID находится за пределами доступного диапазона\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Не удалось получить информацию о пользователе\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

- msgstr "Домашний каталог пользователя уже существует, копирования данных из скелетной директории выполнено не будет\n"

+ msgstr ""

+ "Домашний каталог пользователя уже существует, копирования данных из "

+ "скелетной директории выполнено не будет\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Не удалось создать домашний каталог пользователя: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Не удалось создать пользовательскую почтовую очередь: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "Для пользователя  не удалось выделить ID - домен заполнен?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "Пользователь или группа с таким именем или ID уже существует\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Ошибка в транзакции. Невозможно добавить пользователя.\n"

  

- #: tools/sss_groupadd.c:43

- #: tools/sss_groupmod.c:48

+ #: tools/sss_groupadd.c:43 tools/sss_groupmod.c:48

  msgid "The GID of the group"

  msgstr "GID группы"

  
@@ -634,8 +687,7 @@

  msgid "Specify group to add\n"

  msgstr "Укажите группу для добавления\n"

  

- #: tools/sss_groupadd.c:106

- #: tools/sss_groupmod.c:194

+ #: tools/sss_groupadd.c:106 tools/sss_groupmod.c:194

  msgid "The selected GID is outside the allowed range\n"

  msgstr "Выбранный GID находится вне разрешённого диапазона\n"

  
@@ -661,8 +713,12 @@

  msgstr "Группа %s находится вне назначенного для домена диапазона ID\n"

  

  #: tools/sss_groupdel.c:136

- msgid "No such group in local domain. Removing groups only allowed in local domain.\n"

- msgstr "В локальном домене такой группы нет. Удаление групп разрешено только в локальном домене.\n"

+ msgid ""

+ "No such group in local domain. Removing groups only allowed in local "

+ "domain.\n"

+ msgstr ""

+ "В локальном домене такой группы нет. Удаление групп разрешено только в "

+ "локальном домене.\n"

  

  #: tools/sss_groupdel.c:141

  msgid "Internal error. Could not remove group.\n"
@@ -681,25 +737,32 @@

  msgstr "Укажите группу для изменения\n"

  

  #: tools/sss_groupmod.c:130

- msgid "Cannot find group in local domain, modifying groups is allowed only in local domain\n"

- msgstr "Не удалось найти группу в локальном домене, изменение групп разрешено только в локальном домене\n"

+ msgid ""

+ "Cannot find group in local domain, modifying groups is allowed only in local "

+ "domain\n"

+ msgstr ""

+ "Не удалось найти группу в локальном домене, изменение групп разрешено только "

+ "в локальном домене\n"

  

- #: tools/sss_groupmod.c:151

- #: tools/sss_groupmod.c:178

+ #: tools/sss_groupmod.c:151 tools/sss_groupmod.c:178

  msgid "Member groups must be in the same domain as parent group\n"

- msgstr "Группы-участники должны быть в том же домене, что и родительская группа\n"

+ msgstr ""

+ "Группы-участники должны быть в том же домене, что и родительская группа\n"

  

- #: tools/sss_groupmod.c:159

- #: tools/sss_groupmod.c:186

- #: tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

- msgid "Cannot find group %s in local domain, only groups in local domain are allowed\n"

- msgstr "Не удалось найти группу %s в локальном домене, разрешены только группы локального домена\n"

+ msgid ""

+ "Cannot find group %s in local domain, only groups in local domain are "

+ "allowed\n"

+ msgstr ""

+ "Не удалось найти группу %s в локальном домене, разрешены только группы "

+ "локального домена\n"

  

  #: tools/sss_groupmod.c:222

  msgid "Could not modify group - check if member group names are correct\n"

- msgstr "Не удалось изменить группу — проверьте правильность имён групп-участников\n"

+ msgstr ""

+ "Не удалось изменить группу — проверьте правильность имён групп-участников\n"

  

  #: tools/sss_groupmod.c:226

  msgid "Could not modify group - check if groupname is correct\n"
@@ -709,26 +772,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Ошибка в транзакции. Не удалось изменить группу.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%sГруппа: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "Magic Private"

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sНомер GID: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr "%sПользователи: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, fuzzy, c-format

  msgid ""

  "\n"
@@ -737,7 +800,7 @@

  "\n"

  "%sIs является участником: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"
@@ -746,106 +809,143 @@

  "\n"

  "%sГруппы-участники: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "Рекурсивно выводить непрямых участников группы"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "Укажите группу\n"

  

- #: tools/sss_groupshow.c:1081

- #: tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "Невозможно начать поиск\n"

  

- #: tools/sss_groupshow.c:1115

- msgid "No such group in local domain. Printing groups only allowed in local domain.\n"

- msgstr "В локальном домене нет такой группы. Печать групп разрешена только в локальном домене.\n"

+ #: tools/sss_groupshow.c:1123

+ msgid ""

+ "No such group in local domain. Printing groups only allowed in local "

+ "domain.\n"

+ msgstr ""

+ "В локальном домене нет такой группы. Печать групп разрешена только в "

+ "локальном домене.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "Внутренняя ошибка. Невозможно напечатать группу.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Удалить домашний каталог и почтовую очередь"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Не удалять домашний каталог и почтовую очередь"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Принудительно удалять файлы, не принадлежащие пользователю"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Укажите пользователя для удаления\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr "Пользователь %s находится вне определённого диапазона ID для домена\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

- msgstr "Домашняя директория не удалена — пользователь не является её владельцем\n"

+ msgstr ""

+ "Домашняя директория не удалена — пользователь не является её владельцем\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Не удалось удалить домашнюю директорию: %s\n"

  

- #: tools/sss_userdel.c:186

- msgid "No such user in local domain. Removing users only allowed in local domain.\n"

- msgstr "В локальном домене нет такого пользователя. Удаление пользователей разрешено только для локального домена.\n"

+ #: tools/sss_userdel.c:340

+ msgid ""

+ "No such user in local domain. Removing users only allowed in local domain.\n"

+ msgstr ""

+ "В локальном домене нет такого пользователя. Удаление пользователей разрешено "

+ "только для локального домена.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Внутренняя ошибка. Не удалось удалить пользователя.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "GID пользователя"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Группы, к которым добавить этого пользователя"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Группы, из которых удалить этого пользователя"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Заблокировать учётную запись"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Разблокировать учётную запись"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Укажите пользователя для изменения\n"

  

- #: tools/sss_usermod.c:146

- msgid "Cannot find user in local domain, modifying users is allowed only in local domain\n"

- msgstr "Не удалось найти пользователя в локальном домене, изменение пользователей разрешено только в локальном домене\n"

+ #: tools/sss_usermod.c:148

+ msgid ""

+ "Cannot find user in local domain, modifying users is allowed only in local "

+ "domain\n"

+ msgstr ""

+ "Не удалось найти пользователя в локальном домене, изменение пользователей "

+ "разрешено только в локальном домене\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr "Не удалось изменить пользователя — проверьте правильность имён групп\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr "Не удалось изменить пользователя — он уже является членом групп?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Ошибка в транзакции. Не удалось изменить пользователя.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Недостаточно памяти\n"

  
@@ -854,7 +954,23 @@

  msgid "%s must be run as root\n"

  msgstr "%s должно выполняться от имени root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr "Отправлять отладочные сообщения в файлы, а не в stderr"

  

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "Основной элемент службы смены пароля"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "GID или имя группы пользователя"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Не удалось получить информацию о группе для пользователя\n"

+ 

+ #~ msgid "Length of time between attempts to reconnect while offline"

+ #~ msgstr ""

+ #~ "Временной интервал между попытками возобновления соединения в автономного "

+ #~ "режиме"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "Автономная проверка подлинности"

file modified
+252 -163
@@ -8,10 +8,11 @@

  msgstr ""

  "Project-Id-Version: PACKAGE VERSION\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"

  "Language-Team: LANGUAGE <LL@li.org>\n"

+ "Language: \n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=CHARSET\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -159,436 +160,498 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

- msgid "IPA domain"

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

  msgstr ""

  

  #: config/SSSDConfig.py:87

- msgid "IPA server address"

+ msgid "IPA domain"

  msgstr ""

  

  #: config/SSSDConfig.py:88

+ msgid "IPA server address"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr ""

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr ""

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr ""

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr ""

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr ""

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr ""

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr ""

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr ""

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

+ #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

- #: config/SSSDConfig.py:103

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr ""

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr ""

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr ""

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr ""

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

  msgstr ""

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

  msgstr ""

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr ""

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr ""

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr ""

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr ""

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr ""

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr ""

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr ""

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr ""

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr ""

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr ""

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr ""

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr ""

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr ""

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr ""

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr ""

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr ""

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr ""

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr ""

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr ""

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr ""

  

- #: monitor/monitor.c:2229

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr ""

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr ""

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr ""

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr ""

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr ""

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr ""

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

  msgstr ""

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ""

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

  msgstr ""

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr ""

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr ""

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr ""

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr ""

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr ""

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr ""

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr ""

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr ""

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr ""

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr ""

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr ""

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr ""

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr ""

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr ""

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr ""

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr ""

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr ""

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr ""

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr ""

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr ""

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr ""

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr ""

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr ""

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr ""

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr ""

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr ""

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr ""

  
@@ -657,8 +720,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr ""

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -677,143 +740,169 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr ""

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr ""

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr ""

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr ""

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr ""

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr ""

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr ""

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr ""

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr ""

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr ""

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr ""

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr ""

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr ""

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr ""

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr ""

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"

  msgstr ""

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr ""

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr ""

  
@@ -822,6 +911,6 @@

  msgid "%s must be run as root\n"

  msgstr ""

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr ""

file modified
+316 -219
@@ -1,17 +1,18 @@

  # Swedish messages for sssd server.

- # Copyright © 2009 Red Hat, Inc.

+ # Copyright © 2009-2010 Red Hat, Inc.

  # This file is distributed under the same license as the sssd package.

- # Göran Uddeborg <goeran@uddeborg.se>, 2009.

+ # Göran Uddeborg <goeran@uddeborg.se>, 2009-2010.

  #

- # $Revision: 1.4 $

+ # $Revision: 1.8 $

  msgid ""

  msgstr ""

  "Project-Id-Version: sss_server\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-15 08:12-0400\n"

- "PO-Revision-Date: 2009-12-30 17:58+0100\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

+ "PO-Revision-Date: 2010-05-29 11:19+0200\n"

  "Last-Translator: Göran Uddeborg <goeran@uddeborg.se>\n"

  "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"

+ "Language: sv\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -95,13 +96,15 @@

  

  #: config/SSSDConfig.py:64

  msgid "How many failed logins attempts are allowed when offline"

- msgstr ""

+ msgstr "Hur många misslyckade inloggningsförsök som tillåts i frånkopplat läge"

  

  #: config/SSSDConfig.py:65

  msgid ""

  "How long (minutes) to deny login after offline_failed_login_attempts has "

  "been reached"

  msgstr ""

+ "Hur länge (minuter) som inloggning nekas efter att "

+ "frånkopplade_inloggningsförsök har nåtts"

  

  #: config/SSSDConfig.py:68

  msgid "Identity provider"
@@ -154,451 +157,512 @@

  #: config/SSSDConfig.py:82

  msgid ""

  "Restrict or prefer a specific address family when performing DNS lookups"

- msgstr ""

+ msgstr "Begränsa eller föredra en specifik adressfamilj vid DNS-uppslagningar"

  

  #: config/SSSDConfig.py:83

- #, fuzzy

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

- "Hur länge sparade inloggningar tillåts mellan online-inloggningar (dagar)"

+ "Hur länge cachade poster skall behållas efter senaste lyckade inloggning "

+ "(dagar)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr "Hur länge man väntar på svar från DNS när servrar slås upp (sekunder)"

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "IPA-domän"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "IPA-serveradress"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "IPA-klienvärdnamn"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr "Om klientens DNS-post i FreeIPA automatiskt skall uppdateras"

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr "Gränssnittet var IP skall användas för dynamiska DNS-uppdateringar"

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Kerberosserveradress"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Kerberosrike"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Autentiseringstidsgräns"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "Katalog att lagra kreditiv-cachar i"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Plats för användarens kreditiv-cache"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Plats för nyckeltabellen för att validera kreditiv"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Aktivera validering av kreditiv"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "Huvudmannen för tjänsten att ändra lösenord"

- 

  #: config/SSSDConfig.py:103

- msgid "Server where the change password service is running if not on the KDC"

- msgstr ""

+ msgid "Store password if offline for later online authentication"

+ msgstr "Lagra lösenord när ej ansluten för ansluten autentisering senare"

  

  #: config/SSSDConfig.py:106

+ msgid "Server where the change password service is running if not on the KDC"

+ msgstr "Server där ändringstjänsten för lösenord kör om inte på KDC:n"

+ 

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, URI:n för LDAP-servern"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "Standard bas-DN"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "Schematypen som används i LDAP-servern, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "Standard bindnings-DN"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "Typen på autenticerings-token för standard bindnings-DN"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "Autenticerings-token för standard bindnings-DN"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Tidslängd att försöka ansluta"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Tidslängd att försök synkrona LDAP-operationer"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr "Tidslängd mellan försök att återansluta under frånkoppling"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

+ msgstr "Fil som innehåller CA-certifikat"

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

- msgstr "fil som innehåller CA-certifikat"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr "Sökväg till katalogen med CA-certifikat"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Kräv TLS-certifikatverifiering"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Ange sasl-mekanismen att använda"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Ange sasl-auktorisering-id att använda"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Kerberostjänstens nyckeltabell"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Avnänd Kerberosautenticering för LDAP-anslutning"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

- msgstr ""

+ msgstr "Följer LDAP-hänvisningar"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Livslängd på TGT för LDAP-anslutning"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Tidslängd att vänta på en sökbegäran"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Tidslängd mellan uppräkningsuppdateringar"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

- msgstr "Kräv TLS för ID-uppslagningar, falsk"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

+ msgstr "Kräv TLS för ID-uppslagningar"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "Bas-DN för användaruppslagningar"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Omfång av användaruppslagningar"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Filter för användaruppslagningar"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Objektklass för användare"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Användarnamnsattribut"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "UID-attribut"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Primärt GID-attribut"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "GECOS-attribut"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Hemkatalogattribut"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Skalattribut"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "UUID-attribut"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Användarens huvudmansattribut (för Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Fullständigt namn"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "medlemAv-attribut"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Modifieringstidsattribut"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Policy för att utvärdera utgång av lösenord"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr "LDAP-filter för att bestämma åtkomstprivilegier"

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

- msgstr ""

+ msgstr "Kommaseparerad lista över tillåtna användare"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

- msgstr ""

+ msgstr "Kommaseparerad lista över förbjudna användare"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Standardskal, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Bas för hemkataloger"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "Namnet på NSS-biblioteket att använda"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "PAM-stack att använda"

  

- #: monitor/monitor.c:2199

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

- msgstr ""

+ msgstr "Bli en demon (standard)"

  

- #: monitor/monitor.c:2201

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

- msgstr ""

+ msgstr "Kör interaktivt (inte en demon)"

  

- #: monitor/monitor.c:2203

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

- msgstr ""

+ msgstr "Ange en konfigurationsfil annan än standard"

  

- #: monitor/monitor.c:2229

- #, fuzzy

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

- msgstr "%s måste köras som root\n"

+ msgstr "sssd måste köras som root\n"

  

- #: monitor/monitor.c:2264

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

+ "nscd-uttag upptäcktes.  Eftersom nscd:s cachningsegenskaper kan stå i "

+ "konflikt med SSSD rekommenderas det att inte köra nscd parallellt med SSSD\n"

  

- #: monitor/monitor.c:2274

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "

  "file is owned by root.root\n"

  msgstr ""

+ "Det går inte att läsa konfigurationsfilen %s, kontrollera om rättigheterna "

+ "är 0600 och filen ägs av root.root\n"

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr "Det går inte att läsa in konfigurationsdatabasen\n"

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

- msgstr ""

+ msgstr "Felsökningsnivå"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

- msgstr ""

+ msgstr "Lägg till felsökningstidstämplar"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

- #, fuzzy

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

- msgstr "Ange pratsamhet för felsökningsloggning"

+ msgstr "Ett öppet filhandtag för felsökningsloggarna"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

- msgstr ""

+ msgstr "Domän för informationsleverantören (obligatoriskt)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr "Priviligierat uttag (socket) har fel ägarskap eller rättigheter."

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr "Publikt uttag (socket) har fel ägarskap eller rättigheter."

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr "Oväntat format på serverns kreditivmeddelande."

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr "SSSD körs inte av root."

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr "Ett fel uppstod, men ingen beskrivning kan hittas."

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr "Oväntat fel vid sökning efter ett felmeddelande"

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Lösenorden stämmer inte överens"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr ""

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr "Återställning av lösenord av root stöds inte."

+ 

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr "Autentiserad med cachade kreditiv"

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

- msgstr ""

+ msgstr ", ditt cache-lösenord kommer gå ut: "

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

- msgstr ""

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr "Ditt lösenord har gått ut.  Du har en frist på %d inloggningar kvar."

+ 

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr "Ditt lösenordet kommer gå ut om %d %s."

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr "Autentisering nekas till: "

+ 

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

- msgstr ""

+ msgstr "Systemet är frånkopplat, ändring av lösenord är inte möjligt"

  

- #: sss_client/pam_sss.c:530

- #, fuzzy

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

- msgstr "Leverantör av lösenordsändringar"

+ msgstr "Lösenordsändringen misslyckades. "

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

- msgstr ""

+ msgstr "Servermeddelande: "

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Nytt lösenord: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Skriv det nya lösenordet igen: "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Lösenord: "

  

- #: sss_client/pam_sss.c:989

- #, fuzzy

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

- msgstr "Nytt lösenord: "

+ msgstr "Nuvarande lösenord: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

- msgstr ""

+ msgstr "Lösenordet har gått ut.  Ändra ditt lösenord nu."

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

- msgstr "Felsökningsnivå att köra med"

+ msgstr "Felsökningsnivån att köra med"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "Användarens UID"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "Användarens GID eller gruppnamn"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "Kommentarsträngen"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Hemkatalogen"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Inloggningsskalet"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Grupper"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Skapa användarens katalog om den inte redan finns"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "Skapa aldrig användarens katalog, åsidosätter konfigurationen"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Ange en alternativ skelettkatalog"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr "SELinux-användaren för användarens inloggning"

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "Fel när lokalen sattes\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Ange en användare att lägga till\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

- #, fuzzy

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

- msgstr "Fel vid initiering av verktygen\n"

+ msgstr "Fel vid initiering av verktygen — ingen lokal domän\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Fel vid initiering av verktygen\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "Ogiltig domän angiven i FQDN\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Internt fel vid tolkning av parametrar\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Grupper måste finnas i samma domän som användaren\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Hittar inte grupp %s i den lokala domänen\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Kan inte få gruppinformation för användaren\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Kan inte sätta standardvärden\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "Den valda UID:n är utanför det tillåtna intervallet\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr "Kan inte sätta SELinux-inloggningskontext\n"

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Kan inte få information om användaren\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  "Användarens hemkatalog finns redan, kopierar inte data från "

  "skelettkatalogen\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Kan inte skapa användarens hemkatalog: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Kan inte skapa användarens brevlåda: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "Det gick inte att allokera ID för användaren - full domän?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "En användare eller grupp med samma namn eller ID finns redan\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Transaktionsfel.  Det gick inte att lägga till användaren.\n"

  
@@ -671,8 +735,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr "Medlemsgrupper måster ligga i samma domän som föräldragrupper\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -696,133 +760,160 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Transaktionsfel.  Det gick inte att ändra gruppen.\n"

  

- #: tools/sss_groupshow.c:954

- #, fuzzy, c-format

+ #: tools/sss_groupshow.c:962

+ #, c-format

  msgid "%s%sGroup: %s\n"

- msgstr "Grupper"

+ msgstr "%s%sGrupp: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

- msgstr ""

+ msgstr "Magiskt privat "

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

- msgstr ""

+ msgstr "%sGID-nummer: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

- msgstr ""

+ msgstr "%sMedlemsanvändare: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"

  "%sIs a member of: "

  msgstr ""

+ "\n"

+ "%sÄr en medlem i: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"

  "%sMember groups: "

  msgstr ""

+ "\n"

+ "%sMedlemsgrupper: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

- msgstr ""

+ msgstr "Skriv ut indirekta gruppmedlemmar rekursivt"

  

- #: tools/sss_groupshow.c:1045

- #, fuzzy

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

- msgstr "Ange en grupp att lägga till\n"

+ msgstr "Ange en grupp att visa\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

- #, fuzzy

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

- msgstr "Kan inte få information om användaren\n"

+ msgstr "Det går inte att initiera sökningen\n"

  

- #: tools/sss_groupshow.c:1115

- #, fuzzy

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr ""

- "Ingen sådan grupp i den lokala domänen.  Att ta bort grupper är endast "

+ "Ingen sådan grupp i den lokala domänen.  Att skriva ut grupper är endast "

  "tillåtet i den lokala domänen.\n"

  

- #: tools/sss_groupshow.c:1120

- #, fuzzy

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

- msgstr "Internt fel.  Det gick inte att ta bort gruppen.\n"

+ msgstr "Internt fel.  Det gick inte att skriva ut gruppen.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Ta bort hemkatalog och brevlåda"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Ta inte bort hemkatalog och brevlåda"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Framtvinga borttagning av filer som inte ägs av användaren"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr "Döda anvädares processer före de tas bort"

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Ange användare att ta bort\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr "Användare %s är utanför det definierade ID-intervallet för domänen\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr "Kan inte återställa SELinux-inloggningskontext\n"

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ "VARNING: Användaren (uid %lu) var fortfarande inloggad när han togs bort.\n"

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr "Det går inte att avgöra om användaren var inloggad på denna plattform"

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr "Fel vid kontroll om användaren var inloggad\n"

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr "Kommandot efter borttagandet misslyckades: %s\n"

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "Tar inte bort hemkatalogen - ägs inte av användaren\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Kan inte ta bort hemkatalogen: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  "Ingen sådan användare i den lokala domänen.  Det går endast att ta bort "

  "användare i den lokala domänen.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Internt fel.  Det gick inte att ta bort användaren.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "Användarens GID"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Grupper att lägga till denna användare till"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Grupper att ta bort denna användare ifrån"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Lås kontot"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Lås upp kontot"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Ange användare att ändra\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -830,21 +921,21 @@

  "Det gick inte att hitta användaren i den lokala domänen, det går bara att "

  "ändra användare i den lokala domänen\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "Det gick inte att ändra användaren - kontrollera att gruppnamnen är riktiga\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  "Det gick inte att ändra användaren - är användaren redan medlem i grupper?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "Transaktionsfel.  Det gick inte att ändra användaren.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Slut på minne\n"

  
@@ -853,9 +944,15 @@

  msgid "%s must be run as root\n"

  msgstr "%s måste köras som root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

- msgstr ""

+ msgstr "Skicka felutskrifter till filer istället för standard fel"

+ 

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "Huvudmannen för tjänsten att ändra lösenord"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "Användarens GID eller gruppnamn"

  

- #~ msgid "Password has expired."

- #~ msgstr "Lösenordet har gått ut."

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Kan inte få gruppinformation för användaren\n"

file modified
+287 -175
@@ -6,16 +6,17 @@

  msgstr ""

  "Project-Id-Version: \n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-17 15:16-0400\n"

- "PO-Revision-Date: 2010-03-17 19:38+0200\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

+ "PO-Revision-Date: 2010-05-23 11:49+0300\n"

  "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"

  "Language-Team: Ukrainian <translation@linux.org.ua>\n"

+ "Language: uk\n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=UTF-8\n"

  "Content-Transfer-Encoding: 8bit\n"

- "X-Generator: Lokalize 1.0\n"

- "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%"

- "10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

+ "X-Generator: Lokalize 1.1\n"

+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"

+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"

  

  #: config/SSSDConfig.py:39

  msgid "Set the verbosity of the debug logging"
@@ -168,239 +169,262 @@

  "Тривалість зберігання кешованих записів після останнього успішного входу (у "

  "днях)"

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ "Тривалість очікування на відповідь від DNS під час визначення адрес серверів "

+ "(у секундах)"

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "Домен IPA"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "Адреса сервера IPA"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "Назва вузла клієнта IPA"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ "Визначає, чи слід автоматично оновлювати запис DNS клієнтського вузла у "

+ "FreeIPA"

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ "Інтерфейс, чию адресу IP має бути використано для динамічних оновлень DNS"

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Адреса сервера Kerberos"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr "Область Kerberos"

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "Час очікування на розпізнавання"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "Каталог, де зберігатиметься кеш реєстраційних даних"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "Адреса кешу реєстраційних даних користувача"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "Адреса таблиці ключів для перевірки реєстраційних даних"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "Увімкнути перевірку реєстраційних даних"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "Реєстраційний запис служби зміни паролів"

- 

  #: config/SSSDConfig.py:103

+ msgid "Store password if offline for later online authentication"

+ msgstr "Зберігати пароль у автономному режимі для розпізнавання у мережі"

+ 

+ #: config/SSSDConfig.py:106

  msgid "Server where the change password service is running if not on the KDC"

  msgstr ""

  "Сервер, на якому запущено службу зміни паролів, якщо такий не вдасться "

  "виявити у KDC"

  

- #: config/SSSDConfig.py:106

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr "ldap_uri, адреса URI сервера LDAP"

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr "Типова базова назва домену"

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr "Тип схеми, використаний на сервері LDAP, rfc2307"

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr "Типова назва домену прив’язки"

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr "Тип розпізнавання для типової назви сервера прив’язки"

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr "Лексема розпізнавання типової назви сервера прив’язки"

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr "Проміжок часу між спробами встановлення з’єднання"

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr "Проміжок часу між спробами виконання синхронних операцій LDAP"

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr ""

- "Проміжок часу між повторними спробами встановлення з’єднання у автономному "

- "режимі"

+ #: config/SSSDConfig.py:117

+ msgid "File that contains CA certificates"

+ msgstr "Файл, що містить сертифікати CA"

  

- #: config/SSSDConfig.py:115

- msgid "file that contains CA certificates"

- msgstr "файл, що містить сертифікати CA"

+ #: config/SSSDConfig.py:118

+ msgid "Path to CA certificate directory"

+ msgstr "Шлях до каталогу сертифікатів CA"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "Потрібна перевірка сертифіката TLS"

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "Вкажіть механізм SASL, який слід використовувати"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "Вкажіть ідентифікатор уповноваження SASL, який слід використовувати"

  

- #: config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr "Таблиця ключів служби Kerberos"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr "Розпізнавання Kerberos для з’єднання LDAP"

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr "Переходити за посиланнями LDAP"

  

- #: config/SSSDConfig.py:126

+ #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr "Строк дії TGT для з’єднання LDAP"

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "Тривалість очікування на дані запиту пошуку"

  

- #: config/SSSDConfig.py:127

+ #: config/SSSDConfig.py:131

  msgid "Length of time between enumeration updates"

  msgstr "Проміжок часу між оновленнями нумерації"

  

- #: config/SSSDConfig.py:128

- msgid "Require TLS for ID lookups, false"

- msgstr "Вимагати TLS для пошуків ідентифікаторів, вимкнено"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

+ msgstr "Вимагати TLS для пошуків ідентифікаторів"

  

- #: config/SSSDConfig.py:129

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr "Базова назва домену для пошуків користувачів"

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr "Діапазон пошуків користувачів"

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr "Фільтр пошуку користувачів"

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr "Клас об’єктів для користувачів"

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr "Атрибут імені користувача"

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:138

  msgid "UID attribute"

  msgstr "Атрибут UID"

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:139

  msgid "Primary GID attribute"

  msgstr "Головний атрибут GID"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:140

  msgid "GECOS attribute"

  msgstr "Атрибут GECOS"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:141

  msgid "Home directory attribute"

  msgstr "Атрибут домашнього каталогу"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:142

  msgid "Shell attribute"

  msgstr "Атрибут оболонки"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:143

  msgid "UUID attribute"

  msgstr "Атрибут UUID"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:144

  msgid "User principal attribute (for Kerberos)"

  msgstr "Атрибут реєстраційного запису користувача (для Kerberos)"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "Повне ім'я"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr "Атрибут memberOf"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:147

  msgid "Modification time attribute"

  msgstr "Атрибут часу зміни"

  

- #: config/SSSDConfig.py:146

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "Правила оцінки завершення строку дії пароля"

  

- #: config/SSSDConfig.py:149

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr "Фільтр LDAP для визначення прав доступу"

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "Відокремлений комами список дозволених користувачів"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "Відокремлений комами список заборонених користувачів"

  

- #: config/SSSDConfig.py:153

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "Типова оболонка, /bin/bash"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:161

  msgid "Base for home directories"

  msgstr "Базова адреса домашніх каталогів"

  

- #: config/SSSDConfig.py:157

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "Назва бібліотеки NSS, яку слід використовувати"

  

- #: config/SSSDConfig.py:160

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "Стек PAM, який слід використовувати"

  

- #: monitor/monitor.c:2163

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "Запуститися фонову службу (типова поведінка)"

  

- #: monitor/monitor.c:2165

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "Запустити у інтерактивному режимі (без фонової служби)"

  

- #: monitor/monitor.c:2167

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "Вказати нетиповий файл налаштувань"

  

- #: monitor/monitor.c:2193

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd слід запускати від імені користувача root\n"

  

- #: monitor/monitor.c:2228

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"
@@ -408,7 +432,7 @@

  "Було виявлено сокет nscd. Можливості з кешування nscd можуть конфліктувати з "

  "SSSD. Не рекомендуємо вам користуватися nscd паралельно з SSSD\n"

  

- #: monitor/monitor.c:2238

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "
@@ -418,201 +442,243 @@

  "встановлено для цього файла права доступу 0600 і чи є парою власник-група "

  "файла root.root\n"

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: monitor/monitor.c:2169

+ msgid "Cannot load configuration database\n"

+ msgstr "Не вдалося завантажити базу даних налаштувань\n"

+ 

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "Рівень зневаджування"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "Додавати діагностичні часові позначки"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  msgid "An open file descriptor for the debug logs"

  msgstr "Дескриптор відкритого файла для запису журналів діагностики"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  msgid "Domain of the information provider (mandatory)"

  msgstr "Домен надання відомостей (обов’язковий)"

  

- #: sss_client/pam_sss.c:353

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr "У привілейованого сокета помилковий власник або права доступу."

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr "У відкритого сокета помилковий власник або права доступу."

+ 

+ #: sss_client/common.c:748

+ msgid "Unexpected format of the server credential message."

+ msgstr "Некоректний формат повідомлення щодо реєстраційних даних сервера."

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr "SSSD запущено не від імені користувача root."

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr "Сталася помилка, але не вдалося знайти її опису."

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr "Неочікувана помилка під час пошуку опису помилки"

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "Паролі не збігаються"

  

- #: sss_client/pam_sss.c:422

- msgid "Offline authentication"

- msgstr "Автономне розпізнавання"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr "Підтримки скидання пароля користувачем root не передбачено."

  

- #: sss_client/pam_sss.c:423

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr "Розпізнано за реєстраційними даними з кешу"

+ 

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ", строк дії вашого кешованого пароля завершиться: "

  

- #: sss_client/pam_sss.c:473

- msgid "Offline authentication, authentication is denied until: "

- msgstr "Автономне розпізнавання, розпізнавання заборонено до: "

+ #: sss_client/pam_sss.c:628

+ #, c-format

+ msgid "Your password has expired. You have %d grace login(s) remaining."

+ msgstr "Строк дії вашого пароля вичерпано. Залишилося %d резервних входи."

+ 

+ #: sss_client/pam_sss.c:674

+ #, c-format

+ msgid "Your password will expire in %d %s."

+ msgstr "Строк дії вашого пароля завершиться за %d %s."

+ 

+ #: sss_client/pam_sss.c:723

+ msgid "Authentication is denied until: "

+ msgstr "Розпізнавання заборонено до: "

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "Система працює у автономному режимі, зміна пароля неможлива"

  

- #: sss_client/pam_sss.c:530

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "Спроба зміни пароля зазнала невдачі. "

  

- #: sss_client/pam_sss.c:531

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "Повідомлення сервера: "

  

- #: sss_client/pam_sss.c:898

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "Новий пароль: "

  

- #: sss_client/pam_sss.c:899

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "Ще раз введіть новий пароль: "

  

- #: sss_client/pam_sss.c:957

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "Пароль: "

  

- #: sss_client/pam_sss.c:989

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "Поточний пароль: "

  

- #: sss_client/pam_sss.c:1126

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "Строк дії пароля вичерпано. Змініть ваш пароль."

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  msgid "The debug level to run with"

  msgstr "Рівень діагностики під час запуску"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "Ідентифікатор користувача"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "Ідентифікатор або назва групи користувача"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "Рядок коментаря"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "Домашній каталог"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "Оболонка входу"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "Групи"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "Створити каталог користувача, якщо його ще не існує"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "Ніколи не створювати каталог користувача, перевизначає налаштування"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "Вказати альтернативний основний каталог"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr "Ім’я користувача SELinux для входу до системи"

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "Помилка під час спроби встановити локаль\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "Вкажіть користувача, запис якого слід додати\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "Помилка ініціалізації інструментів: немає локального домену\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "Помилка ініціалізації інструментів\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "У FQDN вказано некоректний домен\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "Внутрішня помилка під час обробки параметрів\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "Групи мають належати до того самого домену, що і користувач\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "Не вдалося знайти групу %s у локальному домені\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "Не вдалося отримати відомості щодо групи користувача\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "Не вдалося встановити типові значення\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr ""

  "Вибраний ідентифікатор користувача не належить до діапазону дозволених\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr "Не вдалося встановити контекст входу SELinux\n"

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "Не вдалося отримати відомості щодо користувача\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr ""

  "Домашній каталог користувача вже існує, копіювання даних з каталогу skel не "

  "виконуватиметься\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "Не вдалося створити домашній каталог користувача: %s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "Не вдалося створити поштовий буфер користувача: %s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr ""

  "Не вдалося отримати ідентифікатор для користувача. Домен переповнено?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr ""

  "Вже існує користувач або група з таким самим іменем, назвою або "

  "ідентифікатором\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "Помилка під час виконання операції. Не вдалося додати користувача.\n"

  
@@ -686,8 +752,8 @@

  msgstr ""

  "Групи-учасники мають належати до того самого домену, що і основна група\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -711,26 +777,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "Помилка під час виконання операції Не вдалося змінити групу.\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%sГрупа: %s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "Магічна приватна "

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sНомер GID: %d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, c-format

  msgid "%sMember users: "

  msgstr "%sКористувачі-учасники: "

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, c-format

  msgid ""

  "\n"
@@ -739,7 +805,7 @@

  "\n"

  "%sє учасником: "

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, c-format

  msgid ""

  "\n"
@@ -748,19 +814,19 @@

  "\n"

  "%sГрупи-учасники: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "Виводити дані щодо непрямих учасників групи рекурсивно"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "Вкажіть групу, дані якої слід показати\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "Не вдалося започаткувати пошук\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"
@@ -768,77 +834,106 @@

  "У локальному домені немає такої групи. Вивід даних груп можливий лише у "

  "межах локального домену.\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "Внутрішня помилка. Не вдалося вивести дані групи.\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  msgid "Remove home directory and mail spool"

  msgstr "Вилучити домашній каталог і поштовий буфер"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  msgid "Do not remove home directory and mail spool"

  msgstr "Не вилучати домашній каталог і поштовий буфер"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "Примусово вилучити файли, які не належать користувачеві"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr "Припинити роботу процесів користувача перед вилученням його запису"

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "Вкажіть користувача, запис якого слід вилучити\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr ""

  "Користувач %s не належить визначеному діапазону ідентифікаторів домену\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr "Не вдалося відновити початковий контекст входу SELinux\n"

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ "ПОПЕРЕДЖЕННЯ: користувач (uid %lu) все ще працював у системі на час "

+ "вилучення його запису.\n"

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ "Не вдалося визначити, чи увійшов користувач до системи на цій платформі"

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr "Помилка під час перевірки входу користувача до системи\n"

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr "Помилка команди, яку слід було виконати після вилучення запису: %s\n"

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "Домашній каталог не буде вилучено. Він не належить користувачеві.\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "Не вдалося вилучити домашній каталог: %s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr ""

  "У локальному домені немає такого користувача. Вилучення користувачів можливе "

  "лише у межах локального домену.\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "Внутрішня помилка Не вдалося вилучити запис користувача.\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "Ідентифікатор групи користувача"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  msgid "Groups to add this user to"

  msgstr "Групи, до яких слід додати цього користувача"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  msgid "Groups to remove this user from"

  msgstr "Групи, з яких слід вилучити цього користувача"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "Заблокувати обліковий запис"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "Розблокувати обліковий запис"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "Вкажіть користувача, запис якого слід змінити\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"
@@ -846,23 +941,23 @@

  "Не вдалося знайти користувача у локальному домені. Зміну записів "

  "користувачів можна виконувати лише у межах локального домену\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr ""

  "Не вдалося змінити запис користувача. Перевірте, чи правильно вказано назви "

  "груп\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr ""

  "Не вдалося змінити запис користувача. Користувач вже є учасником груп?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr ""

  "Помилка під час виконання операції. Не вдалося змінити запис користувача.\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "Не вистачає пам'яті\n"

  
@@ -871,6 +966,23 @@

  msgid "%s must be run as root\n"

  msgstr "%s слід виконувати від імені користувача root\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr "Надіслати діагностичні дані до файлів, а не до stderr"

+ 

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "Реєстраційний запис служби зміни паролів"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "Ідентифікатор або назва групи користувача"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "Не вдалося отримати відомості щодо групи користувача\n"

+ 

+ #~ msgid "Length of time between attempts to reconnect while offline"

+ #~ msgstr ""

+ #~ "Проміжок часу між повторними спробами встановлення з’єднання у "

+ #~ "автономному режимі"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "Автономне розпізнавання"

file modified
+253 -169
@@ -7,10 +7,11 @@

  msgstr ""

  "Project-Id-Version: sss_daemon 1.1.0\n"

  "Report-Msgid-Bugs-To: sssd-devel@lists.fedorahosted.org\n"

- "POT-Creation-Date: 2010-03-22 10:09-0400\n"

+ "POT-Creation-Date: 2010-10-08 19:22-0400\n"

  "PO-Revision-Date: 2010-03-22 22:00+0800\n"

  "Last-Translator: Cheng-Chia Tseng <pswo10680@gmail.com>\n"

  "Language-Team: Fedora-trans-zh_tw <trans-zh_tw@lists.fedoraproject.org>\n"

+ "Language: \n"

  "MIME-Version: 1.0\n"

  "Content-Type: text/plain; charset=utf-8\n"

  "Content-Transfer-Encoding: 8bit\n"
@@ -170,256 +171,272 @@

  msgid "How long to keep cached entries after last successful login (days)"

  msgstr ""

  

- #: config/SSSDConfig.py:86

+ #: config/SSSDConfig.py:84

+ msgid "How long to wait for replies from DNS when resolving servers (seconds)"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:87

  msgid "IPA domain"

  msgstr "IPA 網域"

  

- #: config/SSSDConfig.py:87

+ #: config/SSSDConfig.py:88

  msgid "IPA server address"

  msgstr "IPA 伺服器位址"

  

- #: config/SSSDConfig.py:88

+ #: config/SSSDConfig.py:89

  msgid "IPA client hostname"

  msgstr "IPA 客戶端主機名稱"

  

- #: config/SSSDConfig.py:91 config/SSSDConfig.py:120

+ #: config/SSSDConfig.py:90

+ msgid "Whether to automatically update the client's DNS entry in FreeIPA"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:91

+ msgid "The interface whose IP should be used for dynamic DNS updates"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:94 config/SSSDConfig.py:122

  msgid "Kerberos server address"

  msgstr "Kerberos 伺服器位址"

  

- #: config/SSSDConfig.py:92 config/SSSDConfig.py:121

+ #: config/SSSDConfig.py:95 config/SSSDConfig.py:123

  msgid "Kerberos realm"

  msgstr ""

  

- #: config/SSSDConfig.py:93

+ #: config/SSSDConfig.py:96

  msgid "Authentication timeout"

  msgstr "認證逾時"

  

- #: config/SSSDConfig.py:96

+ #: config/SSSDConfig.py:99

  msgid "Directory to store credential caches"

  msgstr "儲存憑證快取的目錄"

  

- #: config/SSSDConfig.py:97

+ #: config/SSSDConfig.py:100

  msgid "Location of the user's credential cache"

  msgstr "使用者憑證快取的位置"

  

- #: config/SSSDConfig.py:98

+ #: config/SSSDConfig.py:101

  msgid "Location of the keytab to validate credentials"

  msgstr "驗證憑證用的金鑰表格位置"

  

- #: config/SSSDConfig.py:99

+ #: config/SSSDConfig.py:102

  msgid "Enable credential validation"

  msgstr "啟用憑證驗證"

  

- #: config/SSSDConfig.py:102

- msgid "The principal of the change password service"

- msgstr "變更密碼的服務其原則"

- 

  #: config/SSSDConfig.py:103

- msgid "Server where the change password service is running if not on the KDC"

+ msgid "Store password if offline for later online authentication"

  msgstr ""

  

  #: config/SSSDConfig.py:106

+ msgid "Server where the change password service is running if not on the KDC"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:109

  msgid "ldap_uri, The URI of the LDAP server"

  msgstr ""

  

- #: config/SSSDConfig.py:107

+ #: config/SSSDConfig.py:110

  msgid "The default base DN"

  msgstr ""

  

- #: config/SSSDConfig.py:108

+ #: config/SSSDConfig.py:111

  msgid "The Schema Type in use on the LDAP server, rfc2307"

  msgstr ""

  

- #: config/SSSDConfig.py:109

+ #: config/SSSDConfig.py:112

  msgid "The default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:110

+ #: config/SSSDConfig.py:113

  msgid "The type of the authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:111

+ #: config/SSSDConfig.py:114

  msgid "The authentication token of the default bind DN"

  msgstr ""

  

- #: config/SSSDConfig.py:112

+ #: config/SSSDConfig.py:115

  msgid "Length of time to attempt connection"

  msgstr ""

  

- #: config/SSSDConfig.py:113

+ #: config/SSSDConfig.py:116

  msgid "Length of time to attempt synchronous LDAP operations"

  msgstr ""

  

- #: config/SSSDConfig.py:114

- msgid "Length of time between attempts to reconnect while offline"

- msgstr ""

- 

- #: config/SSSDConfig.py:115

+ #: config/SSSDConfig.py:117

  #, fuzzy

  msgid "File that contains CA certificates"

  msgstr "含有 CA 憑證的檔案"

  

- #: config/SSSDConfig.py:116

+ #: config/SSSDConfig.py:118

  msgid "Path to CA certificate directory"

  msgstr ""

  

- #: config/SSSDConfig.py:117

+ #: config/SSSDConfig.py:119

  msgid "Require TLS certificate verification"

  msgstr "需要 TLS 憑證驗證"

  

- #: config/SSSDConfig.py:118

+ #: config/SSSDConfig.py:120

  msgid "Specify the sasl mechanism to use"

  msgstr "指定要使用的 sasl 機制"

  

- #: config/SSSDConfig.py:119

+ #: config/SSSDConfig.py:121

  msgid "Specify the sasl authorization id to use"

  msgstr "指定要使用的 sasl 認證 id"

  

- #: config/SSSDConfig.py:122

+ #: config/SSSDConfig.py:124

  msgid "Kerberos service keytab"

  msgstr ""

  

- #: config/SSSDConfig.py:123

+ #: config/SSSDConfig.py:125

  msgid "Use Kerberos auth for LDAP connection"

  msgstr ""

  

- #: config/SSSDConfig.py:124

+ #: config/SSSDConfig.py:126

  msgid "Follow LDAP referrals"

  msgstr ""

  

  #: config/SSSDConfig.py:127

+ msgid "Lifetime of TGT for LDAP connection"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:130

  msgid "Length of time to wait for a search request"

  msgstr "搜尋請求的等候時間長度"

  

- #: config/SSSDConfig.py:128

+ #: config/SSSDConfig.py:131

  #, fuzzy

  msgid "Length of time between enumeration updates"

  msgstr "在列舉更新之間的長度"

  

- #: config/SSSDConfig.py:129

- msgid "Require TLS for ID lookups, false"

+ #: config/SSSDConfig.py:132

+ msgid "Require TLS for ID lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:130

+ #: config/SSSDConfig.py:133

  msgid "Base DN for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:131

+ #: config/SSSDConfig.py:134

  msgid "Scope of user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:132

+ #: config/SSSDConfig.py:135

  msgid "Filter for user lookups"

  msgstr ""

  

- #: config/SSSDConfig.py:133

+ #: config/SSSDConfig.py:136

  msgid "Objectclass for users"

  msgstr ""

  

- #: config/SSSDConfig.py:134

+ #: config/SSSDConfig.py:137

  msgid "Username attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:135

+ #: config/SSSDConfig.py:138

  #, fuzzy

  msgid "UID attribute"

  msgstr "UID 屬性"

  

- #: config/SSSDConfig.py:136

+ #: config/SSSDConfig.py:139

  #, fuzzy

  msgid "Primary GID attribute"

  msgstr "主要 GID 屬性"

  

- #: config/SSSDConfig.py:137

+ #: config/SSSDConfig.py:140

  #, fuzzy

  msgid "GECOS attribute"

  msgstr "GEOS 屬性"

  

- #: config/SSSDConfig.py:138

+ #: config/SSSDConfig.py:141

  #, fuzzy

  msgid "Home directory attribute"

  msgstr "家目錄屬性"

  

- #: config/SSSDConfig.py:139

+ #: config/SSSDConfig.py:142

  #, fuzzy

  msgid "Shell attribute"

  msgstr "Shell 屬性"

  

- #: config/SSSDConfig.py:140

+ #: config/SSSDConfig.py:143

  #, fuzzy

  msgid "UUID attribute"

  msgstr "UUID 屬性"

  

- #: config/SSSDConfig.py:141

+ #: config/SSSDConfig.py:144

  #, fuzzy

  msgid "User principal attribute (for Kerberos)"

  msgstr "使用者原則屬性(供 Kerberos 使用)"

  

- #: config/SSSDConfig.py:142

+ #: config/SSSDConfig.py:145

  msgid "Full Name"

  msgstr "全名"

  

- #: config/SSSDConfig.py:143

+ #: config/SSSDConfig.py:146

  msgid "memberOf attribute"

  msgstr ""

  

- #: config/SSSDConfig.py:144

+ #: config/SSSDConfig.py:147

  #, fuzzy

  msgid "Modification time attribute"

  msgstr "修改時間屬性"

  

- #: config/SSSDConfig.py:147

+ #: config/SSSDConfig.py:150

  msgid "Policy to evaluate the password expiration"

  msgstr "評估密碼過期時效的策略"

  

- #: config/SSSDConfig.py:150

+ #: config/SSSDConfig.py:153

+ msgid "LDAP filter to determine access privileges"

+ msgstr ""

+ 

+ #: config/SSSDConfig.py:156

  msgid "Comma separated list of allowed users"

  msgstr "許可的使用者清單,請使用半形逗號作為分隔"

  

- #: config/SSSDConfig.py:151

+ #: config/SSSDConfig.py:157

  msgid "Comma separated list of prohibited users"

  msgstr "被禁止的使用者清單,請使用半形逗號作為分隔"

  

- #: config/SSSDConfig.py:154

+ #: config/SSSDConfig.py:160

  msgid "Default shell, /bin/bash"

  msgstr "預設 shell,/bin/bash"

  

- #: config/SSSDConfig.py:155

+ #: config/SSSDConfig.py:161

  #, fuzzy

  msgid "Base for home directories"

  msgstr "家目錄的基礎"

  

- #: config/SSSDConfig.py:158

+ #: config/SSSDConfig.py:164

  msgid "The name of the NSS library to use"

  msgstr "要使用的 NSS 函式庫名稱"

  

- #: config/SSSDConfig.py:161

+ #: config/SSSDConfig.py:167

  msgid "PAM stack to use"

  msgstr "要使用的 PAM 堆疊"

  

- #: monitor/monitor.c:2187

+ #: monitor/monitor.c:2089

  msgid "Become a daemon (default)"

  msgstr "作為幕後程式 (預設)"

  

- #: monitor/monitor.c:2189

+ #: monitor/monitor.c:2091

  msgid "Run interactive (not a daemon)"

  msgstr "以互動方式執行 (非幕後程式)"

  

- #: monitor/monitor.c:2191

+ #: monitor/monitor.c:2093

  msgid "Specify a non-default config file"

  msgstr "指定非預設的配置檔"

  

- #: monitor/monitor.c:2217

+ #: monitor/monitor.c:2119

  msgid "sssd must be run as root\n"

  msgstr "sssd 必須以 root 身分執行\n"

  

- #: monitor/monitor.c:2252

+ #: monitor/monitor.c:2154

  msgid ""

  "nscd socket was detected.  As nscd caching capabilities may conflict with "

  "SSSD, it is recommended to not run nscd in parallel with SSSD\n"

  msgstr ""

  

- #: monitor/monitor.c:2262

+ #: monitor/monitor.c:2164

  #, c-format

  msgid ""

  "Cannot read config file %s, please check if permissions are 0600 and the "
@@ -427,213 +444,242 @@

  msgstr ""

  "無法讀取配置檔 %s,請確認權限是否為 0600 並且檔案是由 root.root 所擁有\n"

  

- #: monitor/monitor.c:2267

+ #: monitor/monitor.c:2169

  msgid "Cannot load configuration database\n"

  msgstr ""

  

- #: providers/krb5/krb5_child.c:929 providers/ldap/ldap_child.c:316

- #: util/util.h:61

+ #: providers/krb5/krb5_child.c:983 providers/ldap/ldap_child.c:377

+ #: util/util.h:62

  msgid "Debug level"

  msgstr "除錯層級"

  

- #: providers/krb5/krb5_child.c:931 providers/ldap/ldap_child.c:318

- #: util/util.h:65

+ #: providers/krb5/krb5_child.c:985 providers/ldap/ldap_child.c:379

+ #: util/util.h:66

  msgid "Add debug timestamps"

  msgstr "加入除錯時間戳記"

  

- #: providers/krb5/krb5_child.c:933 providers/ldap/ldap_child.c:320

+ #: providers/krb5/krb5_child.c:987 providers/ldap/ldap_child.c:381

  #, fuzzy

  msgid "An open file descriptor for the debug logs"

  msgstr "供除錯日誌使用的開啟檔案描述符"

  

- #: providers/data_provider_be.c:1156

+ #: providers/data_provider_be.c:1154

  #, fuzzy

  msgid "Domain of the information provider (mandatory)"

  msgstr "資訊提供者的網域(委任)"

  

- #: sss_client/pam_sss.c:354

+ #: sss_client/common.c:742

+ msgid "Privileged socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:745

+ msgid "Public socket has wrong ownership or permissions."

+ msgstr ""

+ 

+ #: sss_client/common.c:748

+ #, fuzzy

+ msgid "Unexpected format of the server credential message."

+ msgstr "使用者憑證快取的位置"

+ 

+ #: sss_client/common.c:751

+ msgid "SSSD is not run by root."

+ msgstr ""

+ 

+ #: sss_client/common.c:756

+ msgid "An error occurred, but no description can be found."

+ msgstr ""

+ 

+ #: sss_client/common.c:762

+ msgid "Unexpected error while looking for an error description"

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:372

  msgid "Passwords do not match"

  msgstr "密碼不相符"

  

- #: sss_client/pam_sss.c:423

- msgid "Offline authentication"

- msgstr "離線認證"

+ #: sss_client/pam_sss.c:556

+ msgid "Password reset by root is not supported."

+ msgstr ""

+ 

+ #: sss_client/pam_sss.c:597

+ msgid "Authenticated with cached credentials"

+ msgstr ""

  

- #: sss_client/pam_sss.c:424

+ #: sss_client/pam_sss.c:598

  msgid ", your cached password will expire at: "

  msgstr ",您快取的密碼將在此刻過期:"

  

- #: sss_client/pam_sss.c:454

+ #: sss_client/pam_sss.c:628

  #, c-format

  msgid "Your password has expired. You have %d grace login(s) remaining."

  msgstr ""

  

- #: sss_client/pam_sss.c:500

+ #: sss_client/pam_sss.c:674

  #, fuzzy, c-format

  msgid "Your password will expire in %d %s."

  msgstr ",您快取的密碼將在此刻過期:"

  

- #: sss_client/pam_sss.c:549

+ #: sss_client/pam_sss.c:723

  #, fuzzy

- msgid "Offline authentication, authentication is denied until: "

+ msgid "Authentication is denied until: "

  msgstr "離線認證,認證被定義到:"

  

- #: sss_client/pam_sss.c:576

+ #: sss_client/pam_sss.c:750

  msgid "System is offline, password change not possible"

  msgstr "系統已離線,不可能作密碼變更"

  

- #: sss_client/pam_sss.c:606

+ #: sss_client/pam_sss.c:780 sss_client/pam_sss.c:793

  msgid "Password change failed. "

  msgstr "密碼變更失敗。"

  

- #: sss_client/pam_sss.c:607

+ #: sss_client/pam_sss.c:783 sss_client/pam_sss.c:794

  msgid "Server message: "

  msgstr "伺服器訊息:"

  

- #: sss_client/pam_sss.c:980

+ #: sss_client/pam_sss.c:1197

  msgid "New Password: "

  msgstr "新密碼:"

  

- #: sss_client/pam_sss.c:981

+ #: sss_client/pam_sss.c:1198

  msgid "Reenter new Password: "

  msgstr "再次輸入新密碼:"

  

- #: sss_client/pam_sss.c:1039

+ #: sss_client/pam_sss.c:1280

  msgid "Password: "

  msgstr "密碼:"

  

- #: sss_client/pam_sss.c:1071

+ #: sss_client/pam_sss.c:1312

  msgid "Current Password: "

  msgstr "目前的密碼:"

  

- #: sss_client/pam_sss.c:1208

+ #: sss_client/pam_sss.c:1458

  msgid "Password expired. Change your password now."

  msgstr "密碼已過期。請立刻變更您的密碼。"

  

- #: tools/sss_useradd.c:114 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

- #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1008 tools/sss_userdel.c:45

- #: tools/sss_usermod.c:46

+ #: tools/sss_useradd.c:48 tools/sss_groupadd.c:41 tools/sss_groupdel.c:43

+ #: tools/sss_groupmod.c:42 tools/sss_groupshow.c:1016 tools/sss_userdel.c:142

+ #: tools/sss_usermod.c:47

  #, fuzzy

  msgid "The debug level to run with"

  msgstr "要依那種除錯層級執行"

  

- #: tools/sss_useradd.c:115 tools/sss_usermod.c:47

+ #: tools/sss_useradd.c:49 tools/sss_usermod.c:48

  msgid "The UID of the user"

  msgstr "使用者的 UID"

  

- #: tools/sss_useradd.c:116

- msgid "The GID or group name of the user"

- msgstr "使用者的 GID 或群組名稱"

- 

- #: tools/sss_useradd.c:117 tools/sss_usermod.c:49

+ #: tools/sss_useradd.c:50 tools/sss_usermod.c:50

  msgid "The comment string"

  msgstr "註解字串"

  

- #: tools/sss_useradd.c:118 tools/sss_usermod.c:50

+ #: tools/sss_useradd.c:51 tools/sss_usermod.c:51

  msgid "Home directory"

  msgstr "家目錄"

  

- #: tools/sss_useradd.c:119 tools/sss_usermod.c:51

+ #: tools/sss_useradd.c:52 tools/sss_usermod.c:52

  msgid "Login shell"

  msgstr "登入用 shell"

  

- #: tools/sss_useradd.c:120

+ #: tools/sss_useradd.c:53

  msgid "Groups"

  msgstr "群組"

  

- #: tools/sss_useradd.c:121

+ #: tools/sss_useradd.c:54

  msgid "Create user's directory if it does not exist"

  msgstr "如果使用者的目錄不存在便將它建立"

  

- #: tools/sss_useradd.c:122

+ #: tools/sss_useradd.c:55

  msgid "Never create user's directory, overrides config"

  msgstr "永遠不建立使用者的目錄,凌駕配置"

  

- #: tools/sss_useradd.c:123

+ #: tools/sss_useradd.c:56

  msgid "Specify an alternative skeleton directory"

  msgstr "指定替代的骨幹目錄"

  

- #: tools/sss_useradd.c:137 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

- #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1019 tools/sss_userdel.c:57

- #: tools/sss_usermod.c:70

+ #: tools/sss_useradd.c:57 tools/sss_usermod.c:57

+ msgid "The SELinux user for user's login"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:71 tools/sss_groupadd.c:56 tools/sss_groupdel.c:52

+ #: tools/sss_groupmod.c:63 tools/sss_groupshow.c:1027 tools/sss_userdel.c:159

+ #: tools/sss_usermod.c:72

  msgid "Error setting the locale\n"

  msgstr "設定區域設置時發生錯誤\n"

  

- #: tools/sss_useradd.c:172

+ #: tools/sss_useradd.c:107

  msgid "Specify user to add\n"

  msgstr "指定要加入的使用者\n"

  

- #: tools/sss_useradd.c:183 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

- #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1056 tools/sss_userdel.c:102

- #: tools/sss_usermod.c:126

+ #: tools/sss_useradd.c:118 tools/sss_groupadd.c:86 tools/sss_groupdel.c:81

+ #: tools/sss_groupmod.c:111 tools/sss_groupshow.c:1064 tools/sss_userdel.c:208

+ #: tools/sss_usermod.c:128

  msgid "Error initializing the tools - no local domain\n"

  msgstr "初始化工具時發生錯誤 - 沒有本機網域\n"

  

- #: tools/sss_useradd.c:185 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

- #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1058 tools/sss_userdel.c:104

- #: tools/sss_usermod.c:128

+ #: tools/sss_useradd.c:120 tools/sss_groupadd.c:88 tools/sss_groupdel.c:83

+ #: tools/sss_groupmod.c:113 tools/sss_groupshow.c:1066 tools/sss_userdel.c:210

+ #: tools/sss_usermod.c:130

  msgid "Error initializing the tools\n"

  msgstr "初始化工具時發生錯誤\n"

  

- #: tools/sss_useradd.c:194 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

- #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1067 tools/sss_userdel.c:113

- #: tools/sss_usermod.c:137

+ #: tools/sss_useradd.c:129 tools/sss_groupadd.c:97 tools/sss_groupdel.c:92

+ #: tools/sss_groupmod.c:121 tools/sss_groupshow.c:1075 tools/sss_userdel.c:219

+ #: tools/sss_usermod.c:139

  msgid "Invalid domain specified in FQDN\n"

  msgstr "在 FQDN 內指定了無效的網域\n"

  

- #: tools/sss_useradd.c:203 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

- #: tools/sss_usermod.c:162 tools/sss_usermod.c:189

+ #: tools/sss_useradd.c:138 tools/sss_groupmod.c:143 tools/sss_groupmod.c:170

+ #: tools/sss_usermod.c:164 tools/sss_usermod.c:191

  msgid "Internal error while parsing parameters\n"

  msgstr "當解析參數時發生內部錯誤\n"

  

- #: tools/sss_useradd.c:211 tools/sss_usermod.c:170 tools/sss_usermod.c:197

+ #: tools/sss_useradd.c:146 tools/sss_usermod.c:172 tools/sss_usermod.c:199

  msgid "Groups must be in the same domain as user\n"

  msgstr "群組必須位於與使用者相同的網域內\n"

  

- #: tools/sss_useradd.c:219

+ #: tools/sss_useradd.c:154

  #, c-format

  msgid "Cannot find group %s in local domain\n"

  msgstr "在本機網域內找不到 %s 群組\n"

  

- #: tools/sss_useradd.c:229

- msgid "Cannot get group information for the user\n"

- msgstr "無法為這位使用者設定群組資訊\n"

- 

- #: tools/sss_useradd.c:244 tools/sss_userdel.c:123

+ #: tools/sss_useradd.c:169 tools/sss_userdel.c:229

  msgid "Cannot set default values\n"

  msgstr "無法設定預設值\n"

  

- #: tools/sss_useradd.c:251 tools/sss_usermod.c:153

+ #: tools/sss_useradd.c:176 tools/sss_usermod.c:155

  msgid "The selected UID is outside the allowed range\n"

  msgstr "所選的 UID 位於許可的範圍外\n"

  

- #: tools/sss_useradd.c:285

+ #: tools/sss_useradd.c:202 tools/sss_usermod.c:242

+ msgid "Cannot set SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_useradd.c:219

  msgid "Cannot get info about the user\n"

  msgstr "無法取得關於這位使用者的資訊\n"

  

- #: tools/sss_useradd.c:299

+ #: tools/sss_useradd.c:233

  msgid "User's home directory already exists, not copying data from skeldir\n"

  msgstr "使用者的家目錄已經存在,不會從骨幹目錄複製資料\n"

  

- #: tools/sss_useradd.c:302

+ #: tools/sss_useradd.c:236

  #, c-format

  msgid "Cannot create user's home directory: %s\n"

  msgstr "無法建立使用者的家目錄:%s\n"

  

- #: tools/sss_useradd.c:313

+ #: tools/sss_useradd.c:247

  #, c-format

  msgid "Cannot create user's mail spool: %s\n"

  msgstr "無法建立使用者的郵件 spool:%s\n"

  

- #: tools/sss_useradd.c:325

+ #: tools/sss_useradd.c:259

  msgid "Could not allocate ID for the user - domain full?\n"

  msgstr "無法為使用者分配 ID - 網域已滿?\n"

  

- #: tools/sss_useradd.c:329

+ #: tools/sss_useradd.c:263

  msgid "A user or group with the same name or ID already exists\n"

  msgstr "已經存在相同名稱的使用者或群組\n"

  

- #: tools/sss_useradd.c:335

+ #: tools/sss_useradd.c:269

  msgid "Transaction error. Could not add user.\n"

  msgstr "處理事項發生錯誤。無法加入使用者。\n"

  
@@ -704,8 +750,8 @@

  msgid "Member groups must be in the same domain as parent group\n"

  msgstr "成員群組必須位於與親代群組相同的網域內\n"

  

- #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:178

- #: tools/sss_usermod.c:205

+ #: tools/sss_groupmod.c:159 tools/sss_groupmod.c:186 tools/sss_usermod.c:180

+ #: tools/sss_usermod.c:207

  #, c-format

  msgid ""

  "Cannot find group %s in local domain, only groups in local domain are "
@@ -725,26 +771,26 @@

  msgid "Transaction error. Could not modify group.\n"

  msgstr "處理事項發生錯誤。無法修改群組。\n"

  

- #: tools/sss_groupshow.c:954

+ #: tools/sss_groupshow.c:962

  #, c-format

  msgid "%s%sGroup: %s\n"

  msgstr "%s%s群組:%s\n"

  

- #: tools/sss_groupshow.c:955

+ #: tools/sss_groupshow.c:963

  msgid "Magic Private "

  msgstr "魔法隱私"

  

- #: tools/sss_groupshow.c:957

+ #: tools/sss_groupshow.c:965

  #, c-format

  msgid "%sGID number: %d\n"

  msgstr "%sGID 編號:%d\n"

  

- #: tools/sss_groupshow.c:959

+ #: tools/sss_groupshow.c:967

  #, fuzzy, c-format

  msgid "%sMember users: "

  msgstr "%s成員使用者:"

  

- #: tools/sss_groupshow.c:966

+ #: tools/sss_groupshow.c:974

  #, fuzzy, c-format

  msgid ""

  "\n"
@@ -753,7 +799,7 @@

  "\n"

  "%s是該群組的成員:"

  

- #: tools/sss_groupshow.c:973

+ #: tools/sss_groupshow.c:981

  #, fuzzy, c-format

  msgid ""

  "\n"
@@ -762,114 +808,140 @@

  "\n"

  "%s成員群組: "

  

- #: tools/sss_groupshow.c:1010

+ #: tools/sss_groupshow.c:1018

  msgid "Print indirect group members recursively"

  msgstr "遞迴地列出間接的群組成員"

  

- #: tools/sss_groupshow.c:1045

+ #: tools/sss_groupshow.c:1053

  msgid "Specify group to show\n"

  msgstr "指定要顯示的群組\n"

  

- #: tools/sss_groupshow.c:1081 tools/sss_groupshow.c:1099

+ #: tools/sss_groupshow.c:1089 tools/sss_groupshow.c:1107

  msgid "Cannot initiate search\n"

  msgstr "無法開始搜尋\n"

  

- #: tools/sss_groupshow.c:1115

+ #: tools/sss_groupshow.c:1123

  msgid ""

  "No such group in local domain. Printing groups only allowed in local "

  "domain.\n"

  msgstr "本機網域內沒有這樣的群組。只許可在本機網域內列出群組。\n"

  

- #: tools/sss_groupshow.c:1120

+ #: tools/sss_groupshow.c:1128

  msgid "Internal error. Could not print group.\n"

  msgstr "內部錯誤。無法列出群組。\n"

  

- #: tools/sss_userdel.c:46

+ #: tools/sss_userdel.c:144

  #, fuzzy

  msgid "Remove home directory and mail spool"

  msgstr "移除家目錄與郵件 spool"

  

- #: tools/sss_userdel.c:47

+ #: tools/sss_userdel.c:146

  #, fuzzy

  msgid "Do not remove home directory and mail spool"

  msgstr "不要移除家目錄與郵件 spool"

  

- #: tools/sss_userdel.c:48

+ #: tools/sss_userdel.c:148

  msgid "Force removal of files not owned by the user"

  msgstr "強制檔案的移除並非由使用者所擁有"

  

- #: tools/sss_userdel.c:91

+ #: tools/sss_userdel.c:150

+ msgid "Kill users' processes before removing him"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:197

  msgid "Specify user to delete\n"

  msgstr "指定要刪除的使用者\n"

  

- #: tools/sss_userdel.c:141

+ #: tools/sss_userdel.c:247

  #, c-format

  msgid "User %s is outside the defined ID range for domain\n"

  msgstr "使用者 %s 位於為網域所定義的 ID 範圍外\n"

  

- #: tools/sss_userdel.c:172

+ #: tools/sss_userdel.c:285

+ msgid "Cannot reset SELinux login context\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:297

+ #, c-format

+ msgid "WARNING: The user (uid %lu) was still logged in when deleted.\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:302

+ msgid "Cannot determine if the user was logged in on this platform"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:307

+ msgid "Error while checking if the user was logged in\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:314

+ #, c-format

+ msgid "The post-delete command failed: %s\n"

+ msgstr ""

+ 

+ #: tools/sss_userdel.c:326

  msgid "Not removing home dir - not owned by user\n"

  msgstr "不會移除家目錄 - 並非由使用者所擁有\n"

  

- #: tools/sss_userdel.c:174

+ #: tools/sss_userdel.c:328

  #, c-format

  msgid "Cannot remove homedir: %s\n"

  msgstr "無法移除家目錄:%s\n"

  

- #: tools/sss_userdel.c:186

+ #: tools/sss_userdel.c:340

  msgid ""

  "No such user in local domain. Removing users only allowed in local domain.\n"

  msgstr "在本機網域內沒有這樣的使用者。只許可在本機網域內移除使用者。\n"

  

- #: tools/sss_userdel.c:191

+ #: tools/sss_userdel.c:345

  msgid "Internal error. Could not remove user.\n"

  msgstr "內部錯誤。無法移除使用者。\n"

  

- #: tools/sss_usermod.c:48

+ #: tools/sss_usermod.c:49

  msgid "The GID of the user"

  msgstr "使用者的 GID"

  

- #: tools/sss_usermod.c:52

+ #: tools/sss_usermod.c:53

  #, fuzzy

  msgid "Groups to add this user to"

  msgstr "將此使用者加入何群組"

  

- #: tools/sss_usermod.c:53

+ #: tools/sss_usermod.c:54

  #, fuzzy

  msgid "Groups to remove this user from"

  msgstr "將此使用者從何群組移除"

  

- #: tools/sss_usermod.c:54

+ #: tools/sss_usermod.c:55

  msgid "Lock the account"

  msgstr "鎖住這個帳號"

  

- #: tools/sss_usermod.c:55

+ #: tools/sss_usermod.c:56

  msgid "Unlock the account"

  msgstr "解除這個帳號的鎖"

  

- #: tools/sss_usermod.c:115

+ #: tools/sss_usermod.c:117

  msgid "Specify user to modify\n"

  msgstr "指定要修改的使用者\n"

  

- #: tools/sss_usermod.c:146

+ #: tools/sss_usermod.c:148

  msgid ""

  "Cannot find user in local domain, modifying users is allowed only in local "

  "domain\n"

  msgstr "在本機網域內找不到使用者,只許可在本機網域內修改使用者\n"

  

- #: tools/sss_usermod.c:241

+ #: tools/sss_usermod.c:252

  msgid "Could not modify user - check if group names are correct\n"

  msgstr "無法修改使用者 - 請檢查群組名稱是否正確\n"

  

- #: tools/sss_usermod.c:245

+ #: tools/sss_usermod.c:256

  msgid "Could not modify user - user already member of groups?\n"

  msgstr "無法修改使用者 - 使用者是否已經是群組的成員?\n"

  

- #: tools/sss_usermod.c:249

+ #: tools/sss_usermod.c:260

  msgid "Transaction error. Could not modify user.\n"

  msgstr "處理事項發生錯誤。無法修改使用者。\n"

  

- #: tools/tools_util.c:292

+ #: tools/tools_util.c:293

  msgid "Out of memory\n"

  msgstr "記憶體耗盡\n"

  
@@ -878,6 +950,18 @@

  msgid "%s must be run as root\n"

  msgstr "%s 必須以 root 身分執行\n"

  

- #: util/util.h:63

+ #: util/util.h:64

  msgid "Send the debug output to files instead of stderr"

  msgstr "傳送除錯輸出到檔案而不是標準輸出"

+ 

+ #~ msgid "The principal of the change password service"

+ #~ msgstr "變更密碼的服務其原則"

+ 

+ #~ msgid "The GID or group name of the user"

+ #~ msgstr "使用者的 GID 或群組名稱"

+ 

+ #~ msgid "Cannot get group information for the user\n"

+ #~ msgstr "無法為這位使用者設定群組資訊\n"

+ 

+ #~ msgid "Offline authentication"

+ #~ msgstr "離線認證"

file modified
+103 -17
@@ -33,6 +33,42 @@

  #include "db/sysdb.h"

  #include "providers/child_common.h"

  

+ struct sss_child_ctx {

+     struct tevent_signal *sige;

+     pid_t pid;

+     int child_status;

+     sss_child_callback_t cb;

+     void *pvt;

+ };

+ 

+ int child_handler_setup(struct tevent_context *ev, int pid,

+                         sss_child_callback_t cb, void *pvt)

+ {

+     struct sss_child_ctx *child_ctx;

+ 

+     DEBUG(8, ("Setting up signal handler up for pid [%d]\n", pid));

+ 

+     child_ctx = talloc_zero(ev, struct sss_child_ctx);

+     if (child_ctx == NULL) {

+         return ENOMEM;

+     }

+ 

+     child_ctx->sige = tevent_add_signal(ev, child_ctx, SIGCHLD, SA_SIGINFO,

+                                         child_sig_handler, child_ctx);

+     if(!child_ctx->sige) {

+         /* Error setting up signal handler */

+         talloc_free(child_ctx);

+         return ENOMEM;

+     }

+ 

+     child_ctx->pid = pid;

+     child_ctx->cb = cb;

+     child_ctx->pvt = pvt;

+ 

+     DEBUG(8, ("Signal handler set up for pid [%d]\n", pid));

+     return EOK;

+ }

+ 

  /* Async communication with the child process via a pipe */

  

  struct write_pipe_state {
@@ -256,37 +292,87 @@

      return;

  }

  

+ static void child_invoke_callback(struct tevent_context *ev,

+                                   struct tevent_immediate *imm,

+                                   void *pvt);

  void child_sig_handler(struct tevent_context *ev,

                         struct tevent_signal *sige, int signum,

                         int count, void *__siginfo, void *pvt)

  {

-     int ret;

-     int child_status;

+     int ret, err;

+     struct sss_child_ctx *child_ctx;

+     struct tevent_immediate *imm;

  

-     DEBUG(7, ("Waiting for [%d] childeren.\n", count));

-     do {

-         errno = 0;

-         ret = waitpid(-1, &child_status, WNOHANG);

- 

-         if (ret == -1) {

-             DEBUG(1, ("waitpid failed [%d][%s].\n", errno, strerror(errno)));

-         } else if (ret == 0) {

-             DEBUG(1, ("waitpid did not found a child with changed status.\n"));

-         } else  {

-             if (WEXITSTATUS(child_status) != 0) {

+     if (count <= 0) {

+         DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));

+         return;

+     }

+ 

+     child_ctx = talloc_get_type(pvt, struct sss_child_ctx);

+     DEBUG(7, ("Waiting for child [%d].\n", child_ctx->pid));

+ 

+     errno = 0;

+     ret = waitpid(child_ctx->pid, &child_ctx->child_status, WNOHANG);

+ 

+     if (ret == -1) {

+         err = errno;

+         DEBUG(1, ("waitpid failed [%d][%s].\n", err, strerror(err)));

+     } else if (ret == 0) {

+         DEBUG(1, ("waitpid did not found a child with changed status.\n"));

+     } else {

+         if WIFEXITED(child_ctx->child_status) {

+             if (WEXITSTATUS(child_ctx->child_status) != 0) {

                  DEBUG(1, ("child [%d] failed with status [%d].\n", ret,

-                           child_status));

+                           WEXITSTATUS(child_ctx->child_status)));

              } else {

-                 DEBUG(4, ("child [%d] finished successful.\n", ret));

+                 DEBUG(4, ("child [%d] finished successfully.\n", ret));

+             }

+         } else if WIFSIGNALED(child_ctx->child_status) {

+             DEBUG(1, ("child [%d] was terminated by signal [%d].\n", ret,

+                       WTERMSIG(child_ctx->child_status)));

+         } else {

+             if WIFSTOPPED(child_ctx->child_status) {

+                 DEBUG(7, ("child [%d] was stopped by signal [%d].\n", ret,

+                           WSTOPSIG(child_ctx->child_status)));

+             }

+             if WIFCONTINUED(child_ctx->child_status) {

+                 DEBUG(7, ("child [%d] was resumed by delivery of SIGCONT.\n",

+                           ret));

              }

+ 

+             return;

          }

  

-         --count;

-     } while (count < 0);

+         /* Invoke the callback in a tevent_immediate handler

+          * so that it is safe to free the tevent_signal *

+          */

+         imm = tevent_create_immediate(ev);

+         if (imm == NULL) {

+             DEBUG(0, ("Out of memory invoking sig handler callback\n"));

+             return;

+         }

+ 

+         tevent_schedule_immediate(imm, ev,child_invoke_callback,

+                                   child_ctx);

+     }

  

      return;

  }

  

+ static void child_invoke_callback(struct tevent_context *ev,

+                                   struct tevent_immediate *imm,

+                                   void *pvt)

+ {

+     struct sss_child_ctx *child_ctx =

+             talloc_get_type(pvt, struct sss_child_ctx);

+     if (child_ctx->cb) {

+         child_ctx->cb(child_ctx->child_status, child_ctx->sige, child_ctx->pvt);

+     }

+ 

+     /* Stop monitoring for this child */

+     talloc_free(child_ctx);

+ }

+ 

  static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,

                                    int child_debug_fd,

                                    const char *binary,

@@ -45,6 +45,18 @@

      size_t size;

  };

  

+ /* Callback to be invoked when a sigchld handler is called.

+  * The tevent_signal * associated with the handler will be

+  * freed automatically when this function returns.

+  */

+ typedef void (*sss_child_callback_t)(int child_status,

+                                      struct tevent_signal *sige,

+                                      void *pvt);

+ 

+ /* Set up child termination signal handler */

+ int child_handler_setup(struct tevent_context *ev, int pid,

+                         sss_child_callback_t cb, void *pvt);

+ 

  /* Async communication with the child process via a pipe */

  struct tevent_req *write_pipe_send(TALLOC_CTX *mem_ctx,

                                     struct tevent_context *ev,

file modified
+14 -2
@@ -22,10 +22,16 @@

  #ifndef __DATA_PROVIDER_H__

  #define __DATA_PROVIDER_H__

  

+ #include "config.h"

+ 

  #include <stdint.h>

  #include <sys/un.h>

  #include <errno.h>

  #include <stdbool.h>

+ #ifdef USE_KEYRING

+ #include <sys/types.h>

+ #include <keyutils.h>

+ #endif

  #include "talloc.h"

  #include "tevent.h"

  #include "ldb.h"
@@ -178,17 +184,22 @@

      bool offline_auth;

      bool last_auth_saved;

      int priv;

+ #ifdef USE_KEYRING

+     key_serial_t key_serial;

+ #endif

  };

  

  /* from dp_auth_util.c */

+ errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd,

+                       struct pam_data **new_pd);

  void pam_print_data(int l, struct pam_data *pd);

  int pam_add_response(struct pam_data *pd,

                       enum response_type type,

                       int len, const uint8_t *data);

  

  bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd);

- bool dp_unpack_pam_request(DBusMessage *msg, struct pam_data *pd,

-                            DBusError *dbus_error);

+ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx,

+                            struct pam_data **new_pd, DBusError *dbus_error);

  

  bool dp_pack_pam_response(DBusMessage *msg, struct pam_data *pd);

  bool dp_unpack_pam_response(DBusMessage *msg, struct pam_data *pd,
@@ -196,6 +207,7 @@

  

  int dp_common_send_id(struct sbus_connection *conn, uint16_t version,

                        const char *name);

+ void dp_id_callback(DBusPendingCall *pending, void *ptr);

  

  /* from dp_sbus.c */

  int dp_get_sbus_address(TALLOC_CTX *mem_ctx,

@@ -95,7 +95,7 @@

  

  static struct bet_data bet_data[] = {

      {BET_NULL, NULL, NULL},

-     {BET_ID, CONFDB_DOMAIN_ID_PROVIDER, "sssm_%s_init"},

+     {BET_ID, CONFDB_DOMAIN_ID_PROVIDER, "sssm_%s_id_init"},

      {BET_AUTH, CONFDB_DOMAIN_AUTH_PROVIDER, "sssm_%s_auth_init"},

      {BET_ACCESS, CONFDB_DOMAIN_ACCESS_PROVIDER, "sssm_%s_access_init"},

      {BET_CHPASS, CONFDB_DOMAIN_CHPASS_PROVIDER, "sssm_%s_chpass_init"},
@@ -166,6 +166,8 @@

  

      ctx->offstat.went_offline = time(NULL);

      ctx->offstat.offline = true;

+     ctx->run_online_cb = true;

+     be_run_offline_cb(ctx);

  }

  

  static int be_check_online(DBusMessage *message, struct sbus_connection *conn)
@@ -405,7 +407,7 @@

      }

  

      /* process request */

-     be_req = talloc(becli, struct be_req);

+     be_req = talloc_zero(becli, struct be_req);

      if (!be_req) {

          err_maj = DP_ERR_FATAL;

          err_min = ENOMEM;
@@ -479,7 +481,7 @@

  

      DEBUG(4, ("Backend returned: (%d, %d, %s) [%s]\n",

                dp_err_type, errnum, errstr?errstr:"<NULL>",

-               dp_err_to_string(req, dp_err_type, 0)));

+               dp_err_to_string(req, dp_err_type, errnum)));

  

      pd = talloc_get_type(req->req_data, struct pam_data);

  
@@ -526,7 +528,8 @@

      be_req = talloc_zero(becli, struct be_req);

      if (!be_req) {

          DEBUG(7, ("talloc_zero failed.\n"));

-         goto done;

+         dbus_message_unref(reply);

+         return ENOMEM;

      }

  

      be_req->becli = becli;
@@ -534,10 +537,13 @@

      be_req->fn = be_pam_handler_callback;

      be_req->pvt = reply;

  

-     pd = talloc_zero(be_req, struct pam_data);

-     if (!pd) {

+     dbus_error_init(&dbus_error);

+ 

+     ret = dp_unpack_pam_request(message, be_req, &pd, &dbus_error);

+     if (!ret) {

+         DEBUG(1,("Failed, to parse message!\n"));

          talloc_free(be_req);

-         return ENOMEM;

+         return EIO;

      }

  

      pd->pam_status = PAM_SYSTEM_ERR;
@@ -547,14 +553,6 @@

          return ENOMEM;

      }

  

-     dbus_error_init(&dbus_error);

- 

-     ret = dp_unpack_pam_request(message, pd, &dbus_error);

-     if (!ret) {

-         DEBUG(1,("Failed, to parse message!\n"));

-         talloc_free(be_req);

-         return EIO;

-     }

  

      DEBUG(4, ("Got request with the following data\n"));

      DEBUG_PAM_DATA(4, pd);

@@ -0,0 +1,206 @@

+ /*

+     SSSD

+ 

+     Data Provider Process - Callback

+ 

+     Authors:

+ 

+         Stephen Gallagher <sgallagh@redhat.com>

+         Sumit Bose <sbose@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include "util/util.h"

+ #include "providers/dp_backend.h"

+ 

+ struct be_cb {

+     struct be_cb *prev;

+     struct be_cb *next;

+ 

+     be_callback_t cb;

+     void *pvt;

+ 

+     struct be_cb *list;

+     struct be_ctx *be;

+ };

+ 

+ struct be_cb_ctx {

+     struct be_ctx *be;

+     struct be_cb *callback;

+ };

+ 

+ static int cb_destructor(TALLOC_CTX *ptr)

+ {

+     struct be_cb *cb = talloc_get_type(ptr, struct be_cb);

+     DLIST_REMOVE(cb->list, cb);

+     return 0;

+ }

+ 

+ static int be_add_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,

+                      be_callback_t cb, void *pvt, struct be_cb **cb_list,

+                      struct be_cb **return_cb)

+ {

+     struct be_cb *new_cb;

+ 

+     if (!ctx || !cb) {

+         return EINVAL;

+     }

+ 

+     new_cb = talloc(mem_ctx, struct be_cb);

+     if (!new_cb) {

+         return ENOMEM;

+     }

+ 

+     new_cb->cb = cb;

+     new_cb->pvt = pvt;

+     new_cb->list = *cb_list;

+     new_cb->be = ctx;

+ 

+     DLIST_ADD(*cb_list, new_cb);

+ 

+     talloc_set_destructor((TALLOC_CTX *) new_cb, cb_destructor);

+ 

+     if (return_cb) {

+         *return_cb = new_cb;

+     }

+ 

+     return EOK;

+ }

+ 

+ static void be_run_cb_step(struct tevent_context *ev, struct tevent_timer *te,

+                            struct timeval current_time, void *pvt)

+ {

+     struct be_cb_ctx *cb_ctx = talloc_get_type(pvt, struct be_cb_ctx);

+     struct tevent_timer *tev;

+     struct timeval soon;

+ 

+     /* Call the callback */

+     cb_ctx->callback->cb(cb_ctx->callback->pvt);

+ 

+     if (cb_ctx->callback->next) {

+         cb_ctx->callback = cb_ctx->callback->next;

+ 

+         /* Delay 30ms so we don't block any other events */

+         soon = tevent_timeval_current_ofs(0, 30000);

+         tev = tevent_add_timer(cb_ctx->be->ev, cb_ctx, soon,

+                                be_run_cb_step,

+                                cb_ctx);

+         if (!tev) {

+             DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));

+             goto final;

+         }

+         return;

+     }

+ 

+ final:

+     /* Steal the timer event onto the be_ctx so it doesn't

+      * get freed with the cb_ctx

+      */

+     talloc_steal(cb_ctx->be, te);

+     talloc_free(cb_ctx);

+ }

+ 

+ static errno_t be_run_cb(struct be_ctx *be, struct be_cb *cb_list) {

+     struct timeval soon;

+     struct tevent_timer *te;

+     struct be_cb_ctx *cb_ctx;

+ 

+     cb_ctx = talloc(be, struct be_cb_ctx);

+     if (!cb_ctx) {

+         DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));

+         return ENOMEM;

+     }

+     cb_ctx->be = be;

+     cb_ctx->callback = cb_list;

+ 

+     /* Delay 30ms so we don't block any other events */

+     soon = tevent_timeval_current_ofs(0, 30000);

+     te = tevent_add_timer(be->ev, cb_ctx, soon,

+                           be_run_cb_step,

+                           cb_ctx);

+     if (!te) {

+         DEBUG(0, ("Out of memory. Could not invoke callbacks\n"));

+         talloc_free(cb_ctx);

+         return ENOMEM;

+     }

+ 

+     return EOK;

+ }

+ 

+ int be_add_online_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,

+                      void *pvt, struct be_cb **online_cb)

+ {

+     int ret;

+ 

+     ret = be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->online_cb_list, online_cb);

+     if (ret != EOK) {

+         DEBUG(1, ("be_add_cb failed.\n"));

+         return ret;

+     }

+ 

+     /* Make sure we run the callback for the first

+      * connection after startup.

+      */

+     ctx->run_online_cb = true;

+ 

+     return EOK;

+ }

+ 

+ void be_run_online_cb(struct be_ctx *be) {

+     int ret;

+ 

+     if (be->run_online_cb) {

+         /* Reset the flag. We only want to run these

+          * callbacks when transitioning to online

+          */

+         be->run_online_cb = false;

+ 

+         if (be->online_cb_list) {

+             DEBUG(3, ("Going online. Running callbacks.\n"));

+ 

+             ret = be_run_cb(be, be->online_cb_list);

+             if (ret != EOK) {

+                 DEBUG(1, ("be_run_cb failed.\n"));

+             }

+ 

+         } else {

+             DEBUG(9, ("Online call back list is empty, nothing to do.\n"));

+         }

+     }

+ }

+ 

+ int be_add_offline_cb(TALLOC_CTX *mem_ctx, struct be_ctx *ctx, be_callback_t cb,

+                       void *pvt, struct be_cb **offline_cb)

+ {

+     return be_add_cb(mem_ctx, ctx, cb, pvt, &ctx->offline_cb_list, offline_cb);

+ }

+ 

+ void be_run_offline_cb(struct be_ctx *be) {

+     int ret;

+ 

+     if (be->offline_cb_list) {

+         DEBUG(3, ("Going offline. Running callbacks.\n"));

+ 

+         ret = be_run_cb(be, be->offline_cb_list);

+         if (ret != EOK) {

+             DEBUG(1, ("be_run_cb failed.\n"));

+         }

+ 

+     } else {

+         DEBUG(9, ("Offline call back list is empty, nothing to do.\n"));

+     }

+ }

@@ -42,6 +42,7 @@

      struct fo_service *fo_service;

  

      struct fo_server *last_good_srv;

+     bool run_callbacks;

  

      struct be_svc_callback *callbacks;

  };
@@ -53,6 +54,11 @@

      struct be_svc_data *svcs;

  };

  

+ int be_fo_is_srv_identifier(const char *server)

+ {

+     return server && strcasecmp(server, BE_SRV_IDENTIFIER) == 0;

+ }

+ 

  static int be_fo_get_options(TALLOC_CTX *mem_ctx, struct be_ctx *ctx,

                               struct fo_options *opts)

  {
@@ -61,6 +67,7 @@

  

      /* todo get timeout from configuration */

      opts->retry_timeout = 30;

+     opts->srv_retry_timeout = 14400;

  

      ret = confdb_get_string(ctx->cdb, mem_ctx, ctx->conf_path,

                              CONFDB_DOMAIN_FAMILY_ORDER,
@@ -93,6 +100,7 @@

  int be_init_failover(struct be_ctx *ctx)

  {

      int ret;

+     int fo_timeout;

      struct fo_options fopts;

  

      if (ctx->be_fo != NULL) {
@@ -104,7 +112,14 @@

          return ENOMEM;

      }

  

-     ret = resolv_init(ctx, ctx->ev, 5, &ctx->be_fo->resolv);

+     ret = confdb_get_int(ctx->cdb, ctx, ctx->conf_path,

+                          CONFDB_DOMAIN_RESOLV_TIMEOUT,

+                          5, &fo_timeout);

+     if (ret != EOK) {

+         return ret;

+     }

+ 

+     ret = resolv_init(ctx, ctx->ev, fo_timeout, &ctx->be_fo->resolv);

      if (ret != EOK) {

          talloc_zfree(ctx->be_fo);

          return ret;
@@ -226,6 +241,32 @@

      return EOK;

  }

  

+ int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name,

+                          const char *query_service, const char *proto,

+                          const char *domain, void *user_data)

+ {

+     struct be_svc_data *svc;

+     int ret;

+ 

+     DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {

+         if (strcmp(svc->name, service_name) == 0) {

+             break;

+         }

+     }

+     if (NULL == svc) {

+         return ENOENT;

+     }

+ 

+     ret = fo_add_srv_server(svc->fo_service, query_service,

+                             domain, proto, user_data);

+     if (ret && ret != EEXIST) {

+         DEBUG(1, ("Failed to add SRV lookup reference to failover service\n"));

+         return ret;

+     }

+ 

+     return EOK;

+ }

+ 

  int be_fo_add_server(struct be_ctx *ctx, const char *service_name,

                       const char *server, int port, void *user_data)

  {
@@ -374,9 +415,11 @@

                    fo_get_server_name(state->srv), ipaddr));

      }

  

-     /* now call all svc callbacks if server changed */

-     if (state->srv != state->svc->last_good_srv) {

+     /* now call all svc callbacks if server changed or if it is explicitly

+      * requested */

+     if (state->srv != state->svc->last_good_srv || state->svc->run_callbacks) {

          state->svc->last_good_srv = state->srv;

+         state->svc->run_callbacks = false;

  

          DLIST_FOR_EACH(callback, state->svc->callbacks) {

              callback->fn(callback->private_data, state->srv);
@@ -400,3 +443,21 @@

      return EOK;

  }

  

+ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,

+                                         const char *service_name)

+ {

+     struct be_svc_data *svc;

+ 

+     DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {

+         if (strcmp(svc->name, service_name) == 0) {

+             break;

+         }

+     }

+     if (NULL == svc) {

+         return ENOENT;

+     }

+ 

+     svc->run_callbacks = true;

+ 

+     return EOK;

+ }

file modified
+69 -78
@@ -21,44 +21,9 @@

  

  #include "data_provider.h"

  

- void pam_print_data(int l, struct pam_data *pd)

- {

-     DEBUG(l, ("command: %d\n", pd->cmd));

-     DEBUG(l, ("domain: %s\n", pd->domain));

-     DEBUG(l, ("user: %s\n", pd->user));

-     DEBUG(l, ("service: %s\n", pd->service));

-     DEBUG(l, ("tty: %s\n", pd->tty));

-     DEBUG(l, ("ruser: %s\n", pd->ruser));

-     DEBUG(l, ("rhost: %s\n", pd->rhost));

-     DEBUG(l, ("authtok type: %d\n", pd->authtok_type));

-     DEBUG(l, ("authtok size: %d\n", pd->authtok_size));

-     DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type));

-     DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size));

-     DEBUG(l, ("priv: %d\n", pd->priv));

-     DEBUG(l, ("cli_pid: %d\n", pd->cli_pid));

- }

- 

- int pam_add_response(struct pam_data *pd, enum response_type type,

-                      int len, const uint8_t *data)

- {

-     struct response_data *new;

- 

-     new = talloc(pd, struct response_data);

-     if (new == NULL) return ENOMEM;

- 

-     new->type = type;

-     new->len = len;

-     new->data = talloc_memdup(pd, data, len);

-     if (new->data == NULL) return ENOMEM;

-     new->next = pd->resp_list;

-     pd->resp_list = new;

- 

-     return EOK;

- }

- 

  bool dp_pack_pam_request(DBusMessage *msg, struct pam_data *pd)

  {

-     int ret;

+     dbus_bool_t db_ret;

  

      if (pd->user == NULL) return false;

      if (pd->service == NULL) pd->service = talloc_strdup(pd, "");
@@ -67,52 +32,78 @@

      if (pd->rhost == NULL) pd->rhost = talloc_strdup(pd, "");

  

  

-     ret = dbus_message_append_args(msg,

-                                    DBUS_TYPE_INT32,  &(pd->cmd),

-                                    DBUS_TYPE_STRING, &(pd->user),

-                                    DBUS_TYPE_STRING, &(pd->service),

-                                    DBUS_TYPE_STRING, &(pd->tty),

-                                    DBUS_TYPE_STRING, &(pd->ruser),

-                                    DBUS_TYPE_STRING, &(pd->rhost),

-                                    DBUS_TYPE_UINT32, &(pd->authtok_type),

+     db_ret = dbus_message_append_args(msg,

+                                       DBUS_TYPE_INT32,  &(pd->cmd),

+                                       DBUS_TYPE_STRING, &(pd->user),

+                                       DBUS_TYPE_STRING, &(pd->service),

+                                       DBUS_TYPE_STRING, &(pd->tty),

+                                       DBUS_TYPE_STRING, &(pd->ruser),

+                                       DBUS_TYPE_STRING, &(pd->rhost),

+                                       DBUS_TYPE_UINT32, &(pd->authtok_type),

+                                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,

+                                           &(pd->authtok),

+                                           (pd->authtok_size),

+                                       DBUS_TYPE_UINT32, &(pd->newauthtok_type),

+                                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,

+                                           &(pd->newauthtok),

+                                           pd->newauthtok_size,

+                                       DBUS_TYPE_INT32, &(pd->priv),

+                                       DBUS_TYPE_UINT32, &(pd->cli_pid),

+                                       DBUS_TYPE_INVALID);

+ 

+     return db_ret;

+ }

+ 

+ bool dp_unpack_pam_request(DBusMessage *msg, TALLOC_CTX *mem_ctx,

+                            struct pam_data **new_pd, DBusError *dbus_error)

+ {

+     dbus_bool_t db_ret;

+     int ret;

+     struct pam_data pd;

+ 

+     memset(&pd, 0, sizeof(pd));

+ 

+     db_ret = dbus_message_get_args(msg, dbus_error,

+                                    DBUS_TYPE_INT32,  &(pd.cmd),

+                                    DBUS_TYPE_STRING, &(pd.user),

+                                    DBUS_TYPE_STRING, &(pd.service),

+                                    DBUS_TYPE_STRING, &(pd.tty),

+                                    DBUS_TYPE_STRING, &(pd.ruser),

+                                    DBUS_TYPE_STRING, &(pd.rhost),

+                                    DBUS_TYPE_UINT32, &(pd.authtok_type),

                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,

-                                        &(pd->authtok),

-                                        (pd->authtok_size),

-                                    DBUS_TYPE_UINT32, &(pd->newauthtok_type),

+                                        &(pd.authtok),

+                                        &(pd.authtok_size),

+                                    DBUS_TYPE_UINT32, &(pd.newauthtok_type),

                                     DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,

-                                        &(pd->newauthtok),

-                                        pd->newauthtok_size,

-                                    DBUS_TYPE_INT32, &(pd->priv),

-                                    DBUS_TYPE_UINT32, &(pd->cli_pid),

+                                        &(pd.newauthtok),

+                                        &(pd.newauthtok_size),

+                                    DBUS_TYPE_INT32, &(pd.priv),

+                                    DBUS_TYPE_UINT32, &(pd.cli_pid),

                                     DBUS_TYPE_INVALID);

  

-     return ret;

- }

+     if (!db_ret) {

+         DEBUG(1, ("dbus_message_get_args failed.\n"));

+         return false;

+     }

  

- bool dp_unpack_pam_request(DBusMessage *msg, struct pam_data *pd, DBusError *dbus_error)

- {

-     int ret;

+     ret = copy_pam_data(mem_ctx, &pd, new_pd);

+     if (ret != EOK) {

+         DEBUG(1, ("copy_pam_data failed.\n"));

+         return false;

+     }

+ 

+     if (pd.authtok_size != 0 && pd.authtok != NULL) {

+         memset(pd.authtok, 0, pd.authtok_size);

+         pd.authtok_size = 0;

+     }

  

-     ret = dbus_message_get_args(msg, dbus_error,

-                                 DBUS_TYPE_INT32,  &(pd->cmd),

-                                 DBUS_TYPE_STRING, &(pd->user),

-                                 DBUS_TYPE_STRING, &(pd->service),

-                                 DBUS_TYPE_STRING, &(pd->tty),

-                                 DBUS_TYPE_STRING, &(pd->ruser),

-                                 DBUS_TYPE_STRING, &(pd->rhost),

-                                 DBUS_TYPE_UINT32, &(pd->authtok_type),

-                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,

-                                     &(pd->authtok),

-                                     &(pd->authtok_size),

-                                 DBUS_TYPE_UINT32, &(pd->newauthtok_type),

-                                 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,

-                                     &(pd->newauthtok),

-                                     &(pd->newauthtok_size),

-                                 DBUS_TYPE_INT32, &(pd->priv),

-                                 DBUS_TYPE_UINT32, &(pd->cli_pid),

-                                 DBUS_TYPE_INVALID);

- 

-     return ret;

+     if (pd.newauthtok_size != 0 && pd.newauthtok != NULL) {

+         memset(pd.newauthtok, 0, pd.newauthtok_size);

+         pd.newauthtok_size = 0;

+     }

+ 

+     return true;

  }

  

  bool dp_pack_pam_response(DBusMessage *msg, struct pam_data *pd)
@@ -271,7 +262,7 @@

      return true;

  }

  

- static void id_callback(DBusPendingCall *pending, void *ptr)

+ void dp_id_callback(DBusPendingCall *pending, void *ptr)

  {

      DBusMessage *reply;

      DBusError dbus_error;
@@ -362,7 +353,7 @@

          return EIO;

      }

  

-     retval = sbus_conn_send(conn, msg, 30000, id_callback, NULL, NULL);

+     retval = sbus_conn_send(conn, msg, 30000, dp_id_callback, NULL, NULL);

  

      dbus_message_unref(msg);

      return retval;

@@ -26,6 +26,11 @@

  #include "providers/fail_over.h"

  #include "db/sysdb.h"

  

+ /* a special token, if used in place of the hostname, denotes that real

+  * hostnames should be looked up from DNS using SRV requests

+  */

+ #define BE_SRV_IDENTIFIER  "_srv_"

+ 

  struct be_ctx;

  struct bet_ops;

  struct be_req;
@@ -35,6 +40,8 @@

  typedef void (*be_req_fn_t)(struct be_req *);

  typedef void (*be_async_callback_t)(struct be_req *, int, int, const char *);

  

+ typedef void (*be_callback_t)(void *);

+ 

  enum bet_type {

      BET_NULL = 0,

      BET_ID,
@@ -76,6 +83,8 @@

  

  struct be_failover_ctx;

  

+ struct be_cb;

+ 

  struct be_ctx {

      struct tevent_context *ev;

      struct confdb_ctx *cdb;
@@ -85,6 +94,13 @@

      const char *conf_path;

      struct be_failover_ctx *be_fo;

  

+     /* Functions to be invoked when the

+      * backend goes online or offline

+      */

+     struct be_cb *online_cb_list;

+     bool run_online_cb;

+     struct be_cb *offline_cb_list;

+ 

      struct be_offline_status offstat;

  

      struct sbus_connection *mon_conn;
@@ -103,6 +119,8 @@

      be_req_fn_t finalize;

  };

  

+ #define MAX_BE_REQ_RESTARTS 2

+ 

  struct be_req {

      struct be_client *becli;

      struct be_ctx *be_ctx;
@@ -110,6 +128,8 @@

  

      be_async_callback_t fn;

      void *pvt;

+ 

+     int restarts;

  };

  

  struct be_acct_req {
@@ -122,14 +142,32 @@

  bool be_is_offline(struct be_ctx *ctx);

  void be_mark_offline(struct be_ctx *ctx);

  

+ int be_add_online_cb(TALLOC_CTX *mem_ctx,

+                      struct be_ctx *ctx,

+                      be_callback_t cb,

+                      void *pvt,

+                      struct be_cb **online_cb);

+ void be_run_online_cb(struct be_ctx *be);

+ 

+ int be_add_offline_cb(TALLOC_CTX *mem_ctx,

+                      struct be_ctx *ctx,

+                      be_callback_t cb,

+                      void *pvt,

+                      struct be_cb **online_cb);

+ void be_run_offline_cb(struct be_ctx *be);

+ 

  /* from data_provider_fo.c */

  typedef void (be_svc_callback_fn_t)(void *, struct fo_server *);

  

  int be_init_failover(struct be_ctx *ctx);

+ int be_fo_is_srv_identifier(const char *server);

  int be_fo_add_service(struct be_ctx *ctx, const char *service_name);

  int be_fo_service_add_callback(TALLOC_CTX *memctx,

                                 struct be_ctx *ctx, const char *service_name,

                                 be_svc_callback_fn_t *fn, void *private_data);

+ int be_fo_add_srv_server(struct be_ctx *ctx, const char *service_name,

+                          const char *query_service, const char *proto,

+                          const char *domain, void *user_data);

  int be_fo_add_server(struct be_ctx *ctx, const char *service_name,

                       const char *server, int port, void *user_data);

  
@@ -139,4 +177,6 @@

                                            const char *service_name);

  int be_resolve_server_recv(struct tevent_req *req, struct fo_server **srv);

  

+ int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,

+                                         const char *service_name);

  #endif /* __DP_BACKEND_H___ */

@@ -0,0 +1,169 @@

+ /*

+     SSSD

+ 

+     Utilities to for tha pam_data structure

+ 

+     Authors:

+         Sumit Bose <sbose@redhat.com>

+ 

+     Copyright (C) 2009 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include "providers/data_provider.h"

+ 

+ #define PD_STR_COPY(el) do { \

+     if (old_pd->el != NULL) { \

+         pd->el = talloc_strdup(pd, old_pd->el); \

+         if (pd->el == NULL) { \

+             DEBUG(1, ("talloc_strdup failed.\n")); \

+             goto failed; \

+         } \

+     } \

+ } while(0);

+ 

+ #define PD_MEM_COPY(el, size) do { \

+     if (old_pd->el != NULL) { \

+         pd->el = talloc_memdup(pd, old_pd->el, (size)); \

+         if (pd->el == NULL) { \

+             DEBUG(1, ("talloc_memdup failed.\n")); \

+             goto failed; \

+         } \

+     } \

+ } while(0);

+ 

+ int pam_data_destructor(void *ptr)

+ {

+     struct pam_data *pd = talloc_get_type(ptr, struct pam_data);

+ 

+     if (pd->authtok_size != 0 && pd->authtok != NULL) {

+         memset(pd->authtok, 0, pd->authtok_size);

+         pd->authtok_size = 0;

+     }

+ 

+     if (pd->newauthtok_size != 0 && pd->newauthtok != NULL) {

+         memset(pd->newauthtok, 0, pd->newauthtok_size);

+         pd->newauthtok_size = 0;

+     }

+ 

+     return EOK;

+ }

+ 

+ struct pam_data *create_pam_data(TALLOC_CTX *mem_ctx)

+ {

+     struct pam_data *pd;

+ 

+     pd = talloc_zero(mem_ctx, struct pam_data);

+     if (pd == NULL) {

+         DEBUG(1, ("talloc_zero failed.\n"));

+         return NULL;

+     }

+ 

+     talloc_set_destructor((TALLOC_CTX *) pd, pam_data_destructor);

+ 

+     return pd;

+ }

+ 

+ errno_t copy_pam_data(TALLOC_CTX *mem_ctx, struct pam_data *old_pd,

+                       struct pam_data **new_pd)

+ {

+     struct pam_data *pd = NULL;

+ 

+     pd = create_pam_data(mem_ctx);

+     if (pd == NULL) {

+         DEBUG(1, ("create_pam_data failed.\n"));

+         return ENOMEM;

+     }

+ 

+     pd->cmd  = old_pd->cmd;

+     pd->authtok_type = old_pd->authtok_type;

+     pd->authtok_size = old_pd->authtok_size;

+     pd->newauthtok_type = old_pd->newauthtok_type;

+     pd->newauthtok_size = old_pd->newauthtok_size;

+ 

+     PD_STR_COPY(domain);

+     PD_STR_COPY(user);

+     PD_STR_COPY(service);

+     PD_STR_COPY(tty);

+     PD_STR_COPY(ruser);

+     PD_STR_COPY(rhost);

+     PD_MEM_COPY(authtok, old_pd->authtok_size);

+     PD_MEM_COPY(newauthtok, old_pd->newauthtok_size);

+     pd->cli_pid = old_pd->cli_pid;

+ 

+     *new_pd = pd;

+ 

+     return EOK;

+ 

+ failed:

+     talloc_free(pd);

+     return ENOMEM;

+ }

+ 

+ static const char *pamcmd2str(int cmd) {

+     switch (cmd) {

+     case SSS_PAM_AUTHENTICATE:

+         return "PAM_AUTHENTICATE";

+     case SSS_PAM_SETCRED:

+         return "PAM_SETCRED";

+     case SSS_PAM_ACCT_MGMT:

+         return "PAM_ACCT_MGMT";

+     case SSS_PAM_OPEN_SESSION:

+         return "PAM_OPEN_SESSION";

+     case SSS_PAM_CLOSE_SESSION:

+         return "PAM_CLOSE_SESSION";

+     case SSS_PAM_CHAUTHTOK:

+         return "PAM_CHAUTHTOK";

+     case SSS_PAM_CHAUTHTOK_PRELIM:

+         return "PAM_CHAUTHTOK_PRELIM";

+     default:

+         return "UNKNOWN";

+     }

+ }

+ 

+ void pam_print_data(int l, struct pam_data *pd)

+ {

+     DEBUG(l, ("command: %s\n", pamcmd2str(pd->cmd)));

+     DEBUG(l, ("domain: %s\n", pd->domain));

+     DEBUG(l, ("user: %s\n", pd->user));

+     DEBUG(l, ("service: %s\n", pd->service));

+     DEBUG(l, ("tty: %s\n", pd->tty));

+     DEBUG(l, ("ruser: %s\n", pd->ruser));

+     DEBUG(l, ("rhost: %s\n", pd->rhost));

+     DEBUG(l, ("authtok type: %d\n", pd->authtok_type));

+     DEBUG(l, ("authtok size: %d\n", pd->authtok_size));

+     DEBUG(l, ("newauthtok type: %d\n", pd->newauthtok_type));

+     DEBUG(l, ("newauthtok size: %d\n", pd->newauthtok_size));

+     DEBUG(l, ("priv: %d\n", pd->priv));

+     DEBUG(l, ("cli_pid: %d\n", pd->cli_pid));

+ }

+ 

+ int pam_add_response(struct pam_data *pd, enum response_type type,

+                      int len, const uint8_t *data)

+ {

+     struct response_data *new;

+ 

+     new = talloc(pd, struct response_data);

+     if (new == NULL) return ENOMEM;

+ 

+     new->type = type;

+     new->len = len;

+     new->data = talloc_memdup(pd, data, len);

+     if (new->data == NULL) return ENOMEM;

+     new->next = pd->resp_list;

+     pd->resp_list = new;

+ 

+     return EOK;

+ }

file modified
+539 -54
@@ -5,8 +5,9 @@

  

     Authors:

          Martin Nagy <mnagy@redhat.com>

+         Jakub Hrozek <jhrozek@redhat.com>

  

-    Copyright (C) Red Hat, Inc 2009

+    Copyright (C) Red Hat, Inc 2010

  

     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
@@ -40,6 +41,14 @@

  

  #define DEFAULT_PORT_STATUS PORT_NEUTRAL

  #define DEFAULT_SERVER_STATUS SERVER_NAME_NOT_RESOLVED

+ #define DEFAULT_SRV_STATUS SRV_NEUTRAL

+ 

+ enum srv_lookup_status {

+     SRV_NEUTRAL,        /* We didn't try this SRV lookup yet */

+     SRV_RESOLVED,       /* This SRV lookup is resolved       */

+     SRV_NOT_RESOLVED,   /* Could not resolve this SRV lookup */

+     SRV_EXPIRED         /* Need to refresh the SRV query     */

+ };

  

  struct fo_ctx {

      struct fo_service *service_list;
@@ -66,6 +75,7 @@

      void *user_data;

      int port;

      int port_status;

+     struct srv_data *srv_data;

      struct fo_service *service;

      struct timeval last_status_change;

      struct server_common *common;
@@ -74,6 +84,8 @@

  struct server_common {

      REFCOUNT_COMMON;

  

+     struct fo_ctx *ctx;

+ 

      struct server_common *prev;

      struct server_common *next;

  
@@ -84,6 +96,17 @@

      struct timeval last_status_change;

  };

  

+ struct srv_data {

+     char *domain;

+     char *proto;

+     char *srv;

+ 

+     struct fo_server *meta;

+ 

+     int srv_lookup_status;

+     struct timeval last_status_change;

+ };

+ 

  struct resolve_service_request {

      struct resolve_service_request *prev;

      struct resolve_service_request *next;
@@ -113,6 +136,7 @@

          return NULL;

      }

  

+     ctx->opts->srv_retry_timeout = opts->srv_retry_timeout;

      ctx->opts->retry_timeout = opts->retry_timeout;

      ctx->opts->family_order  = opts->family_order;

  
@@ -137,6 +161,23 @@

  }

  

  static const char *

+ str_srv_data_status(enum srv_lookup_status status)

+ {

+     switch (status) {

+     case SRV_NEUTRAL:

+         return "neutral";

+     case SRV_RESOLVED:

+         return "resolved";

+     case SRV_NOT_RESOLVED:

+         return "not resolved";

+     case SRV_EXPIRED:

+         return "expired";

+     }

+ 

+     return "unknown SRV lookup status";

+ }

+ 

+ static const char *

  str_server_status(enum server_status status)

  {

      switch (status) {
@@ -155,6 +196,105 @@

      return "unknown server status";

  }

  

+ int fo_is_srv_lookup(struct fo_server *s)

+ {

+     return s && s->srv_data;

+ }

+ 

+ static char *

+ get_srv_query(TALLOC_CTX *mem_ctx, struct fo_server *server)

+ {

+     char *query;

+ 

+     if (!fo_is_srv_lookup(server)) {

+         return NULL;

+     }

+ 

+     query = talloc_asprintf(mem_ctx, "_%s._%s.%s", server->srv_data->srv,

+                                                    server->srv_data->proto,

+                                                    server->srv_data->domain);

+     return query;

+ }

+ 

+ static struct fo_server *

+ collapse_srv_lookup(struct fo_server *server)

+ {

+     struct fo_server *tmp, *meta;

+ 

+     meta = server->srv_data->meta;

+     DEBUG(4, ("Need to refresh SRV lookup for domain %s\n", meta->srv_data->domain))

+ 

+     if (server != meta) {

+         while (server->prev && server->prev->srv_data == meta->srv_data) {

+             tmp = server->prev;

+             DLIST_REMOVE(server->service->server_list, tmp);

+             talloc_zfree(tmp);

+         }

+         while (server->next && server->next->srv_data == meta->srv_data) {

+             tmp = server->next;

+             DLIST_REMOVE(server->service->server_list, tmp);

+             talloc_zfree(tmp);

+         }

+ 

+         if (server == server->service->active_server) {

+             server->service->active_server = NULL;

+         }

+         if (server == server->service->last_tried_server) {

+             server->service->last_tried_server = meta;

+         }

+ 

+         /* add back the meta server to denote SRV lookup */

+         DLIST_ADD_AFTER(server->service->server_list, meta, server);

+         DLIST_REMOVE(server->service->server_list, server);

+         talloc_zfree(server);

+     }

+ 

+     meta->srv_data->srv_lookup_status = SRV_NEUTRAL;

+     meta->srv_data->last_status_change.tv_sec = 0;

+ 

+     return meta;

+ }

+ 

+ static enum srv_lookup_status

+ get_srv_data_status(struct srv_data *data)

+ {

+     struct timeval tv;

+     time_t timeout;

+ 

+     timeout = data->meta->service->ctx->opts->srv_retry_timeout;

+     gettimeofday(&tv, NULL);

+ 

+     if (timeout && STATUS_DIFF(data, tv) > timeout) {

+         switch(data->srv_lookup_status) {

+         case SRV_EXPIRED:

+         case SRV_NEUTRAL:

+             break;

+         case SRV_RESOLVED:

+             data->srv_lookup_status = SRV_EXPIRED;

+             data->last_status_change.tv_sec = 0;

+             break;

+         case SRV_NOT_RESOLVED:

+             data->srv_lookup_status = SRV_NEUTRAL;

+             data->last_status_change.tv_sec = 0;

+             break;

+         default:

+             DEBUG(1, ("Unknown state for SRV server!\n"));

+         }

+     }

+ 

+     return data->srv_lookup_status;

+ }

+ 

+ static void

+ set_srv_data_status(struct srv_data *data, enum srv_lookup_status status)

+ {

+     DEBUG(4, ("Marking SRV lookup of service '%s' as '%s'\n",

+               data->meta->service->name, str_srv_data_status(status)));

+ 

+     gettimeofday(&data->last_status_change, NULL);

+     data->srv_lookup_status = status;

+ }

+ 

  /*

   * This function will return the status of the server. If the status was

   * last updated a long time ago, we will first reset the status.
@@ -302,9 +442,9 @@

      struct server_common *common;

  

      DLIST_FOR_EACH(common, ctx->server_common_list) {

-         if (!strcmp(name, common->name)) {

+         if (!strcasecmp(name, common->name)) {

              *_common = rc_reference(mem_ctx, struct server_common, common);

-             if (_common == NULL)

+             if (*_common == NULL)

                  return ENOMEM;

              return EOK;

          }
@@ -313,6 +453,20 @@

      return ENOENT;

  }

  

+ static int server_common_destructor(void *memptr)

+ {

+     struct server_common *common;

+ 

+     common = talloc_get_type(memptr, struct server_common);

+     if (common->request_list) {

+         DEBUG(1, ("BUG: pending requests still associated with this server\n"));

+         return -1;

+     }

+     DLIST_REMOVE(common->ctx->server_common_list, common);

+ 

+     return 0;

+ }

+ 

  static struct server_common *

  create_server_common(TALLOC_CTX *mem_ctx, struct fo_ctx *ctx, const char *name)

  {
@@ -328,6 +482,7 @@

          return NULL;

      }

  

+     common->ctx = ctx;

      common->prev = NULL;

      common->next = NULL;

      common->hostent = NULL;
@@ -336,27 +491,29 @@

      common->last_status_change.tv_sec = 0;

      common->last_status_change.tv_usec = 0;

  

+     talloc_set_destructor((TALLOC_CTX *) common, server_common_destructor);

      DLIST_ADD_END(ctx->server_common_list, common, struct server_common *);

      return common;

  }

  

  int

- fo_add_server(struct fo_service *service, const char *name, int port,

-               void *user_data)

+ fo_add_srv_server(struct fo_service *service, const char *srv,

+                   const char *domain, const char *proto, void *user_data)

  {

      struct fo_server *server;

-     int ret;

  

-     DEBUG(3, ("Adding new server '%s', to service '%s'\n",

-               name ? name : "(no name)", service->name));

+     DEBUG(3, ("Adding new SRV server in domain '%s', to service '%s'\n",

+               domain, service->name));

+ 

      DLIST_FOR_EACH(server, service->server_list) {

-         if (server->port != port || server->user_data != user_data)

+         if (server->user_data != user_data)

              continue;

-         if (name == NULL && server->common == NULL) {

-             return EEXIST;

-         } else if (name != NULL && server->common != NULL) {

-             if (!strcmp(name, server->common->name))

+ 

+         if (fo_is_srv_lookup(server)) {

+             if (strcasecmp(server->srv_data->domain, domain) == 0 &&

+                 strcasecmp(server->srv_data->proto, proto) == 0) {

                  return EEXIST;

+             }

          }

      }

  
@@ -364,6 +521,42 @@

      if (server == NULL)

          return ENOMEM;

  

+     server->user_data = user_data;

+     server->service = service;

+     server->port_status = DEFAULT_PORT_STATUS;

+ 

+     /* add the SRV-specific data */

+     server->srv_data = talloc_zero(service, struct srv_data);

+     if (server->srv_data == NULL)

+         return ENOMEM;

+ 

+     server->srv_data->domain = talloc_strdup(server->srv_data, domain);

+     server->srv_data->proto = talloc_strdup(server->srv_data, proto);

+     server->srv_data->srv = talloc_strdup(server->srv_data, srv);

+     if (server->srv_data->domain == NULL ||

+         server->srv_data->proto == NULL ||

+         server->srv_data->srv == NULL)

+         return ENOMEM;

+ 

+     server->srv_data->meta = server;

+     server->srv_data->srv_lookup_status = DEFAULT_SRV_STATUS;

+     server->srv_data->last_status_change.tv_sec = 0;

+ 

+     DLIST_ADD_END(service->server_list, server, struct fo_server *);

+     return EOK;

+ }

+ 

+ static struct fo_server *

+ create_fo_server(struct fo_service *service, const char *name,

+                  int port, void *user_data)

+ {

+     struct fo_server *server;

+     int ret;

+ 

+     server = talloc_zero(service, struct fo_server);

+     if (server == NULL)

+         return NULL;

+ 

      server->port = port;

      server->user_data = user_data;

      server->service = service;
@@ -375,14 +568,41 @@

              server->common = create_server_common(server, service->ctx, name);

              if (server->common == NULL) {

                  talloc_free(server);

-                 return ENOMEM;

+                 return NULL;

              }

          } else if (ret != EOK) {

              talloc_free(server);

-             return ret;

+             return NULL;

+         }

+     }

+ 

+     return server;

+ }

+ 

+ int

+ fo_add_server(struct fo_service *service, const char *name, int port,

+               void *user_data)

+ {

+     struct fo_server *server;

+ 

+     DEBUG(3, ("Adding new server '%s', to service '%s'\n",

+               name ? name : "(no name)", service->name));

+     DLIST_FOR_EACH(server, service->server_list) {

+         if (server->port != port || server->user_data != user_data)

+             continue;

+         if (name == NULL && server->common == NULL) {

+             return EEXIST;

+         } else if (name != NULL && server->common != NULL) {

+             if (!strcasecmp(name, server->common->name))

+                 return EEXIST;

          }

      }

  

+     server = create_fo_server(service, name, port, user_data);

+     if (!server) {

+         return ENOMEM;

+     }

+ 

      DLIST_ADD_END(service->server_list, server, struct fo_server *);

  

      return EOK;
@@ -452,7 +672,12 @@

          talloc_free(request);

          return ENOMEM;

      }

-     request->server_common = server->common;

+     request->server_common = rc_reference(request, struct server_common,

+                                           server->common);

+     if (request->server_common == NULL) {

+         talloc_free(request);

+         return ENOMEM;

+     }

      request->req = req;

      DLIST_ADD(server->common->request_list, request);

      talloc_set_destructor(request, resolve_service_request_destructor);
@@ -466,9 +691,24 @@

  

  struct resolve_service_state {

      struct fo_server *server;

+ 

+     struct resolv_ctx *resolv;

+     struct tevent_context *ev;

+     struct fo_ctx *fo_ctx;

  };

  

+ 

+ static void fo_resolve_service_cont(struct tevent_req *subreq);

  static void fo_resolve_service_done(struct tevent_req *subreq);

+ static bool fo_resolve_service_server(struct tevent_req *req);

+ 

+ /* Forward declarations for SRV resolving */

+ static struct tevent_req *

+ resolve_srv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,

+                     struct resolv_ctx *resolv, struct fo_ctx *ctx,

+                     struct fo_server *server);

+ static int

+ resolve_srv_recv(struct tevent_req *req, struct fo_server **server);

  

  struct tevent_req *

  fo_resolve_service_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
@@ -486,83 +726,139 @@

      if (req == NULL)

          return NULL;

  

+     state->resolv = resolv;

+     state->ev = ev;

+     state->fo_ctx = ctx;

+ 

      ret = get_first_server_entity(service, &server);

      if (ret != EOK) {

          DEBUG(1, ("No available servers for service '%s'\n", service->name));

          goto done;

      }

  

+     if (fo_is_srv_lookup(server)) {

+         /* Don't know the server yet, must do a SRV lookup */

+         subreq = resolve_srv_send(state, ev, resolv,

+                                   ctx, server);

+         if (subreq == NULL) {

+             ret = ENOMEM;

+             goto done;

+         }

+ 

+         tevent_req_set_callback(subreq,

+                                 fo_resolve_service_cont,

+                                 req);

+         return req;

+     }

+ 

+     /* This is a regular server, just do hostname lookup */

      state->server = server;

+     if (fo_resolve_service_server(req)) {

+         tevent_req_post(req, ev);

+     }

  

-     if (server->common == NULL) {

-         /* This server doesn't have a name, we don't do name resolution. */

-         tevent_req_done(req);

+     ret = EOK;

+ done:

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

          tevent_req_post(req, ev);

-         return req;

+     }

+     return req;

+ }

+ 

+ static void set_server_common_status(struct server_common *common,

+                                      enum server_status status);

+ 

+ /* SRV resolving finished, see if we got server to work with */

+ static void

+ fo_resolve_service_cont(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct resolve_service_state *state = tevent_req_data(req,

+                                         struct resolve_service_state);

+     int ret;

+ 

+     ret = resolve_srv_recv(subreq, &state->server);

+     talloc_zfree(subreq);

+ 

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

      }

  

-     switch (get_server_status(server)) {

+     fo_resolve_service_server(req);

+ }

+ 

+ static bool

+ fo_resolve_service_server(struct tevent_req *req)

+ {

+     struct resolve_service_state *state = tevent_req_data(req,

+                                         struct resolve_service_state);

+     struct tevent_req *subreq;

+     int ret;

+ 

+     switch (get_server_status(state->server)) {

      case SERVER_NAME_NOT_RESOLVED: /* Request name resolution. */

-         subreq = resolv_gethostbyname_send(server->common, ev, resolv,

-                                            server->common->name,

-                                            ctx->opts->family_order);

+         subreq = resolv_gethostbyname_send(state->server->common,

+                                            state->ev, state->resolv,

+                                            state->server->common->name,

+                                            state->fo_ctx->opts->family_order);

          if (subreq == NULL) {

-             ret = ENOMEM;

-             goto done;

+             tevent_req_error(req, ENOMEM);

+             return true;

          }

-         tevent_req_set_callback(subreq, fo_resolve_service_done, server->common);

-         fo_set_server_status(server, SERVER_RESOLVING_NAME);

+         tevent_req_set_callback(subreq, fo_resolve_service_done, req);

+         fo_set_server_status(state->server, SERVER_RESOLVING_NAME);

          /* FALLTHROUGH */

      case SERVER_RESOLVING_NAME:

          /* Name resolution is already under way. Just add ourselves into the

           * waiting queue so we get notified after the operation is finished. */

-         ret = set_lookup_hook(server, req);

-         if (ret != EOK)

-             goto done;

+         ret = set_lookup_hook(state->server, req);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+             return true;

+         }

          break;

      default: /* The name is already resolved. Return immediately. */

          tevent_req_done(req);

-         tevent_req_post(req, ev);

-         break;

+         return true;

      }

  

- done:

-     if (ret != EOK) {

-         tevent_req_error(req, ret);

-         tevent_req_post(req, ev);

-     }

-     return req;

+     return false;

  }

  

- static void set_server_common_status(struct server_common *common,

-                                      enum server_status status);

- 

  static void

  fo_resolve_service_done(struct tevent_req *subreq)

  {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct resolve_service_state *state = tevent_req_data(req,

+                                                 struct resolve_service_state);

+     struct server_common *common;

      int resolv_status;

      struct resolve_service_request *request;

-     struct server_common *common;

      int ret;

  

-     common = tevent_req_callback_data(subreq, struct server_common);

- 

-     if (common->hostent != NULL) {

-         talloc_zfree(common->hostent);

+     if (state->server->common->hostent != NULL) {

+         talloc_zfree(state->server->common->hostent);

      }

  

-     ret = resolv_gethostbyname_recv(subreq, common,

-                                     &resolv_status, NULL, &common->hostent);

-     talloc_free(subreq);

+     ret = resolv_gethostbyname_recv(subreq, state->server->common,

+                                     &resolv_status, NULL,

+                                     &state->server->common->hostent);

+     talloc_zfree(subreq);

      if (ret != EOK) {

-         DEBUG(1, ("Failed to resolve server '%s': %s\n", common->name,

-               resolv_strerror(resolv_status)));

-         set_server_common_status(common, SERVER_NOT_WORKING);

+         DEBUG(1, ("Failed to resolve server '%s': %s\n",

+                   state->server->common->name,

+                   resolv_strerror(resolv_status)));

+         set_server_common_status(state->server->common, SERVER_NOT_WORKING);

      } else {

-         set_server_common_status(common, SERVER_NAME_RESOLVED);

+         set_server_common_status(state->server->common, SERVER_NAME_RESOLVED);

      }

  

      /* Take care of all requests for this server. */

+     common = state->server->common; /* state can disappear now */

      while ((request = common->request_list) != NULL) {

          DLIST_REMOVE(common->request_list, request);

          if (resolv_status) {
@@ -594,6 +890,188 @@

      return EOK;

  }

  

+ /*******************************************************************

+  * Resolve the server to connect to using a SRV query.             *

+  *******************************************************************/

+ 

+ static void resolve_srv_done(struct tevent_req *subreq);

+ 

+ struct resolve_srv_state {

+     struct fo_server *meta;

+     struct fo_service *service;

+ 

+     struct fo_server *out;

+ 

+     struct resolv_ctx *resolv;

+     struct tevent_context *ev;

+     struct fo_ctx *fo_ctx;

+ };

+ 

+ static struct tevent_req *

+ resolve_srv_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev,

+                  struct resolv_ctx *resolv, struct fo_ctx *ctx,

+                  struct fo_server *server)

+ {

+     int ret;

+     char *query;

+     struct tevent_req *req;

+     struct tevent_req *subreq;

+     struct resolve_srv_state *state;

+     int status;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct resolve_srv_state);

+     if (req == NULL)

+         return NULL;

+ 

+     state->service = server->service;

+     state->ev = ev;

+     state->resolv = resolv;

+     state->fo_ctx = ctx;

+     state->meta = server;

+ 

+     status = get_srv_data_status(server->srv_data);

+     DEBUG(6, ("The status of SRV lookup is %s\n",

+               str_srv_data_status(status)));

+     switch(status) {

+     case SRV_EXPIRED: /* Need a refresh */

+         state->meta = collapse_srv_lookup(server);

+         /* FALLTHROUGH */

+     case SRV_NEUTRAL: /* Request SRV lookup */

+         query = get_srv_query(state, state->meta);

+         if (!query) {

+             ret = ENOMEM;

+             goto done;

+         }

+         DEBUG(4, ("Searching for servers via SRV query '%s'\n", query));

+ 

+         subreq = resolv_getsrv_send(state, ev, resolv, query);

+         if (subreq == NULL) {

+             ret = ENOMEM;

+             goto done;

+         }

+         tevent_req_set_callback(subreq, resolve_srv_done, req);

+         break;

+     case SRV_NOT_RESOLVED: /* query could not be resolved but don't retry yet */

+         ret = EIO;

+         goto done;

+     case SRV_RESOLVED:  /* The query is resolved and valid. Return. */

+         state->out = server;

+         tevent_req_done(req);

+         tevent_req_post(req, state->ev);

+         return req;

+     default:

+         DEBUG(1, ("Unexpected status %d for a SRV server\n", status));

+         ret = EIO;

+         break;

+     }

+ 

+     ret = EOK;

+ done:

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         tevent_req_post(req, ev);

+     }

+     return req;

+ }

+ 

+ static void

+ resolve_srv_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct resolve_srv_state *state = tevent_req_data(req,

+                                                 struct resolve_srv_state);

+     struct ares_srv_reply *reply_list;

+     struct ares_srv_reply *reply;

+     struct fo_server *server = NULL;

+     struct fo_server *srv_list = NULL;

+     int ret;

+     int resolv_status;

+ 

+     ret = resolv_getsrv_recv(state, subreq,

+                              &resolv_status, NULL, &reply_list);

+     talloc_free(subreq);

+     if (ret != EOK) {

+         DEBUG(1, ("SRV query failed %s\n",

+                   resolv_strerror(resolv_status)));

+         fo_set_port_status(state->meta, PORT_NOT_WORKING);

+         goto fail;

+     }

+ 

+     ret = resolv_sort_srv_reply(state, &reply_list);

+     if (ret != EOK) {

+         DEBUG(1, ("Could not sort the answers from DNS [%d]: %s\n",

+                   ret, strerror(ret)));

+         fo_set_port_status(state->meta, PORT_NOT_WORKING);

+         goto fail;

+     }

+ 

+     for (reply = reply_list; reply; reply = reply->next) {

+         ret = EOK;

+         DLIST_FOR_EACH(server, state->service->server_list) {

+             if (server->port == reply->port) {

+                 ret = EEXIST;

+                 break;

+             }

+         }

+         if (ret == EEXIST) continue;

+ 

+         server = create_fo_server(state->service, reply->host,

+                                   reply->port, state->meta->user_data);

+         if (!server) {

+             ret = ENOMEM;

+             goto fail;

+         }

+         server->srv_data = state->meta->srv_data;

+ 

+         DLIST_ADD_END(srv_list, server, struct fo_server *);

+         DEBUG(6, ("Inserted server '%s:%d' for service %s\n",

+                   server->common->name,

+                   server->port,

+                   state->service->name));

+     }

+ 

+     if (srv_list) {

+         DLIST_ADD_LIST_AFTER(state->service->server_list, state->meta,

+                              srv_list, struct fo_server *);

+ 

+         DLIST_REMOVE(state->service->server_list, state->meta);

+         if (state->service->last_tried_server == state->meta) {

+             state->service->last_tried_server = srv_list;

+         }

+ 

+         state->out = srv_list;

+         set_srv_data_status(state->meta->srv_data, SRV_RESOLVED);

+         tevent_req_done(req);

+         return;

+     } else {

+         ret = EIO;

+         goto fail;

+     }

+ 

+ fail:

+     state->out = state->meta;

+     set_srv_data_status(state->meta->srv_data, SRV_NOT_RESOLVED);

+     tevent_req_error(req, ret);

+ }

+ 

+ static int

+ resolve_srv_recv(struct tevent_req *req, struct fo_server **server)

+ {

+     struct resolve_srv_state *state = tevent_req_data(req,

+                                                 struct resolve_srv_state);

+ 

+     /* always return the server if asked for, otherwise the caller

+      * cannot mark it as faulty in case we return an error */

+     if (server) {

+         *server = state->out;

+     }

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

  static void

  set_server_common_status(struct server_common *common,

                           enum server_status status)
@@ -644,6 +1122,13 @@

  

  const char *fo_get_server_name(struct fo_server *server)

  {

+     if (!server->common) {

+         if (fo_is_srv_lookup(server)) {

+             return "SRV lookup meta-server";

+         }

+         return "unknown name";

+     }

+ 

      return server->common->name;

  }

  

file modified
+16
@@ -30,6 +30,9 @@

  

  #include "resolv/async_resolv.h"

  

+ #define FO_PROTO_TCP "tcp"

+ #define FO_PROTO_UDP "udp"

+ 

  /* Some forward declarations that don't have to do anything with fail over. */

  struct hostent;

  struct tevent_context;
@@ -60,10 +63,14 @@

   * duration in seconds of how long a server or port will be considered

   * non-working after being marked as such.

   *

+  * The 'srv_retry_timeout' member specifies how long a SRV lookup

+  * is considered valid until we ask the server again.

+  *

   * The family_order member specifies the order of address families to

   * try when looking up the service.

   */

  struct fo_options {

+     time_t srv_retry_timeout;

      time_t retry_timeout;

      enum restrict_family family_order;

  };
@@ -101,6 +108,13 @@

                    int port,

                    void *user_data);

  

+ 

+ int fo_add_srv_server(struct fo_service *service,

+                       const char *srv,

+                       const char *domain,

+                       const char *proto,

+                       void *user_data);

+ 

  /*

   * Request the first server from the service's list of servers. It is only

   * considered if it is not marked as not working (or the retry interval already
@@ -145,4 +159,6 @@

  

  struct hostent *fo_get_server_hostent(struct fo_server *server);

  

+ int fo_is_srv_lookup(struct fo_server *s);

+ 

  #endif /* !__FAIL_OVER_H__ */

file modified
+845 -58
@@ -31,7 +31,8 @@

  #include "providers/ipa/ipa_access.h"

  #include "providers/ipa/ipa_timerules.h"

  

- #define IPA_HOST_MEMBEROF "memberOf"

+ #define OBJECTCLASS "objectclass"

+ #define IPA_MEMBEROF "memberOf"

  #define IPA_HOST_SERVERHOSTNAME "serverHostName"

  #define IPA_HOST_FQDN "fqdn"

  #define IPA_ACCESS_RULE_TYPE "accessRuleType"
@@ -47,14 +48,21 @@

  #define IPA_MEMBER_HOST "memberHost"

  #define IPA_HOST_CATEGORY "hostCategory"

  #define IPA_CN "cn"

+ #define IPA_MEMBER_SERVICE "memberService"

+ #define IPA_SERVICE_CATEGORY "serviceCategory"

+ #define IPA_SERVICEGROUP_MEMBER "member"

  

  #define IPA_HOST_BASE_TMPL "cn=computers,cn=accounts,%s"

  #define IPA_HBAC_BASE_TMPL "cn=hbac,%s"

+ #define IPA_SERVICES_BASE_TMPL "cn=hbacservices,cn=hbac,%s"

+ #define IPA_SERVICEGROUPS_BASE_TMPL "cn=hbacservicegroups,cn=hbac,%s"

  

  #define SYSDB_HBAC_BASE_TMPL "cn=hbac,"SYSDB_TMPL_CUSTOM_BASE

  

  #define HBAC_RULES_SUBDIR "hbac_rules"

  #define HBAC_HOSTS_SUBDIR "hbac_hosts"

+ #define HBAC_SERVICES_SUBDIR "hbac_services"

+ #define HBAC_SERVICEGROUPS_SUBDIR "hbac_servicegroups"

  

  static errno_t msgs2attrs_array(TALLOC_CTX *mem_ctx, size_t count,

                                  struct ldb_message **msgs,
@@ -91,13 +99,667 @@

      pd = talloc_get_type(be_req->req_data, struct pam_data);

      pd->pam_status = pam_status;

  

-     if (pam_status == PAM_SUCCESS) {

+     if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED) {

          be_req->fn(be_req, DP_ERR_OK, pam_status, NULL);

      } else {

          be_req->fn(be_req, DP_ERR_FATAL, pam_status, NULL);

      }

  }

  

+ struct hbac_get_service_data_state {

+     struct tevent_context *ev;

+     struct sdap_id_ctx *sdap_ctx;

+     struct sysdb_ctx *sysdb;

+     struct sysdb_handle *handle;

+     const char *basedn;

+     bool offline;

+ 

+     char *services_filter;

+     char *services_search_base;

+     const char **services_attrs;

+     struct sysdb_attrs **services_reply_list;

+     size_t services_reply_count;

+ 

+     char *servicegroups_filter;

+     char *servicegroups_search_base;

+     const char **servicegroups_attrs;

+     struct sysdb_attrs **servicegroups_reply_list;

+     size_t servicegroups_reply_count;

+ 

+     size_t current_item;

+ };

+ 

+ static void hbac_get_services_connect_done(struct tevent_req *subreq);

+ static void hbac_services_get_done(struct tevent_req *subreq);

+ static void hbac_servicegroups_get_done(struct tevent_req *subreq);

+ static void hbac_service_data_sysdb_transaction_started(struct tevent_req *subreq);

+ static void hbac_services_delete_done(struct tevent_req *subreq);

+ static void hbac_servicegroups_delete_done(struct tevent_req *subreq);

+ static void hbac_service_store_prepare(struct tevent_req *req);

+ static void hbac_service_store_done(struct tevent_req *subreq);

+ static void hbac_servicegroup_store_prepare(struct tevent_req *req);

+ static void hbac_servicegroup_store_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *hbac_get_service_data_send(TALLOC_CTX *memctx,

+                                               struct tevent_context *ev,

+                                                bool offline,

+                                                struct sdap_id_ctx *sdap_ctx,

+                                                struct sysdb_ctx *sysdb,

+                                                const char *basedn)

+ {

+     struct tevent_req *req = NULL;

+     struct tevent_req *subreq = NULL;

+     struct hbac_get_service_data_state *state;

+     int ret;

+ 

+     req = tevent_req_create(memctx, &state, struct hbac_get_service_data_state);

+     if (req == NULL) {

+         DEBUG(1, ("tevent_req_create failed.\n"));

+         return NULL;

+     }

+ 

+     state->ev = ev;

+     state->offline = offline;

+     state->sdap_ctx = sdap_ctx;

+     state->sysdb = sysdb;

+     state->handle = NULL;

+     state->basedn = basedn;

+ 

+     state->services_reply_list = NULL;

+     state->services_reply_count = 0;

+ 

+     state->servicegroups_filter = NULL;

+     state->servicegroups_search_base = NULL;

+     state->servicegroups_attrs = NULL;

+     state->servicegroups_reply_list = NULL;

+     state->servicegroups_reply_count = 0;

+ 

+     state->current_item = 0;

+ 

+     state->services_search_base = talloc_asprintf(state, IPA_SERVICES_BASE_TMPL,

+                                               basedn);

+     if (state->services_search_base == NULL) {

+         DEBUG(1, ("Failed to create service search base.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     state->services_attrs = talloc_array(state, const char *, 7);

+     if (state->services_attrs == NULL) {

+         DEBUG(1, ("Failed to allocate service attribute list.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     state->services_attrs[0] = IPA_CN;

+     state->services_attrs[1] = SYSDB_ORIG_DN;

+     state->services_attrs[2] = IPA_UNIQUE_ID;

+     state->services_attrs[3] = IPA_MEMBEROF;

+     state->services_attrs[4] = SYSDB_ORIG_MEMBEROF;

+     state->services_attrs[5] = OBJECTCLASS;

+     state->services_attrs[6] = NULL;

+ 

+     state->services_filter = talloc_asprintf(state,

+                                             "(objectclass=ipaHBACService)");

+     if (state->services_filter == NULL) {

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     DEBUG(9, ("Services filter: [%s].\n", state->services_filter));

+ 

+     if (offline) {

+         subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL,

+                                           state->sdap_ctx->be->domain,

+                                           state->services_filter,

+                                           HBAC_SERVICES_SUBDIR,

+                                           state->services_attrs);

+         if (subreq == NULL) {

+             DEBUG(1, ("sysdb_search_custom_send failed.\n"));

+             ret = ENOMEM;

+             goto fail;

+         }

+ 

+         tevent_req_set_callback(subreq, hbac_services_get_done, req);

+ 

+         return req;

+     }

+ 

+     if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) {

+         subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,

+                                        sdap_ctx->be, sdap_ctx->service, NULL);

+         if (!subreq) {

+             DEBUG(1, ("sdap_cli_connect_send failed.\n"));

+             ret = ENOMEM;

+             goto fail;

+         }

+ 

+         tevent_req_set_callback(subreq, hbac_get_services_connect_done, req);

+ 

+         return req;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev,

+                                    state->sdap_ctx->opts,

+                                    state->sdap_ctx->gsh,

+                                    state->services_search_base,

+                                    LDAP_SCOPE_SUB,

+                                    state->services_filter,

+                                    state->services_attrs,

+                                    NULL, 0);

+ 

+     if (subreq == NULL) {

+         DEBUG(1, ("sdap_get_generic_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     tevent_req_set_callback(subreq, hbac_services_get_done, req);

+ 

+     return req;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     tevent_req_post(req, ev);

+     return req;

+ }

+ 

+ static void hbac_get_services_connect_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+ 

+     ret = sdap_cli_connect_recv(subreq, state->sdap_ctx, &state->sdap_ctx->gsh,

+                                 NULL);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev,

+                                    state->sdap_ctx->opts,

+                                    state->sdap_ctx->gsh,

+                                    state->services_search_base,

+                                    LDAP_SCOPE_SUB,

+                                    state->services_filter,

+                                    state->services_attrs,

+                                    NULL, 0);

+ 

+     if (subreq == NULL) {

+         DEBUG(1, ("sdap_get_generic_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     tevent_req_set_callback(subreq, hbac_services_get_done, req);

+     return;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_services_get_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+     struct ldb_message **msgs;

+ 

+     if (state->offline) {

+         ret = sysdb_search_custom_recv(subreq, state,

+                                        &state->services_reply_count, &msgs);

+     } else {

+         ret = sdap_get_generic_recv(subreq, state, &state->services_reply_count,

+                                     &state->services_reply_list);

+     }

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (state->offline) {

+         ret = msgs2attrs_array(state, state->services_reply_count, msgs,

+                                &state->services_reply_list);

+         talloc_zfree(msgs);

+         if (ret != EOK) {

+             DEBUG(1, ("msgs2attrs_array failed.\n"));

+             goto fail;

+         }

+     }

+ 

+     state->servicegroups_search_base = talloc_asprintf(state,

+                                                     IPA_SERVICEGROUPS_BASE_TMPL,

+                                                     state->basedn);

+     if (state->servicegroups_search_base == NULL) {

+         DEBUG(1, ("Failed to create service groups search base.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     state->servicegroups_attrs = talloc_array(state, const char *, 8);

+     if (state->servicegroups_attrs == NULL) {

+         DEBUG(1, ("Failed to allocate servicegroup attribute list.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     state->servicegroups_attrs[0] = IPA_CN;

+     state->servicegroups_attrs[1] = IPA_SERVICEGROUP_MEMBER;

+     state->servicegroups_attrs[2] = SYSDB_ORIG_DN;

+     state->servicegroups_attrs[3] = IPA_UNIQUE_ID;

+     state->servicegroups_attrs[4] = IPA_MEMBEROF;

+     state->servicegroups_attrs[5] = SYSDB_ORIG_MEMBEROF;

+     state->servicegroups_attrs[6] = OBJECTCLASS;

+     state->servicegroups_attrs[7] = NULL;

+ 

+     state->servicegroups_filter = talloc_asprintf(state,

+                                            "(objectclass=ipaHBACServiceGroup)");

+     if (state->servicegroups_filter == NULL) {

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     DEBUG(9, ("Services filter: [%s].\n", state->servicegroups_filter));

+ 

+     if (state->offline) {

+         subreq = sysdb_search_custom_send(state, state->ev, state->sysdb, NULL,

+                                           state->sdap_ctx->be->domain,

+                                           state->servicegroups_filter,

+                                           HBAC_SERVICEGROUPS_SUBDIR,

+                                           state->servicegroups_attrs);

+         if (subreq == NULL) {

+             DEBUG(1, ("sysdb_search_custom_send failed.\n"));

+             ret = ENOMEM;

+             goto fail;

+         }

+ 

+         tevent_req_set_callback(subreq, hbac_servicegroups_get_done, req);

+ 

+         return;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev,

+                                    state->sdap_ctx->opts,

+                                    state->sdap_ctx->gsh,

+                                    state->servicegroups_search_base,

+                                    LDAP_SCOPE_SUB,

+                                    state->servicegroups_filter,

+                                    state->servicegroups_attrs,

+                                    NULL, 0);

+ 

+     if (subreq == NULL) {

+         DEBUG(1, ("sdap_get_generic_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     tevent_req_set_callback(subreq, hbac_servicegroups_get_done, req);

+     return;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_servicegroups_get_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+     struct ldb_message **msgs;

+ 

+     if (state->offline) {

+         ret = sysdb_search_custom_recv(subreq, state,

+                                        &state->servicegroups_reply_count, &msgs);

+     } else {

+         ret = sdap_get_generic_recv(subreq, state,

+                                     &state->servicegroups_reply_count,

+                                     &state->servicegroups_reply_list);

+     }

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (state->offline) {

+         ret = msgs2attrs_array(state, state->servicegroups_reply_count, msgs,

+                                &state->servicegroups_reply_list);

+         talloc_zfree(msgs);

+         if (ret != EOK) {

+             DEBUG(1, ("msgs2attrs_array failed.\n"));

+             goto fail;

+         }

+     }

+ 

+     if ((state->services_reply_count == 0 &&

+          state->servicegroups_reply_count == 0)|| state->offline) {

+         tevent_req_done(req);

+         return;

+     }

+ 

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     if (subreq == NULL) {

+         DEBUG(1, ("sysdb_transaction_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     tevent_req_set_callback(subreq, hbac_service_data_sysdb_transaction_started,

+                             req);

+     return;

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_service_data_sysdb_transaction_started(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+     struct ldb_dn *services_base_dn;

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     services_base_dn = sysdb_custom_subtree_dn(state->sysdb, state,

+                                            state->sdap_ctx->be->domain->name,

+                                            HBAC_SERVICES_SUBDIR);

+     if (services_base_dn == NULL) {

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     DEBUG(9, ("Trying to delete [%s].\n", ldb_dn_get_linearized(services_base_dn)));

+     subreq = sysdb_delete_recursive_send(state, state->ev, state->handle,

+                                          services_base_dn, true);

+     if (subreq == NULL) {

+         DEBUG(1, ("sysdb_delete_recursive_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     tevent_req_set_callback(subreq, hbac_services_delete_done, req);

+     return;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_services_delete_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+     struct ldb_dn *servicegroups_base_dn;

+ 

+     ret = sysdb_delete_recursive_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     servicegroups_base_dn = sysdb_custom_subtree_dn(state->sysdb, state,

+                                            state->sdap_ctx->be->domain->name,

+                                            HBAC_SERVICEGROUPS_SUBDIR);

+     if (servicegroups_base_dn == NULL) {

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     DEBUG(9, ("Trying to delete [%s].\n", ldb_dn_get_linearized(servicegroups_base_dn)));

+     subreq = sysdb_delete_recursive_send(state, state->ev, state->handle,

+                                          servicegroups_base_dn, true);

+     if (subreq == NULL) {

+         DEBUG(1, ("sysdb_delete_recursive_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     tevent_req_set_callback(subreq, hbac_servicegroups_delete_done, req);

+     return;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_servicegroups_delete_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+ 

+     ret = sysdb_delete_recursive_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->current_item = 0;

+     hbac_service_store_prepare(req);

+ }

+ 

+ static void hbac_service_store_prepare(struct tevent_req *req)

+ {

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+     struct ldb_message_element *el;

+     struct tevent_req *subreq;

+     char *object_name;

+ 

+     if (state->current_item < state->services_reply_count) {

+ 

+ /* TODO: I would prefer IPA_UNIQUE_ID but currently it is not available */

+         ret = sysdb_attrs_get_el(state->services_reply_list[state->current_item],

+                                  IPA_CN, &el);

+         if (ret != EOK) {

+             DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

+             goto fail;

+         }

+         if (el->num_values == 0) {

+             ret = EINVAL;

+             goto fail;

+         }

+         object_name = talloc_strndup(state, (const char *)el->values[0].data,

+                                      el->values[0].length);

+         if (object_name == NULL) {

+             ret = ENOMEM;

+             goto fail;

+         }

+         DEBUG(9, ("Object name: [%s].\n", object_name));

+ 

+         ret = sysdb_attrs_replace_name(

+                                 state->services_reply_list[state->current_item],

+                                 IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF);

+         if (ret != EOK) {

+             DEBUG(1, ("sysdb_attrs_replace_name failed.\n"));

+             goto fail;

+         }

+ 

+         subreq = sysdb_store_custom_send(state, state->ev,

+                                          state->handle,

+                                          state->sdap_ctx->be->domain,

+                                          object_name,

+                                          HBAC_SERVICES_SUBDIR,

+                                          state->services_reply_list[state->current_item]);

+ 

+         if (subreq == NULL) {

+             DEBUG(1, ("sysdb_store_custom_send failed.\n"));

+             ret = ENOMEM;

+             goto fail;

+         }

+ 

+         tevent_req_set_callback(subreq, hbac_service_store_done, req);

+         return;

+     }

+ 

+     state->current_item = 0;

+     hbac_servicegroup_store_prepare(req);

+ 

+     return;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_service_store_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+ 

+     ret = sysdb_store_custom_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->current_item++;

+     hbac_service_store_prepare(req);

+ }

+ 

+ static void hbac_servicegroup_store_prepare(struct tevent_req *req)

+ {

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+     struct ldb_message_element *el;

+     struct tevent_req *subreq;

+     char *object_name;

+ 

+     if (state->current_item < state->servicegroups_reply_count) {

+ 

+ /* TODO: I would prefer IPA_UNIQUE_ID but currently it is not available */

+         ret = sysdb_attrs_get_el(state->servicegroups_reply_list[state->current_item],

+                                  IPA_CN, &el);

+         if (ret != EOK) {

+             DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

+             goto fail;

+         }

+         if (el->num_values == 0) {

+             ret = EINVAL;

+             goto fail;

+         }

+         object_name = talloc_strndup(state, (const char *)el->values[0].data,

+                                      el->values[0].length);

+         if (object_name == NULL) {

+             ret = ENOMEM;

+             goto fail;

+         }

+         DEBUG(9, ("Object name: [%s].\n", object_name));

+ 

+         ret = sysdb_attrs_replace_name(

+                            state->servicegroups_reply_list[state->current_item],

+                            IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF);

+         if (ret != EOK) {

+             DEBUG(1, ("sysdb_attrs_replace_name failed.\n"));

+             goto fail;

+         }

+ 

+         subreq = sysdb_store_custom_send(state, state->ev,

+                                          state->handle,

+                                          state->sdap_ctx->be->domain,

+                                          object_name,

+                                          HBAC_SERVICEGROUPS_SUBDIR,

+                                          state->servicegroups_reply_list[state->current_item]);

+ 

+         if (subreq == NULL) {

+             DEBUG(1, ("sysdb_store_custom_send failed.\n"));

+             ret = ENOMEM;

+             goto fail;

+         }

+ 

+         tevent_req_set_callback(subreq, hbac_servicegroup_store_done, req);

+         return;

+     }

+ 

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (subreq == NULL) {

+         DEBUG(1, ("sysdb_transaction_commit_send failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     tevent_req_set_callback(subreq, sysdb_transaction_complete, req);

+ 

+     return;

+ 

+ fail:

+     tevent_req_error(req, ret);

+     return;

+ }

+ 

+ static void hbac_servicegroup_store_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int ret;

+ 

+     ret = sysdb_store_custom_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->current_item++;

+     hbac_servicegroup_store_prepare(req);

+ }

+ 

+ static int hbac_get_service_data_recv(struct tevent_req *req,

+                                   TALLOC_CTX *memctx,

+                                   size_t *hbac_services_count,

+                                   struct sysdb_attrs ***hbac_services_list,

+                                   size_t *hbac_servicegroups_count,

+                                   struct sysdb_attrs ***hbac_servicegroups_list)

+ {

+     struct hbac_get_service_data_state *state = tevent_req_data(req,

+                                             struct hbac_get_service_data_state);

+     int i;

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     *hbac_services_count = state->services_reply_count;

+     *hbac_services_list = talloc_steal(memctx, state->services_reply_list);

+     for (i = 0; i < state->services_reply_count; i++) {

+         talloc_steal(memctx, state->services_reply_list[i]);

+     }

+ 

+     *hbac_servicegroups_count = state->servicegroups_reply_count;

+     *hbac_servicegroups_list = talloc_steal(memctx,

+                                                state->servicegroups_reply_list);

+     for (i = 0; i < state->servicegroups_reply_count; i++) {

+         talloc_steal(memctx, state->servicegroups_reply_list[i]);

+     }

+     return EOK;

+ }

+ 

  struct hbac_get_user_info_state {

      struct tevent_context *ev;

      struct be_ctx *be_ctx;;
@@ -407,7 +1069,7 @@

          ret = ENOMEM;

          goto fail;

      }

-     state->host_attrs[0] = IPA_HOST_MEMBEROF;

+     state->host_attrs[0] = IPA_MEMBEROF;

      state->host_attrs[1] = IPA_HOST_SERVERHOSTNAME;

      state->host_attrs[2] = IPA_HOST_FQDN;

      state->host_attrs[3] = "objectClass";
@@ -432,10 +1094,6 @@

      }

  

      if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) {

-         if (sdap_ctx->gsh != NULL) {

-             talloc_zfree(sdap_ctx->gsh);

-         }

- 

          subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,

                                         sdap_ctx->be, sdap_ctx->service, NULL);

          if (!subreq) {
@@ -522,7 +1180,6 @@

                                                 struct hbac_get_host_info_state);

      int ret;

      int i;

-     int v;

      struct ldb_message_element *el;

      struct hbac_host_info **hhi;

      struct ldb_message **msgs;
@@ -628,33 +1285,23 @@

              goto fail;

          }

  

-         ret = sysdb_attrs_get_el(state->host_reply_list[i],

-                                  state->offline ? SYSDB_ORIG_MEMBEROF :

-                                                   IPA_HOST_MEMBEROF,

-                                  &el);

+         ret = sysdb_attrs_get_string_array(state->host_reply_list[i],

+                                           state->offline ? SYSDB_ORIG_MEMBEROF :

+                                                            IPA_MEMBEROF,

+                                           hhi, &(hhi[i]->memberof));

          if (ret != EOK) {

-             DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

-             goto fail;

-         }

- 

-         hhi[i]->memberof = talloc_array(hhi, const char *, el->num_values + 1);

-         if (hhi[i]->memberof == NULL) {

-             ret = ENOMEM;

-             goto fail;

-         }

-         memset(hhi[i]->memberof, 0,

-                sizeof(const char *) * (el->num_values + 1));

+             if (ret != ENOENT) {

+                 DEBUG(1, ("sysdb_attrs_get_string_array failed.\n"));

+                 goto fail;

+             }

  

-         for(v = 0; v < el->num_values; v++) {

-             DEBUG(9, ("%s: [%.*s].\n", IPA_HOST_MEMBEROF, el->values[v].length,

-                                      (const char *)el->values[v].data));

-             hhi[i]->memberof[v] = talloc_strndup(hhi,

-                                                (const char *)el->values[v].data,

-                                                el->values[v].length);

-             if (hhi[i]->memberof[v] == NULL) {

+             hhi[i]->memberof = talloc_array(hhi, const char *, 1);

+             if (hhi[i]->memberof == NULL) {

+                 DEBUG(1, ("talloc_array failed.\n"));

                  ret = ENOMEM;

                  goto fail;

              }

+             hhi[i]->memberof[0] = NULL;

          }

      }

  
@@ -731,7 +1378,7 @@

  

          ret = sysdb_attrs_replace_name(

                                      state->host_reply_list[state->current_item],

-                                     IPA_HOST_MEMBEROF, SYSDB_ORIG_MEMBEROF);

+                                     IPA_MEMBEROF, SYSDB_ORIG_MEMBEROF);

          if (ret != EOK) {

              DEBUG(1, ("sysdb_attrs_replace_name failed.\n"));

              goto fail;
@@ -874,7 +1521,7 @@

          goto fail;

      }

  

-     state->hbac_attrs = talloc_array(state, const char *, 16);

+     state->hbac_attrs = talloc_array(state, const char *, 18);

      if (state->hbac_attrs == NULL) {

          DEBUG(1, ("Failed to allocate HBAC attribute list.\n"));

          ret = ENOMEM;
@@ -891,11 +1538,13 @@

      state->hbac_attrs[8] = IPA_UNIQUE_ID;

      state->hbac_attrs[9] = IPA_ENABLED_FLAG;

      state->hbac_attrs[10] = IPA_CN;

-     state->hbac_attrs[11] = "objectclass";

+     state->hbac_attrs[11] = OBJECTCLASS;

      state->hbac_attrs[12] = IPA_MEMBER_HOST;

      state->hbac_attrs[13] = IPA_HOST_CATEGORY;

-     state->hbac_attrs[14] = SYSDB_ORIG_DN;

-     state->hbac_attrs[15] = NULL;

+     state->hbac_attrs[14] = IPA_MEMBER_SERVICE;

+     state->hbac_attrs[15] = IPA_SERVICE_CATEGORY;

+     state->hbac_attrs[16] = SYSDB_ORIG_DN;

+     state->hbac_attrs[17] = NULL;

  

      state->hbac_filter = talloc_asprintf(state,

                                           "(&(objectclass=ipaHBACRule)"
@@ -941,10 +1590,6 @@

      }

  

      if (sdap_ctx->gsh == NULL || ! sdap_ctx->gsh->connected) {

-         if (sdap_ctx->gsh != NULL) {

-             talloc_zfree(sdap_ctx->gsh);

-         }

- 

          subreq = sdap_cli_connect_send(state, ev, sdap_ctx->opts,

                                         sdap_ctx->be, sdap_ctx->service, NULL);

          if (!subreq) {
@@ -1256,40 +1901,130 @@

      RULE_ERROR

  };

  

- enum check_result check_service(struct pam_data *pd,

+ static errno_t get_service_data(const char *cn, size_t count,

+                                 struct sysdb_attrs **list, const char **dn,

+                                 struct ldb_message_element **mof)

+ {

+     int ret;

+     int i;

+     int j;

+     struct ldb_message_element *el;

+ 

+     for (i = 0; i < count; i++) {

+         ret = sysdb_attrs_get_el(list[i], IPA_CN, &el);

+         if (ret != EOK) {

+             DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

+             return ENOENT;

+         }

+         if (el->num_values == 0) {

+             DEBUG(9, ("No cn found.\n"));

+             return ENOENT;

+         } else {

+             for (j = 0; j < el->num_values; j++) {

+                 if (strlen(cn) == el->values[j].length &&

+                     strncmp(cn, (const char *) el->values[j].data,

+                             el->values[j].length) == 0) {

+ 

+                     ret = sysdb_attrs_get_string(list[i], SYSDB_ORIG_DN, dn);

+                     if (ret != EOK) {

+                         DEBUG(1, ("sysdb_attrs_get_string failed.\n"));

+                         return ret;

+                     }

+ 

+                     ret = sysdb_attrs_get_el(list[i], SYSDB_ORIG_MEMBEROF, mof);

+                     if (ret != EOK) {

+                         DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

+                         return ret;

+                     }

+ 

+                     return EOK;

+                 }

+             }

+         }

+     }

+ 

+     return ENOENT;

+ }

+ 

+ enum check_result check_service(struct hbac_ctx *hbac_ctx,

                                  struct sysdb_attrs *rule_attrs)

  {

      int ret;

      int i;

+     int g;

      struct ldb_message_element *el;

+     const char *service_dn;

+     struct ldb_message_element *service_memberof;

  

-     if (pd->service == NULL) {

+     if (hbac_ctx->pd->service == NULL) {

          DEBUG(1, ("No service in pam data, assuming error.\n"));

          return RULE_ERROR;

      }

  

-     ret = sysdb_attrs_get_el(rule_attrs, IPA_SERVICE_NAME, &el);

+     ret = sysdb_attrs_get_el(rule_attrs, IPA_SERVICE_CATEGORY, &el);

      if (ret != EOK) {

          DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

          return RULE_ERROR;

      }

      if (el->num_values == 0) {

-         DEBUG(9, ("No services in rule specified, assuming rule applies.\n"));

-         return RULE_APPLICABLE;

+         DEBUG(9, ("Service category is not set.\n"));

      } else {

          for (i = 0; i < el->num_values; i++) {

-             if (strncasecmp(pd->service, (const char *) el->values[i].data,

+             if (strncasecmp("all", (const char *) el->values[i].data,

                              el->values[i].length) == 0) {

-                 DEBUG(9, ("Service [%s] found, rule applies.\n",

-                           pd->service));

+                 DEBUG(9, ("Service category is set to 'all', rule applies.\n"));

                  return RULE_APPLICABLE;

              }

+             DEBUG(9, ("Unsupported service category [%.*s].\n",

+                       el->values[i].length,

+                       (char *) el->values[i].data));

          }

-         DEBUG(9, ("No matching service found, rule does not apply.\n"));

+     }

+ 

+     ret = get_service_data(hbac_ctx->pd->service, hbac_ctx->hbac_services_count,

+                            hbac_ctx->hbac_services_list, &service_dn,

+                            &service_memberof);

+     if (ret != EOK) {

+         DEBUG(1, ("Cannot find original DN for service [%s].\n",

+                   hbac_ctx->pd->service));

+         return RULE_ERROR;

+     }

+     DEBUG(9, ("OriginalDN for service [%s]: [%s].\n", hbac_ctx->pd->service,

+               service_dn));

+ 

+     ret = sysdb_attrs_get_el(rule_attrs, IPA_MEMBER_SERVICE, &el);

+     if (ret != EOK) {

+         DEBUG(1, ("sysdb_attrs_get_el failed.\n"));

+         return RULE_ERROR;

+     }

+     if (el->num_values == 0) {

+         DEBUG(9, ("No service or service group specified, rule does not apply.\n"));

          return RULE_NOT_APPLICABLE;

      }

  

-     return RULE_ERROR;

+     for (i = 0; i < el->num_values; i++) {

+         if (strncmp(service_dn, (const char *) el->values[i].data,

+                     el->values[i].length) == 0) {

+             DEBUG(9, ("Service [%s] found in the list of allowed "

+                       "services.\n", hbac_ctx->pd->service));

+             return RULE_APPLICABLE;

+         }

+ 

+         for (g = 0; g < service_memberof->num_values; g++) {

+             if (service_memberof->values[g].length == el->values[i].length &&

+                 strncmp((const char *) service_memberof->values[g].data,

+                         (const char *) el->values[i].data,

+                         el->values[i].length) == 0) {

+                 DEBUG(9, ("Service [%s] is a member of a group in the list of "

+                           "allowed service groups.\n", hbac_ctx->pd->service));

+                 return RULE_APPLICABLE;

+             }

+         }

+     }

+ 

+     DEBUG(9, ("Service [%s] was not found in the list of allowed services and "

+               "service groups.\n", hbac_ctx->pd->service));

+     return RULE_NOT_APPLICABLE;

  }

  

  enum check_result check_access_time(struct time_rules_ctx *tr_ctx,
@@ -1368,7 +2103,7 @@

          return RULE_ERROR;

      }

      if (el->num_values == 0) {

-         DEBUG(9, ("USer category is not set.\n"));

+         DEBUG(9, ("User category is not set.\n"));

      } else {

          for (i = 0; i < el->num_values; i++) {

              if (strncasecmp("all", (const char *) el->values[i].data,
@@ -1389,7 +2124,7 @@

      }

      if (el->num_values == 0) {

          DEBUG(9, ("No user specified, rule does not apply.\n"));

-         return RULE_APPLICABLE;

+         return RULE_NOT_APPLICABLE;

      } else {

          for (i = 0; i < el->num_values; i++) {

              DEBUG(9, ("Searching matches for [%.*s].\n", el->values[i].length,
@@ -1509,9 +2244,9 @@

      return RULE_ERROR;

  }

  

- static errno_t check_if_rule_applies(enum hbac_result *result,

-                                      struct hbac_ctx *hbac_ctx,

-                                      struct sysdb_attrs *rule_attrs) {

+ static errno_t check_if_rule_applies(struct hbac_ctx *hbac_ctx,

+                                      struct sysdb_attrs *rule_attrs,

+                                      enum hbac_result *result) {

      int ret;

      struct ldb_message_element *el;

      enum hbac_result rule_type;
@@ -1536,6 +2271,24 @@

      }

      DEBUG(9, ("Processsing rule [%s].\n", rule_name));

  

+     ret = sysdb_attrs_get_el(rule_attrs, IPA_ENABLED_FLAG, &el);

+     if (ret != EOK) {

+         DEBUG(1, ("Failed to find out if rule is enabled or not, "

+                   "assuming it is enabled.\n"));

+     } else {

+         if (el->num_values == 0) {

+             DEBUG(1, ("Failed to find out if rule is enabled or not, "

+                       "assuming it is enabled.\n"));

+         } else {

+             if (strncasecmp("false", (const char*) el->values[0].data,

+                             el->values[0].length) == 0) {

+                 DEBUG(7, ("Rule is disabled.\n"));

+                 *result = HBAC_NOT_APPLICABLE;

+                 return EOK;

+             }

+         }

+     }

+ 

      /* rule type */

      ret = sysdb_attrs_get_el(rule_attrs, IPA_ACCESS_RULE_TYPE, &el);

      if (ret != EOK) {
@@ -1558,7 +2311,7 @@

          return EINVAL;

      }

  

-     ret = check_service(pd, rule_attrs);

+     ret = check_service(hbac_ctx, rule_attrs);

      if (ret != RULE_APPLICABLE) {

          goto not_applicable;

      }
@@ -1603,8 +2356,8 @@

  

      for (i = 0; i < hbac_ctx->hbac_rule_count ; i++) {

  

-         ret = check_if_rule_applies(&result, hbac_ctx,

-                                     hbac_ctx->hbac_rule_list[i]);

+         ret = check_if_rule_applies(hbac_ctx, hbac_ctx->hbac_rule_list[i],

+                                     &result);

          if (ret != EOK) {

              DEBUG(1, ("check_if_rule_applies failed.\n"));

              return ret;
@@ -1632,6 +2385,7 @@

  

  static void hbac_get_host_info_done(struct tevent_req *req);

  static void hbac_get_rules_done(struct tevent_req *req);

+ static void hbac_get_service_data_done(struct tevent_req *req);

  static void hbac_get_user_info_done(struct tevent_req *req);

  

  void ipa_access_handler(struct be_req *be_req)
@@ -1767,7 +2521,6 @@

  static void hbac_get_rules_done(struct tevent_req *req)

  {

      struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);

-     struct pam_data *pd = hbac_ctx->pd;

      struct be_req *be_req = hbac_ctx->be_req;

      int ret;

      int pam_status = PAM_SYSTEM_ERR;
@@ -1779,6 +2532,40 @@

          goto fail;

      }

  

+     req = hbac_get_service_data_send(hbac_ctx, be_req->be_ctx->ev,

+                                      hbac_ctx->offline, hbac_ctx->sdap_ctx,

+                                      be_req->be_ctx->sysdb,

+                                      hbac_ctx->ldap_basedn);

+     if (req == NULL) {

+         DEBUG(1, ("hbac_get_service_data_send failed.\n"));

+         goto fail;

+     }

+ 

+     tevent_req_set_callback(req, hbac_get_service_data_done, hbac_ctx);

+     return;

+ 

+ fail:

+     ipa_access_reply(be_req, pam_status);

+ }

+ 

+ static void hbac_get_service_data_done(struct tevent_req *req)

+ {

+     struct hbac_ctx *hbac_ctx = tevent_req_callback_data(req, struct hbac_ctx);

+     struct pam_data *pd = hbac_ctx->pd;

+     struct be_req *be_req = hbac_ctx->be_req;

+     int ret;

+     int pam_status = PAM_SYSTEM_ERR;

+ 

+     ret = hbac_get_service_data_recv(req, hbac_ctx,

+                                      &hbac_ctx->hbac_services_count,

+                                      &hbac_ctx->hbac_services_list,

+                                      &hbac_ctx->hbac_servicegroups_count,

+                                      &hbac_ctx->hbac_servicegroups_list);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         goto fail;

+     }

+ 

      req = hbac_get_user_info_send(hbac_ctx, be_req->be_ctx->ev, be_req->be_ctx,

                                    pd->user);

      if (req == NULL) {

@@ -60,6 +60,10 @@

      const char **groups;

      bool offline;

      char *ldap_basedn;

+     struct sysdb_attrs **hbac_services_list;

+     size_t hbac_services_count;

+     struct sysdb_attrs **hbac_servicegroups_list;

+     size_t hbac_servicegroups_count;

  };

  

  void ipa_access_handler(struct be_req *be_req);

file modified
+355 -176
@@ -31,283 +31,462 @@

  #include "providers/krb5/krb5_auth.h"

  #include "providers/ipa/ipa_common.h"

  

- struct ipa_auth_ctx {

-     struct sdap_auth_ctx *sdap_auth_ctx;

-     struct krb5_ctx *krb5_ctx;

-     struct be_req *be_req;

-     be_async_callback_t callback;

-     void *pvt;

-     bool password_migration;

- 

-     int dp_err_type;

-     int errnum;

-     char *errstr;

- };

+ #define IPA_CONFIG_MIRATION_ENABLED "ipaMigrationEnabled"

+ #define IPA_CONFIG_SEARCH_BASE_TEMPLATE "cn=etc,%s"

+ #define IPA_CONFIG_FILTER "(&(cn=ipaConfig)(objectClass=ipaGuiConfig))"

  

- static void ipa_auth_reply(struct ipa_auth_ctx *ipa_auth_ctx)

+ static void ipa_auth_reply(struct be_req *be_req, int dp_err, int result)

  {

-     struct pam_data *pd;

-     struct be_req *be_req = ipa_auth_ctx->be_req;

-     be_req->fn = ipa_auth_ctx->callback;

-     be_req->pvt = ipa_auth_ctx->pvt;

-     be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx;

-     pd = talloc_get_type(be_req->req_data, struct pam_data);

-     int dp_err_type = ipa_auth_ctx->dp_err_type;

-     char *errstr = ipa_auth_ctx->errstr;

- 

-     talloc_zfree(ipa_auth_ctx);

-     DEBUG(9, ("sending [%d] [%d] [%s].\n", dp_err_type, pd->pam_status,

-                                            errstr));

- 

-     be_req->fn(be_req, dp_err_type, pd->pam_status, errstr);

+     be_req->fn(be_req, dp_err, result, NULL);

  }

  

- struct ipa_auth_handler_state {

+ struct get_password_migration_flag_state {

      struct tevent_context *ev;

- 

-     int dp_err_type;

-     int errnum;

-     char *errstr;

+     struct sdap_auth_ctx *sdap_auth_ctx;

+     struct sdap_handle *sh;

+     enum sdap_result result;

+     struct fo_server *srv;

+     char *ipa_domain;

+     bool password_migration;

  };

  

- static void ipa_auth_handler_callback(struct be_req *be_req,

-                                    int dp_err_type,

-                                    int errnum,

-                                    const char *errstr);

+ static void get_password_migration_flag_auth_done(struct tevent_req *subreq);

+ static void get_password_migration_flag_done(struct tevent_req *subreq);

  

- static struct tevent_req *ipa_auth_handler_send(TALLOC_CTX *memctx,

+ static struct tevent_req *get_password_migration_flag_send(TALLOC_CTX *memctx,

                                              struct tevent_context *ev,

-                                             struct be_req *be_req,

-                                             be_req_fn_t auth_handler)

+                                             struct sdap_auth_ctx *sdap_auth_ctx,

+                                             char *ipa_domain)

  {

-     struct ipa_auth_handler_state *state;

-     struct tevent_req *req;

+     int ret;

+     struct tevent_req *req, *subreq;

+     struct get_password_migration_flag_state *state;

+ 

+     if (sdap_auth_ctx == NULL || ipa_domain == NULL) {

+         DEBUG(1, ("Missing parameter.\n"));

+         return NULL;

+     }

  

-     req = tevent_req_create(memctx, &state, struct ipa_auth_handler_state);

+     req = tevent_req_create(memctx, &state,

+                             struct get_password_migration_flag_state);

      if (req == NULL) {

          DEBUG(1, ("tevent_req_create failed.\n"));

          return NULL;

      }

  

      state->ev = ev;

+     state->sdap_auth_ctx = sdap_auth_ctx;

+     state->sh = NULL;

+     state->result = SDAP_ERROR;

+     state->srv = NULL;

+     state->password_migration = false;

+     state->ipa_domain = ipa_domain;

+ 

+     /* We request to use StartTLS here, because if password migration is

+      * enabled we will use this connection for authentication, too. */

+     ret = dp_opt_set_bool(sdap_auth_ctx->opts->basic, SDAP_ID_TLS, true);

+     if (ret != EOK) {

+         DEBUG(1, ("Failed to set SDAP_ID_TLS to true.\n"));

+         goto fail;

+     }

  

-     be_req->fn = ipa_auth_handler_callback;

-     be_req->pvt = req;

- 

-     auth_handler(be_req);

+     subreq = sdap_cli_connect_send(state, ev, sdap_auth_ctx->opts,

+                                    sdap_auth_ctx->be, sdap_auth_ctx->service,

+                                    NULL);

+     if (subreq == NULL) {

+         DEBUG(1, ("sdap_cli_connect_send failed.\n"));

+         goto fail;

+     }

+     tevent_req_set_callback(subreq, get_password_migration_flag_auth_done,

+                             req);

  

      return req;

+ 

+ fail:

+     talloc_zfree(req);

+     return NULL;

  }

  

- static void ipa_auth_handler_callback(struct be_req *be_req,

-                                    int dp_err_type,

-                                    int errnum,

-                                    const char *errstr)

+ static void get_password_migration_flag_auth_done(struct tevent_req *subreq)

  {

-     struct tevent_req *req = talloc_get_type(be_req->pvt, struct tevent_req);

-     struct ipa_auth_handler_state *state = tevent_req_data(req,

-                                                  struct ipa_auth_handler_state);

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct get_password_migration_flag_state *state = tevent_req_data(req,

+                                       struct get_password_migration_flag_state);

+     int ret;

+     char *ldap_basedn;

+     char *search_base;

+     const char **attrs;

+ 

+     ret = sdap_cli_connect_recv(subreq, state, &state->sh, NULL);

+     talloc_zfree(subreq);

+     if (ret) {

+         DEBUG(1, ("sdap_auth request failed.\n"));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     ret = domain_to_basedn(state, state->ipa_domain, &ldap_basedn);

+     if (ret != EOK) {

+         DEBUG(1, ("domain_to_basedn failed.\n"));

+         tevent_req_error(req, ret);

+         return;

+     }

  

-     DEBUG(9, ("received from handler [%d] [%d] [%s].\n", dp_err_type, errnum,

-                                                          errstr));

-     state->dp_err_type = dp_err_type;

-     state->errnum = errnum;

-     state->errstr = talloc_strdup(state, errstr);

+     search_base = talloc_asprintf(state, IPA_CONFIG_SEARCH_BASE_TEMPLATE,

+                                   ldap_basedn);

+     if (search_base == NULL) {

+         DEBUG(1, ("talloc_asprintf failed.\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

  

-     tevent_req_post(req, state->ev);

-     tevent_req_done(req);

-     return;

+     attrs = talloc_array(state, const char*, 2);

+     if (attrs == NULL) {

+         DEBUG(1, ("talloc_array failed.\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     attrs[0] = IPA_CONFIG_MIRATION_ENABLED;

+     attrs[1] = NULL;

+ 

+     subreq = sdap_get_generic_send(state, state->ev, state->sdap_auth_ctx->opts,

+                                    state->sh, search_base, LDAP_SCOPE_SUBTREE,

+                                    IPA_CONFIG_FILTER, attrs, NULL, 0);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq, get_password_migration_flag_done, req);

  }

  

- static int ipa_auth_handler_recv(struct tevent_req *req, TALLOC_CTX *memctx,

-                               int *dp_err_type, int *errnum,

-                               char **errstr)

+ static void get_password_migration_flag_done(struct tevent_req *subreq)

  {

-     struct ipa_auth_handler_state *state = tevent_req_data(req,

-                                                  struct ipa_auth_handler_state);

-     enum tevent_req_state tstate;

-     uint64_t err;

- 

-     if (tevent_req_is_error(req, &tstate, &err)) {

-         if (err) return err;

-         return EIO;

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct get_password_migration_flag_state *state = tevent_req_data(req,

+                                       struct get_password_migration_flag_state);

+     int ret;

+     size_t reply_count;

+     struct sysdb_attrs **reply = NULL;

+     const char *value = NULL;

+ 

+     ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (reply_count != 1) {

+         DEBUG(1, ("Unexpected number of results, expected 1, got %d.\n",

+                   reply_count));

+         tevent_req_error(req, EINVAL);

+         return;

+     }

+ 

+     ret = sysdb_attrs_get_string(reply[0], IPA_CONFIG_MIRATION_ENABLED, &value);

+     if (strcasecmp(value, "true") == 0) {

+         state->password_migration = true;

      }

  

-     *dp_err_type = state->dp_err_type;

-     *errnum = state->errnum;

-     *errstr = talloc_steal(memctx, state->errstr);

+     tevent_req_done(req);

+ }

+ 

+ static int get_password_migration_flag_recv(struct tevent_req *req,

+                                             TALLOC_CTX *mem_ctx,

+                                             bool *password_migration,

+                                             struct sdap_handle **sh)

+ {

+     struct get_password_migration_flag_state *state = tevent_req_data(req,

+                                       struct get_password_migration_flag_state);

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     *password_migration = state->password_migration;

+     if (sh != NULL) {

+         *sh = talloc_steal(mem_ctx, state->sh);

+     }

  

      return EOK;

  }

  

  

+ struct ipa_auth_state {

+     struct be_req *be_req;

+     struct tevent_context *ev;

+     struct ipa_auth_ctx *ipa_auth_ctx;

+     struct pam_data *pd;

+     bool password_migration;

+     struct sdap_handle *sh;

+ };

+ 

  static void ipa_auth_handler_done(struct tevent_req *req);

+ static void ipa_get_migration_flag_done(struct tevent_req *req);

+ static void ipa_auth_get_user_dn_done(struct tevent_req *req);

  static void ipa_auth_ldap_done(struct tevent_req *req);

  static void ipa_auth_handler_retry_done(struct tevent_req *req);

  

  void ipa_auth(struct be_req *be_req)

  {

      struct tevent_req *req;

-     struct ipa_auth_ctx *ipa_auth_ctx;

-     struct sdap_id_ctx *sdap_id_ctx;

+     struct ipa_auth_state *state;

+     struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data);

  

-     ipa_auth_ctx = talloc_zero(be_req, struct ipa_auth_ctx);

-     if (ipa_auth_ctx == NULL) {

-         DEBUG(1, ("talloc failed.\n"));

-         be_req->fn(be_req, DP_ERR_FATAL, PAM_SYSTEM_ERR, NULL);

-     }

- 

-     ipa_auth_ctx->callback = be_req->fn;

-     ipa_auth_ctx->pvt = be_req->pvt;

- 

-     ipa_auth_ctx->be_req = be_req;

- 

-     ipa_auth_ctx->sdap_auth_ctx = talloc_zero(ipa_auth_ctx,

-                                               struct sdap_auth_ctx);

-     if (ipa_auth_ctx->sdap_auth_ctx == NULL) {

-         DEBUG(1, ("talloc failed.\n"));

+     state = talloc_zero(be_req, struct ipa_auth_state);

+     if (state == NULL) {

+         DEBUG(1, ("talloc_zero failed.\n"));

          goto fail;

      }

  

-     sdap_id_ctx = talloc_get_type(

-                               be_req->be_ctx->bet_info[BET_ID].pvt_bet_data,

-                               struct sdap_id_ctx);

-     ipa_auth_ctx->sdap_auth_ctx->be = sdap_id_ctx->be;

-     ipa_auth_ctx->sdap_auth_ctx->opts = sdap_id_ctx->opts;

- 

-     ipa_auth_ctx->krb5_ctx = talloc_get_type(

-                               be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,

-                               struct krb5_ctx);

- 

- /* TODO: test and activate when server side support is available */

-     ipa_auth_ctx->password_migration = false;

- 

-     ipa_auth_ctx->dp_err_type = DP_ERR_FATAL;

-     ipa_auth_ctx->errnum = EIO;

-     ipa_auth_ctx->errstr = NULL;

+     state->password_migration = false;

+     state->sh = NULL;

+ 

+     state->be_req = be_req;

+     state->ev = be_req->be_ctx->ev;

+ 

+     state->pd = pd;

+ 

+     switch (state->pd->cmd) {

+         case SSS_PAM_AUTHENTICATE:

+             state->ipa_auth_ctx = talloc_get_type(

+                                 be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,

+                                 struct ipa_auth_ctx);

+             break;

+         case SSS_PAM_CHAUTHTOK:

+         case SSS_PAM_CHAUTHTOK_PRELIM:

+             state->ipa_auth_ctx = talloc_get_type(

+                               be_req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,

+                               struct ipa_auth_ctx);

+             break;

+         default:

+             DEBUG(1, ("Unsupported PAM task.\n"));

+             goto fail;

+     }

  

-     req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req,

-                                 krb5_pam_handler);

+     req = krb5_auth_send(state, state->ev, be_req->be_ctx, state->pd,

+                          state->ipa_auth_ctx->krb5_auth_ctx);

      if (req == NULL) {

-         DEBUG(1, ("ipa_auth_handler_send failed.\n"));

+         DEBUG(1, ("krb5_auth_send failed.\n"));

          goto fail;

      }

  

-     tevent_req_set_callback(req, ipa_auth_handler_done, ipa_auth_ctx);

+     tevent_req_set_callback(req, ipa_auth_handler_done, state);

      return;

  

  fail:

-     ipa_auth_reply(ipa_auth_ctx);

+     talloc_free(state);

+     pd->pam_status = PAM_SYSTEM_ERR;

+     ipa_auth_reply(be_req, DP_ERR_FATAL, pd->pam_status);

  }

  

  static void ipa_auth_handler_done(struct tevent_req *req)

  {

-     struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req,

-                                                            struct ipa_auth_ctx);

-     struct pam_data *pd;

-     struct be_req *be_req;

+     struct ipa_auth_state *state = tevent_req_callback_data(req,

+                                                          struct ipa_auth_state);

      int ret;

+     int pam_status = PAM_SYSTEM_ERR;

+     int dp_err;

  

-     be_req = ipa_auth_ctx->be_req;

-     pd = talloc_get_type(be_req->req_data, struct pam_data);

- 

-     ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type,

-                                 &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr);

+     ret = krb5_auth_recv(req, &pam_status, &dp_err);

      talloc_zfree(req);

-     if (ret != EOK) {

-         DEBUG(1, ("ipa_auth_handler request failed.\n"));

-         pd->pam_status = PAM_SYSTEM_ERR;

+     state->pd->pam_status = pam_status;

+     if (ret != EOK && pam_status != PAM_CRED_ERR) {

+         DEBUG(1, ("krb5_auth_recv request failed.\n"));

+         dp_err = DP_ERR_OK;

          goto done;

      }

-     if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) {

-         pd->pam_status = ipa_auth_ctx->errnum;

+ 

+     if (dp_err != DP_ERR_OK) {

          goto done;

      }

  

-     if (ipa_auth_ctx->password_migration && pd->pam_status == PAM_CRED_ERR) {

-         DEBUG(1, ("Assuming Kerberos password is missing, "

-                   "starting password migration.\n"));

-         be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data =

-                                                     ipa_auth_ctx->sdap_auth_ctx;

-         req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req,

-                                     sdap_pam_auth_handler);

+     if (state->pd->cmd == SSS_PAM_AUTHENTICATE &&

+         state->pd->pam_status == PAM_CRED_ERR) {

+ 

+         req = get_password_migration_flag_send(state, state->ev,

+                                              state->ipa_auth_ctx->sdap_auth_ctx,

+                                              dp_opt_get_string(

+                                                state->ipa_auth_ctx->ipa_options,

+                                                IPA_DOMAIN));

          if (req == NULL) {

-             DEBUG(1, ("ipa_auth_ldap_send failed.\n"));

+             DEBUG(1, ("get_password_migration_flag failed.\n"));

              goto done;

          }

  

-         tevent_req_set_callback(req, ipa_auth_ldap_done, ipa_auth_ctx);

+         tevent_req_set_callback(req, ipa_get_migration_flag_done, state);

          return;

      }

  

  done:

-     ipa_auth_reply(ipa_auth_ctx);

+     ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);

  }

  

- static void ipa_auth_ldap_done(struct tevent_req *req)

+ static void ipa_get_migration_flag_done(struct tevent_req *req)

  {

-     struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req,

-                                                            struct ipa_auth_ctx);

-     struct pam_data *pd;

-     struct be_req *be_req;

+     struct ipa_auth_state *state = tevent_req_callback_data(req,

+                                                          struct ipa_auth_state);

      int ret;

+     int dp_err = DP_ERR_FATAL;

+     const char **attrs;

  

-     be_req = ipa_auth_ctx->be_req;

-     pd = talloc_get_type(be_req->req_data, struct pam_data);

- 

-     ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type,

-                                 &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr);

+     ret = get_password_migration_flag_recv(req, state,

+                                            &state->password_migration,

+                                            &state->sh);

      talloc_zfree(req);

      if (ret != EOK) {

-         DEBUG(1, ("ipa_auth_handler request failed.\n"));

-         pd->pam_status = PAM_SYSTEM_ERR;

-         goto done;

-     }

-     if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) {

-         pd->pam_status = ipa_auth_ctx->errnum;

+         DEBUG(1, ("get_password_migration_flag request failed.\n"));

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         dp_err = DP_ERR_OK;

          goto done;

      }

  

-     if (pd->pam_status == PAM_SUCCESS) {

-         DEBUG(1, ("LDAP authentication succeded, "

-                   "trying Kerberos authentication again.\n"));

-         be_req->be_ctx->bet_info[BET_AUTH].pvt_bet_data = ipa_auth_ctx->krb5_ctx;

-         req = ipa_auth_handler_send(ipa_auth_ctx, be_req->be_ctx->ev, be_req,

-                                     krb5_pam_handler);

+     if (state->password_migration) {

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         DEBUG(1, ("Assuming Kerberos password is missing, "

+                   "starting password migration.\n"));

+ 

+         attrs = talloc_array(state, const char *, 2);

+         if (attrs == NULL) {

+             DEBUG(1, ("talloc_array failed.\n"));

+             state->pd->pam_status = PAM_SYSTEM_ERR;

+             dp_err = DP_ERR_OK;

+             goto done;

+         }

+         attrs[0] = SYSDB_ORIG_DN;

+         attrs[1] = NULL;

+ 

+         req = sysdb_search_user_by_name_send(state, state->ev,

+                                              state->be_req->be_ctx->sysdb, NULL,

+                                              state->be_req->be_ctx->domain,

+                                              state->pd->user, attrs);

          if (req == NULL) {

-             DEBUG(1, ("ipa_auth_ldap_send failed.\n"));

+             DEBUG(1, ("sysdb_search_user_by_name_send failed.\n"));

              goto done;

          }

  

-         tevent_req_set_callback(req, ipa_auth_handler_retry_done, ipa_auth_ctx);

+         tevent_req_set_callback(req, ipa_auth_get_user_dn_done, state);

          return;

+     } else {

+         DEBUG(5, ("Password migration is not enabled.\n"));

      }

  

+     dp_err = DP_ERR_OK;

+ 

  done:

-     ipa_auth_reply(ipa_auth_ctx);

+     ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);

  }

  

- static void ipa_auth_handler_retry_done(struct tevent_req *req)

+ void ipa_auth_get_user_dn_done(struct tevent_req *req)

  {

-     struct ipa_auth_ctx *ipa_auth_ctx = tevent_req_callback_data(req,

-                                                            struct ipa_auth_ctx);

-     struct pam_data *pd;

-     struct be_req *be_req;

+     struct ipa_auth_state *state = tevent_req_callback_data(req,

+                                                          struct ipa_auth_state);

      int ret;

+     int dp_err = DP_ERR_FATAL;

+     struct dp_opt_blob password;

+     struct ldb_message *msg;

+     const char *dn;

+ 

+     ret = sysdb_search_user_recv(req, state, &msg);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(1, ("sysdb_search_user request failed.\n"));

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         dp_err = DP_ERR_OK;

+         goto done;

+     }

+ 

+     dn = ldb_msg_find_attr_as_string(msg, SYSDB_ORIG_DN, NULL);

+     if (dn == NULL) {

+         DEBUG(1, ("Missing original DN for user [%s].\n", state->pd->user));

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         dp_err = DP_ERR_OK;

+         goto done;

+     }

+ 

+     password.data = state->pd->authtok;

+     password.length = state->pd->authtok_size;

+ 

+     req = sdap_auth_send(state, state->ev, state->sh, NULL, NULL, dn,

+                          "password", password);

+     if (req == NULL) {

+         DEBUG(1, ("sdap_auth_send failed.\n"));

+         goto done;

+     }

  

-     be_req = ipa_auth_ctx->be_req;

-     pd = talloc_get_type(be_req->req_data, struct pam_data);

+     tevent_req_set_callback(req, ipa_auth_ldap_done, state);

+     return;

+ 

+ done:

+     ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);

+ }

+ 

+ 

+ static void ipa_auth_ldap_done(struct tevent_req *req)

+ {

+     struct ipa_auth_state *state = tevent_req_callback_data(req,

+                                                          struct ipa_auth_state);

+     int ret;

+     int dp_err = DP_ERR_FATAL;

+     enum sdap_result result;

  

-     ret = ipa_auth_handler_recv(req, ipa_auth_ctx, &ipa_auth_ctx->dp_err_type,

-                                 &ipa_auth_ctx->errnum, &ipa_auth_ctx->errstr);

+     ret = sdap_auth_recv(req, state, &result, NULL);

      talloc_zfree(req);

      if (ret != EOK) {

-         DEBUG(1, ("ipa_auth_handler request failed.\n"));

-         pd->pam_status = PAM_SYSTEM_ERR;

+         DEBUG(1, ("auth_send request failed.\n"));

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         dp_err = DP_ERR_OK;

+         goto done;

      }

-     if (ipa_auth_ctx->dp_err_type != DP_ERR_OK) {

-         pd->pam_status = ipa_auth_ctx->errnum;

+ 

+ /* TODO: do we need to handle expired passwords? */

+     if (result != SDAP_AUTH_SUCCESS) {

+         DEBUG(1, ("LDAP authentication failed, "

+                   "Password migration not possible.\n"));

+         state->pd->pam_status = PAM_CRED_INSUFFICIENT;

+         dp_err = DP_ERR_OK;

+         goto done;

      }

  

-     ipa_auth_reply(ipa_auth_ctx);

+     DEBUG(1, ("LDAP authentication succeded, "

+               "trying Kerberos authentication again.\n"));

+ 

+     req = krb5_auth_send(state, state->ev,

+                          state->be_req->be_ctx, state->pd,

+                          state->ipa_auth_ctx->krb5_auth_ctx);

+     if (req == NULL) {

+         DEBUG(1, ("krb5_auth_send failed.\n"));

+         goto done;

+     }

+ 

+     tevent_req_set_callback(req, ipa_auth_handler_retry_done, state);

+     return;

+ 

+ done:

+     ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);

+ }

+ 

+ static void ipa_auth_handler_retry_done(struct tevent_req *req)

+ {

+     struct ipa_auth_state *state = tevent_req_callback_data(req,

+                                                          struct ipa_auth_state);

+     int ret;

+     int pam_status;

+     int dp_err;

+ 

+     ret = krb5_auth_recv(req, &pam_status, &dp_err);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(1, ("krb5_auth_recv request failed.\n"));

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         dp_err = DP_ERR_OK;

+         goto done;

+     }

+ 

+     state->pd->pam_status = pam_status;

+ 

+ done:

+     ipa_auth_reply(state->be_req, dp_err, state->pd->pam_status);

  }

file modified
+47 -14
@@ -32,6 +32,8 @@

      { "ipa_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ipa_server", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ipa_hostname", DP_OPT_STRING, NULL_STRING, NULL_STRING },

+     { "ipa_dyndns_update", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },

+     { "ipa_dyndns_iface", DP_OPT_STRING, NULL_STRING, NULL_STRING}

  };

  

  struct dp_option ipa_def_ldap_opts[] = {
@@ -40,7 +42,7 @@

      { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING},

      { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },

-     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },

+     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER },

      { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },

      { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },

      { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING },
@@ -51,7 +53,6 @@

      { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },

      { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_schema", DP_OPT_STRING, { "ipa_v1" }, NULL_STRING },

-     { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },

      { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },

      { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },

      { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 3600 }, NULL_NUMBER },
@@ -67,7 +68,11 @@

      { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING },

      { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },

-     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER }

+     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },

+     { "ldap_dns_service_name", DP_OPT_STRING, { SSS_LDAP_SRV_NAME }, NULL_STRING },

+     { "ldap_access_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },

+     { "ldap_krb5_ticket_lifetime", DP_OPT_NUMBER, { .number = (24 * 60 * 60) }, NULL_NUMBER },

+     { "ldap_group_nesting_level", DP_OPT_NUMBER, { .number = 2 }, NULL_NUMBER }

  };

  

  struct sdap_attr_map ipa_attr_map[] = {
@@ -120,7 +125,8 @@

      { "krb5_auth_timeout", DP_OPT_NUMBER, { .number = 15 }, NULL_NUMBER },

      { "krb5_keytab", DP_OPT_STRING, { "/etc/krb5.keytab" }, NULL_STRING },

      { "krb5_validate", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },

-     { "krb5_kpasswd", DP_OPT_STRING, NULL_STRING, NULL_STRING }

+     { "krb5_kpasswd", DP_OPT_STRING, NULL_STRING, NULL_STRING },

+     { "krb5_store_password_if_offline", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }

  };

  

  int ipa_get_options(TALLOC_CTX *memctx,
@@ -155,12 +161,9 @@

          }

      }

  

-     /* FIXME: Make non-fatal once we have discovery */

      server = dp_opt_get_string(opts->basic, IPA_SERVER);

      if (!server) {

-         DEBUG(0, ("Can't find ipa server, missing option!\n"));

-         ret = EINVAL;

-         goto done;

+         DEBUG(1, ("No ipa server set, will use service discovery!\n"));

      }

  

      ipa_hostname = dp_opt_get_string(opts->basic, IPA_HOSTNAME);
@@ -280,11 +283,17 @@

      /* set krb realm */

      if (NULL == dp_opt_get_string(ipa_opts->id->basic, SDAP_KRB5_REALM)) {

          realm = dp_opt_get_string(ipa_opts->basic, IPA_DOMAIN);

-         for (i = 0; realm[i]; i++) {

-             realm[i] = toupper(realm[i]);

+         value = talloc_strdup(tmpctx, realm);

+         if (value == NULL) {

+             DEBUG(1, ("talloc_strdup failed.\n"));

+             ret = ENOMEM;

+             goto done;

+         }

+         for (i = 0; value[i]; i++) {

+             value[i] = toupper(value[i]);

          }

          ret = dp_opt_set_string(ipa_opts->id->basic,

-                                 SDAP_KRB5_REALM, realm);

+                                 SDAP_KRB5_REALM, value);

          if (ret != EOK) {

              goto done;

          }
@@ -368,6 +377,7 @@

                           struct dp_option **_opts)

  {

      char *value;

+     char *copy = NULL;

      int ret;

      int i;

  
@@ -400,10 +410,16 @@

              ret = ENOMEM;

              goto done;

          }

-         for (i = 0; value[i]; i++) {

-             value[i] = toupper(value[i]);

+         copy = talloc_strdup(ipa_opts->auth, value);

+         if (copy == NULL) {

+             DEBUG(1, ("talloc_strdup failed.\n"));

+             ret = ENOMEM;

+             goto done;

+         }

+         for (i = 0; copy[i]; i++) {

+             copy[i] = toupper(copy[i]);

          }

-         ret = dp_opt_set_string(ipa_opts->auth, KRB5_REALM, value);

+         ret = dp_opt_set_string(ipa_opts->auth, KRB5_REALM, copy);

          if (ret != EOK) {

              goto done;

          }
@@ -416,6 +432,7 @@

      ret = EOK;

  

  done:

+     talloc_free(copy);

      if (ret != EOK) {

          talloc_zfree(ipa_opts->auth);

      }
@@ -536,6 +553,10 @@

      }

      service->krb5_service->realm = realm;

  

+     if (!servers) {

+         servers = BE_SRV_IDENTIFIER;

+     }

+ 

      /* split server parm into a list */

      ret = split_on_separator(tmp_ctx, servers, ',', true, &list, NULL);

      if (ret != EOK) {
@@ -548,6 +569,18 @@

  

          talloc_steal(service, list[i]);

  

+         if (be_fo_is_srv_identifier(list[i])) {

+             ret = be_fo_add_srv_server(ctx, "IPA", "ldap",

+                                        FO_PROTO_TCP, ctx->domain->name, NULL);

+             if (ret) {

+                 DEBUG(0, ("Failed to add server\n"));

+                 goto done;

+             }

+ 

+             DEBUG(6, ("Added service lookup for service IPA\n"));

+             continue;

+         }

+ 

          ret = be_fo_add_server(ctx, "IPA", list[i], 0, NULL);

          if (ret && ret != EEXIST) {

              DEBUG(0, ("Failed to add server\n"));

@@ -35,21 +35,29 @@

  /* the following defines are used to keep track of the options in the ldap

   * module, so that if they change and ipa is not updated correspondingly

   * this will trigger a runtime abort error */

- #define IPA_OPTS_BASIC_TEST 32

+ #define IPA_OPTS_BASIC_TEST 35

  

  /* the following define is used to keep track of the options in the krb5

   * module, so that if they change and ipa is not updated correspondingly

   * this will trigger a runtime abort error */

- #define IPA_KRB5_OPTS_TEST 9

+ #define IPA_KRB5_OPTS_TEST 10

  

  enum ipa_basic_opt {

      IPA_DOMAIN = 0,

      IPA_SERVER,

      IPA_HOSTNAME,

+     IPA_DYNDNS_UPDATE,

+     IPA_DYNDNS_IFACE,

  

      IPA_OPTS_BASIC /* opts counter */

  };

  

+ struct ipa_auth_ctx {

+     struct krb5_ctx *krb5_auth_ctx;

+     struct sdap_auth_ctx *sdap_auth_ctx;

+     struct dp_option *ipa_options;

+ };

+ 

  struct ipa_options {

      struct dp_option *basic;

  
@@ -61,7 +69,7 @@

  

      /* auth and chpass provider */

      struct dp_option *auth;

-     struct krb5_ctx *auth_ctx;

+     struct ipa_auth_ctx *auth_ctx;

  };

  

  int domain_to_basedn(TALLOC_CTX *memctx, const char *domain, char **basedn);

@@ -0,0 +1,587 @@

+ /*

+     SSSD

+ 

+     ipa_dyndns.c

+ 

+     Authors:

+         Stephen Gallagher <sgallagh@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include <sys/types.h>

+ #include <sys/socket.h>

+ #include <sys/ioctl.h>

+ #include <arpa/inet.h>

+ #include <net/if.h>

+ #include <ifaddrs.h>

+ #include <ctype.h>

+ #include "util/util.h"

+ #include "confdb/confdb.h"

+ #include "providers/ipa/ipa_common.h"

+ #include "providers/ipa/ipa_dyndns.h"

+ #include "providers/child_common.h"

+ #include "providers/data_provider.h"

+ #include "providers/ldap/ldap_common.h"

+ #include "providers/ldap/sdap_async_private.h"

+ #include "resolv/async_resolv.h"

+ 

+ #define IPA_DYNDNS_TIMEOUT 15

+ 

+ struct ipa_ipaddress {

+     struct ipa_ipaddress *next;

+     struct ipa_ipaddress *prev;

+ 

+     struct sockaddr *addr;

+     bool matched;

+ };

+ 

+ struct ipa_dyndns_ctx {

+     struct ipa_options *ipa_ctx;

+     char *hostname;

+     struct ipa_ipaddress *addresses;

+     int child_status;

+ };

+ 

+ 

+ static struct tevent_req * ipa_dyndns_update_send(struct ipa_options *ctx);

+ 

+ static void ipa_dyndns_update_done(struct tevent_req *req);

+ 

+ void ipa_dyndns_update(void *pvt)

+ {

+     struct ipa_options *ctx = talloc_get_type(pvt, struct ipa_options);

+     struct tevent_req *req = ipa_dyndns_update_send(ctx);

+     if (req == NULL) {

+         DEBUG(1, ("Could not update DNS\n"));

+         return;

+     }

+     tevent_req_set_callback(req, ipa_dyndns_update_done, req);

+ }

+ 

+ 

+ static struct tevent_req *

+ ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx);

+ 

+ static void ipa_dyndns_gss_tsig_update_done(struct tevent_req *subreq);

+ 

+ static struct tevent_req *

+ ipa_dyndns_update_send(struct ipa_options *ctx)

+ {

+     int ret;

+     int fd;

+     char *iface;

+     char *ipa_hostname;

+     struct ipa_dyndns_ctx *state;

+     struct sockaddr sa;

+     socklen_t sa_len = sizeof(sa);

+     struct ifaddrs *ifaces;

+     struct ifaddrs *ifa;

+     struct ipa_ipaddress *address;

+     struct tevent_req *req, *subreq;

+ 

+     DEBUG (9, ("Performing update\n"));

+ 

+     req = tevent_req_create(ctx, &state, struct ipa_dyndns_ctx);

+     if (req == NULL) {

+         return NULL;

+     }

+     state->ipa_ctx = ctx;

+ 

+     iface = dp_opt_get_string(ctx->basic, IPA_DYNDNS_IFACE);

+ 

+     if (iface) {

+         /* Get the IP addresses associated with the

+          * specified interface

+          */

+         errno = 0;

+         ret = getifaddrs(&ifaces);

+         if (ret == -1) {

+             ret = errno;

+             DEBUG(0, ("Could not read interfaces [%d][%s]\n",

+                       ret, strerror(ret)));

+             goto failed;

+         }

+ 

+         for(ifa = ifaces; ifa != NULL; ifa=ifa->ifa_next) {

+             /* Some interfaces don't have an ifa_addr */

+             if (!ifa->ifa_addr) continue;

+ 

+             /* Add IP addresses to the list */

+             if((ifa->ifa_addr->sa_family == AF_INET ||

+                 ifa->ifa_addr->sa_family == AF_INET6) &&

+                strcasecmp(ifa->ifa_name, iface) == 0) {

+                 /* Add this address to the IP address list */

+                 address = talloc_zero(state, struct ipa_ipaddress);

+                 if (!address) {

+                     goto failed;

+                 }

+ 

+                 address->addr = talloc_memdup(address, ifa->ifa_addr,

+                                               sizeof(struct sockaddr));

+                 if(address->addr == NULL) {

+                     goto failed;

+                 }

+                 DLIST_ADD(state->addresses, address);

+             }

+         }

+ 

+         freeifaddrs(ifaces);

+     }

+ 

+     else {

+         /* Get the file descriptor for the primary LDAP connection */

+         ret = get_fd_from_ldap(ctx->id_ctx->gsh->ldap, &fd);

+         if (ret != EOK) {

+             goto failed;

+         }

+ 

+         ret = getsockname(fd, &sa, &sa_len);

+         if (ret == -1) {

+             DEBUG(0,("Failed to get socket name\n"));

+             goto failed;

+         }

+ 

+         switch(sa.sa_family) {

+         case AF_INET:

+         case AF_INET6:

+             address = talloc(state, struct ipa_ipaddress);

+             if (!address) {

+                 goto failed;

+             }

+             address->addr = talloc_memdup(address, &sa,

+                                           sizeof(struct sockaddr));

+             if(address->addr == NULL) {

+                 goto failed;

+             }

+             DLIST_ADD(state->addresses, address);

+             break;

+         default:

+             DEBUG(1, ("Connection to LDAP is neither IPv4 nor IPv6\n"));

+             ret = EIO;

+             goto failed;

+         }

+     }

+ 

+     /* Get the IPA hostname */

+     ipa_hostname = dp_opt_get_string(state->ipa_ctx->basic,

+                                      IPA_HOSTNAME);

+     if (!ipa_hostname) {

+         /* This should never happen, but we'll protect

+          * against it anyway.

+          */

+         talloc_free(req);

+         return NULL;

+     }

+ 

+     state->hostname = talloc_strdup(state, ipa_hostname);

+     if(state->hostname == NULL) {

+         talloc_free(req);

+         return NULL;

+     }

+ 

+     /* In the future, it might be best to check that an update

+      * needs to be run before running it, but this is such a

+      * rare event that it's probably fine to just run an update

+      * every time we come online.

+      */

+     subreq = ipa_dyndns_gss_tsig_update_send(state);

+     if(subreq == NULL) {

+         tevent_req_error(req, EIO);

+     }

+     tevent_req_set_callback(subreq,

+                             ipa_dyndns_gss_tsig_update_done,

+                             req);

+     return req;

+ 

+ failed:

+     talloc_free(req);

+     return NULL;

+ }

+ 

+ struct ipa_nsupdate_ctx {

+     char *update_msg;

+     struct ipa_dyndns_ctx *dyndns_ctx;

+     int pipefd_to_child;

+     struct tevent_timer *timeout_handler;

+ };

+ 

+ 

+ static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx);

+ 

+ static struct tevent_req *

+ fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx);

+ 

+ static void fork_nsupdate_done(struct tevent_req *subreq);

+ 

+ static struct tevent_req *

+ ipa_dyndns_gss_tsig_update_send(struct ipa_dyndns_ctx *ctx)

+ {

+     int ret;

+     struct ipa_nsupdate_ctx *state;

+     struct tevent_req *req;

+     struct tevent_req *subreq;

+ 

+     req = tevent_req_create(ctx, &state, struct ipa_nsupdate_ctx);

+     if(req == NULL) {

+         return NULL;

+     }

+     state->dyndns_ctx = ctx;

+ 

+     /* Format the message to pass to the nsupdate command */

+     ret = create_nsupdate_message(state);

+     if (ret != EOK) {

+         goto failed;

+     }

+ 

+     /* Fork a child process to perform the DNS update */

+     subreq = fork_nsupdate_send(state);

+     if(subreq == NULL) {

+         goto failed;

+     }

+     tevent_req_set_callback(subreq, fork_nsupdate_done, req);

+ 

+     return req;

+ 

+ failed:

+     talloc_free(req);

+     return NULL;

+ }

+ 

+ struct nsupdate_send_ctx {

+     struct ipa_nsupdate_ctx *nsupdate_ctx;

+ };

+ 

+ static int create_nsupdate_message(struct ipa_nsupdate_ctx *ctx)

+ {

+     int ret, i;

+     char *servername;

+     char *zone;

+     char ip_addr[INET6_ADDRSTRLEN];

+     const char *ip;

+     struct ipa_ipaddress *new_record;

+ 

+     servername = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic,

+                                    IPA_SERVER);

+     if (!servername) {

+         return EIO;

+     }

+ 

+     zone = dp_opt_get_string(ctx->dyndns_ctx->ipa_ctx->basic,

+                              IPA_DOMAIN);

+     if (!zone) {

+         return EIO;

+     }

+ 

+     /* The DNS zone for IPA is the lower-case

+      * version of hte IPA domain

+      */

+     for(i = 0; zone[i] != '\0'; i++) {

+         zone[i] = tolower(zone[i]);

+     }

+ 

+     /* Add the server and zone headers */

+     ctx->update_msg = talloc_asprintf(ctx, "server %s\nzone %s.\n",

+                                            servername,

+                                            zone);

+     if (ctx->update_msg == NULL) {

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     /* Remove any existing entries */

+     ctx->update_msg = talloc_asprintf_append(ctx->update_msg,

+                                              "update delete %s. in A\nsend\n"

+                                              "update delete %s. in AAAA\nsend\n",

+                                              ctx->dyndns_ctx->hostname,

+                                              ctx->dyndns_ctx->hostname);

+     if (ctx->update_msg == NULL) {

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     DLIST_FOR_EACH(new_record, ctx->dyndns_ctx->addresses) {

+         switch(new_record->addr->sa_family) {

+         case AF_INET:

+             ip = inet_ntop(new_record->addr->sa_family,

+                            &(((struct sockaddr_in *)new_record->addr)->sin_addr),

+                            ip_addr, INET6_ADDRSTRLEN);

+             if (ip == NULL) {

+                 ret = EIO;

+                 goto done;

+             }

+             break;

+ 

+         case AF_INET6:

+             ip = inet_ntop(new_record->addr->sa_family,

+                            &(((struct sockaddr_in6 *)new_record->addr)->sin6_addr),

+                            ip_addr, INET6_ADDRSTRLEN);

+             if (ip == NULL) {

+                 ret = EIO;

+                 goto done;

+             }

+             break;

+ 

+         default:

+             DEBUG(0, ("Unknown address family\n"));

+             ret = EIO;

+             goto done;

+         }

+ 

+         /* Format the record update */

+         ctx->update_msg = talloc_asprintf_append(

+                 ctx->update_msg,

+                 "update add %s. 86400 in %s %s\n",

+                 ctx->dyndns_ctx->hostname,

+                 new_record->addr->sa_family == AF_INET ? "A" : "AAAA",

+                 ip_addr);

+         if (ctx->update_msg == NULL) {

+             ret = ENOMEM;

+             goto done;

+         }

+     }

+ 

+     ctx->update_msg = talloc_asprintf_append(ctx->update_msg, "send\n");

+     if (ctx->update_msg == NULL) {

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     ret = EOK;

+ 

+ done:

+     return ret;

+ }

+ 

+ static void ipa_dyndns_stdin_done(struct tevent_req *subreq);

+ 

+ static void ipa_dyndns_child_handler(int child_status,

+                                      struct tevent_signal *sige,

+                                      void *pvt);

+ 

+ static void ipa_dyndns_timeout(struct tevent_context *ev,

+                                struct tevent_timer *te,

+                                struct timeval tv, void *pvt);

+ 

+ static struct tevent_req *

+ fork_nsupdate_send(struct ipa_nsupdate_ctx *ctx)

+ {

+     int pipefd_to_child[2];

+     pid_t pid;

+     int ret;

+     errno_t err;

+     struct timeval tv;

+     struct tevent_req *req = NULL;

+     struct tevent_req *subreq = NULL;

+     struct nsupdate_send_ctx *state;

+     char *args[3];

+ 

+     req = tevent_req_create(ctx, &state, struct nsupdate_send_ctx);

+     if (req == NULL) {

+         return NULL;

+     }

+     state->nsupdate_ctx = ctx;

+ 

+     ret = pipe(pipefd_to_child);

+     if (ret == -1) {

+         err = errno;

+         DEBUG(1, ("pipe failed [%d][%s].\n", err, strerror(err)));

+         return NULL;

+     }

+ 

+     pid = fork();

+ 

+     if (pid == 0) { /* child */

+         args[0] = talloc_strdup(ctx, NSUPDATE_PATH);

+         args[1] = talloc_strdup(ctx, "-g");

+         args[2] = NULL;

+         if (args[0] == NULL || args[1] == NULL) {

+             return NULL;

+         }

+ 

+         close(pipefd_to_child[1]);

+         ret = dup2(pipefd_to_child[0], STDIN_FILENO);

+         if (ret == -1) {

+             err = errno;

+             DEBUG(1, ("dup2 failed [%d][%s].\n", err, strerror(err)));

+             return NULL;

+         }

+ 

+         errno = 0;

+         ret = execv(NSUPDATE_PATH, args);

+         if(ret == -1) {

+             err = errno;

+             DEBUG(1, ("execv failed [%d][%s].\n", err, strerror(err)));

+         }

+         return NULL;

+     }

+ 

+     else if (pid > 0) { /* parent */

+         close(pipefd_to_child[0]);

+ 

+         ctx->pipefd_to_child = pipefd_to_child[1];

+ 

+         /* Write the update message to the nsupdate child */

+         subreq = write_pipe_send(req,

+                                  ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev,

+                                  (uint8_t *)ctx->update_msg,

+                                  strlen(ctx->update_msg)+1,

+                                  ctx->pipefd_to_child);

+         if (subreq == NULL) {

+             return NULL;

+         }

+         tevent_req_set_callback(subreq, ipa_dyndns_stdin_done, req);

+ 

+         /* Set up SIGCHLD handler */

+         ret = child_handler_setup(ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev,

+                                   pid, ipa_dyndns_child_handler, req);

+         if (ret != EOK) {

+             return NULL;

+         }

+ 

+         /* Set up timeout handler */

+         tv = tevent_timeval_current_ofs(IPA_DYNDNS_TIMEOUT, 0);

+         ctx->timeout_handler = tevent_add_timer(

+                 ctx->dyndns_ctx->ipa_ctx->id_ctx->be->ev,

+                 req, tv, ipa_dyndns_timeout, req);

+         if(ctx->timeout_handler == NULL) {

+             return NULL;

+         }

+     }

+ 

+     else { /* error */

+         err = errno;

+         DEBUG(1, ("fork failed [%d][%s].\n", err, strerror(err)));

+         return NULL;

+     }

+ 

+     return req;

+ }

+ 

+ static void ipa_dyndns_timeout(struct tevent_context *ev,

+                                struct tevent_timer *te,

+                                struct timeval tv, void *pvt)

+ {

+     struct tevent_req *req =

+             talloc_get_type(pvt, struct tevent_req);

+ 

+     DEBUG(1, ("Timeout reached for dynamic DNS update\n"));

+ 

+     tevent_req_error(req, ETIMEDOUT);

+ }

+ 

+ static void ipa_dyndns_stdin_done(struct tevent_req *subreq)

+ {

+     /* Verify that the buffer was sent, then return

+      * and wait for the sigchld handler to finish.

+      */

+     DEBUG(9, ("Sending nsupdate data complete\n"));

+ 

+     int ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct nsupdate_send_ctx *state =

+             tevent_req_data(req, struct nsupdate_send_ctx);

+ 

+     ret = write_pipe_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(1, ("Sending nsupdate data failed\n"));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     close(state->nsupdate_ctx->pipefd_to_child);

+     state->nsupdate_ctx->pipefd_to_child = -1;

+ }

+ 

+ static void ipa_dyndns_child_handler(int child_status,

+                                      struct tevent_signal *sige,

+                                      void *pvt)

+ {

+     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);

+ 

+     if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {

+         DEBUG(1, ("Dynamic DNS child failed with status [%d]\n",

+                   child_status));

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     if WIFSIGNALED(child_status) {

+         DEBUG(1, ("Dynamic DNS child was terminated by signal [%d]\n",

+                   WTERMSIG(child_status)));

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ static int ipa_dyndns_generic_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ static void fork_nsupdate_done(struct tevent_req *subreq)

+ {

+     int ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = ipa_dyndns_generic_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ static void ipa_dyndns_gss_tsig_update_done(struct tevent_req *subreq)

+ {

+     /* Check the return code from the sigchld handler

+      * and return it to the parent request.

+      */

+     int ret;

+ 

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = ipa_dyndns_generic_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ static void ipa_dyndns_update_done(struct tevent_req *req)

+ {

+     int ret = ipa_dyndns_generic_recv(req);

+     talloc_free(req);

+     if (ret != EOK) {

+         DEBUG(1, ("Updating DNS entry failed\n"));

+         return;

+     }

+ 

+     DEBUG(1,("Updated DNS entry\n"));

+ }

@@ -0,0 +1,31 @@

+ /*

+     SSSD

+ 

+     ipa_dyndns.h

+ 

+     Authors:

+         Stephen Gallagher <sgallagh@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #ifndef IPA_DYNDNS_H_

+ #define IPA_DYNDNS_H_

+ 

+ void ipa_dyndns_update(void *pvt);

+ 

+ 

+ #endif /* IPA_DYNDNS_H_ */

file modified
+134 -28
@@ -33,6 +33,7 @@

  #include "providers/ipa/ipa_auth.h"

  #include "providers/ipa/ipa_access.h"

  #include "providers/ipa/ipa_timerules.h"

+ #include "providers/ipa/ipa_dyndns.h"

  

  struct ipa_options *ipa_options = NULL;

  
@@ -48,7 +49,7 @@

  };

  

  struct bet_ops ipa_chpass_ops = {

-     .handler = krb5_pam_handler,

+     .handler = ipa_auth,

      .finalize = NULL,

  };

  
@@ -72,8 +73,7 @@

  

      ipa_servers = dp_opt_get_string(ipa_options->basic, IPA_SERVER);

      if (!ipa_servers) {

-         DEBUG(0, ("Missing ipa_server option!\n"));

-         return EINVAL;

+         DEBUG(1, ("Missing ipa_server option - using service discovery!\n"));

      }

  

      ipa_domain = dp_opt_get_string(ipa_options->basic, IPA_DOMAIN);
@@ -92,11 +92,13 @@

      return EOK;

  }

  

- int sssm_ipa_init(struct be_ctx *bectx,

-                   struct bet_ops **ops,

-                   void **pvt_data)

+ int sssm_ipa_id_init(struct be_ctx *bectx,

+                      struct bet_ops **ops,

+                      void **pvt_data)

  {

      struct sdap_id_ctx *ctx;

+     struct stat stat_buf;

+     errno_t err;

      int ret;

  

      if (!ipa_options) {
@@ -128,6 +130,54 @@

          goto done;

      }

  

+     /* FIXME: This is a workaround for 1.2.0. In the future, we need to have

+      * separate timeouts for enumeration operations

+      * If enumeration is enabled and the search timeout is less

+      * than 30s, force it to a minimum of 30s.

+      */

+     if(bectx->domain->enumerate &&

+             dp_opt_get_int(ctx->opts->basic, SDAP_SEARCH_TIMEOUT) < 30) {

+         dp_opt_set_int(ctx->opts->basic, SDAP_SEARCH_TIMEOUT, 30);

+     }

+ 

+     if(dp_opt_get_bool(ipa_options->basic, IPA_DYNDNS_UPDATE)) {

+         /* Perform automatic DNS updates when the

+          * IP address changes.

+          * Register a callback for successful LDAP

+          * reconnections. This is the easiest way to

+          * identify that we have gone online.

+          */

+ 

+         /* Ensure that nsupdate exists */

+         errno = 0;

+         ret = stat(NSUPDATE_PATH, &stat_buf);

+         if (ret == -1) {

+             err = errno;

+             if (err == ENOENT) {

+                 DEBUG(0, ("%s does not exist. Dynamic DNS updates disabled\n",

+                           NSUPDATE_PATH));

+             }

+             else {

+                 DEBUG(0, ("Could not set up dynamic DNS updates: [%d][%s]\n",

+                           err, strerror(err)));

+             }

+         }

+         else {

+             /* nsupdate is available. Dynamic updates

+              * are supported

+              */

+             ret = be_add_online_cb(ctx, ctx->be,

+                                    ipa_dyndns_update,

+                                    ipa_options, NULL);

+             if (ret != EOK) {

+                 DEBUG(1,("Failure setting up automatic DNS update\n"));

+                 /* We will continue without DNS updating */

+             }

+         }

+     }

+ 

+ 

+ 

      ret = setup_tls_config(ctx->opts->basic);

      if (ret != EOK) {

          DEBUG(1, ("setup_tls_config failed [%d][%s].\n",
@@ -135,6 +185,13 @@

          goto done;

      }

  

+     ret = be_add_offline_cb(ctx, bectx, sdap_gsh_disconnect_callback, ctx,

+                             NULL);

+     if (ret != EOK) {

+         DEBUG(1, ("be_add_offline_cb failed.\n"));

+         goto done;

+     }

+ 

      ret = sdap_id_setup_tasks(ctx);

      if (ret != EOK) {

          goto done;
@@ -162,8 +219,9 @@

                         struct bet_ops **ops,

                         void **pvt_data)

  {

-     struct krb5_ctx *ctx;

-     struct tevent_signal *sige;

+     struct ipa_auth_ctx *ipa_auth_ctx;

+     struct krb5_ctx *krb5_auth_ctx;

+     struct sdap_auth_ctx *sdap_auth_ctx;

      FILE *debug_filep;

      unsigned v;

      int ret;
@@ -182,33 +240,81 @@

          return EOK;

      }

  

-     ctx = talloc_zero(bectx, struct krb5_ctx);

-     if (!ctx) {

+     ipa_auth_ctx = talloc_zero(ipa_options, struct ipa_auth_ctx);

+     if (!ipa_auth_ctx) {

          return ENOMEM;

      }

-     ctx->service = ipa_options->service->krb5_service;

-     ipa_options->auth_ctx = ctx;

+     ipa_options->auth_ctx = ipa_auth_ctx;

  

-     ret = ipa_get_auth_options(ipa_options, bectx->cdb,

-                                bectx->conf_path,

-                                &ctx->opts);

+     ret = dp_copy_options(ipa_auth_ctx, ipa_options->basic,

+                           IPA_OPTS_BASIC, &ipa_auth_ctx->ipa_options);

      if (ret != EOK) {

+         DEBUG(1, ("dp_copy_options failed.\n"));

+         goto done;

+     }

+ 

+     krb5_auth_ctx = talloc_zero(ipa_auth_ctx, struct krb5_ctx);

+     if (!krb5_auth_ctx) {

+         ret = ENOMEM;

          goto done;

      }

+     krb5_auth_ctx->service = ipa_options->service->krb5_service;

+     ipa_options->auth_ctx->krb5_auth_ctx = krb5_auth_ctx;

  

-     ret = check_and_export_options(ctx->opts, bectx->domain);

+     ret = ipa_get_auth_options(ipa_options, bectx->cdb, bectx->conf_path,

+                                &krb5_auth_ctx->opts);

      if (ret != EOK) {

-         DEBUG(1, ("check_and_export_opts failed.\n"));

          goto done;

      }

  

-     sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO,

-                              child_sig_handler, NULL);

-     if (sige == NULL) {

-         DEBUG(1, ("tevent_add_signal failed.\n"));

+     sdap_auth_ctx = talloc_zero(ipa_auth_ctx, struct sdap_auth_ctx);

+     if (!sdap_auth_ctx) {

          ret = ENOMEM;

          goto done;

      }

+     sdap_auth_ctx->be =  bectx;

+     sdap_auth_ctx->service = ipa_options->service->sdap;

+     ipa_options->auth_ctx->sdap_auth_ctx = sdap_auth_ctx;

+ 

+     ret = ipa_get_id_options(ipa_options, bectx->cdb, bectx->conf_path,

+                              &sdap_auth_ctx->opts);

+     if (ret != EOK) {

+         goto done;

+     }

+ 

+     ret = setup_tls_config(sdap_auth_ctx->opts->basic);

+     if (ret != EOK) {

+         DEBUG(1, ("setup_tls_config failed [%d][%s].\n",

+                   ret, strerror(ret)));

+         goto done;

+     }

+ 

+     if (dp_opt_get_bool(krb5_auth_ctx->opts, KRB5_STORE_PASSWORD_IF_OFFLINE)) {

+         ret = init_delayed_online_authentication(krb5_auth_ctx, bectx,

+                                                  bectx->ev);

+         if (ret != EOK) {

+             DEBUG(1, ("init_delayed_online_authentication failed.\n"));

+             goto done;

+         }

+     }

+ 

+     ret = check_and_export_options(krb5_auth_ctx->opts, bectx->domain);

+     if (ret != EOK) {

+         DEBUG(1, ("check_and_export_opts failed.\n"));

+         goto done;

+     }

+ 

+     ret = krb5_install_offline_callback(bectx, krb5_auth_ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("krb5_install_offline_callback failed.\n"));

+         goto done;

+     }

+ 

+     ret = krb5_install_sigterm_handler(bectx->ev, krb5_auth_ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("krb5_install_sigterm_handler failed.\n"));

+         goto done;

+     }

  

      if (debug_to_file != 0) {

          ret = open_debug_file_ex("krb5_child", &debug_filep);
@@ -218,19 +324,19 @@

              goto done;

          }

  

-         ctx->child_debug_fd = fileno(debug_filep);

-         if (ctx->child_debug_fd == -1) {

+         krb5_auth_ctx->child_debug_fd = fileno(debug_filep);

+         if (krb5_auth_ctx->child_debug_fd == -1) {

              DEBUG(0, ("fileno failed [%d][%s]\n", errno, strerror(errno)));

              ret = errno;

              goto done;

          }

  

-         v = fcntl(ctx->child_debug_fd, F_GETFD, 0);

-         fcntl(ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC);

+         v = fcntl(krb5_auth_ctx->child_debug_fd, F_GETFD, 0);

+         fcntl(krb5_auth_ctx->child_debug_fd, F_SETFD, v & ~FD_CLOEXEC);

      }

  

      *ops = &ipa_auth_ops;

-     *pvt_data = ctx;

+     *pvt_data = ipa_auth_ctx;

      ret = EOK;

  

  done:
@@ -263,9 +369,9 @@

          return ENOMEM;

      }

  

-     ret = sssm_ipa_init(bectx, ops, (void **) &ipa_access_ctx->sdap_ctx);

+     ret = sssm_ipa_id_init(bectx, ops, (void **) &ipa_access_ctx->sdap_ctx);

      if (ret != EOK) {

-         DEBUG(1, ("sssm_ipa_init failed.\n"));

+         DEBUG(1, ("sssm_ipa_id_init failed.\n"));

          goto done;

      }

  

@@ -706,7 +706,7 @@

          JMP_NEOK(ret);

          ret = copy_substring(mpctx, str, "interval_day", &match);

          JMP_NEOK(ret);

-         BUFFER_OR_JUMP(ctx, per->day_of_month, DAY_OF_MONTH_BUFSIZE);

+         BUFFER_OR_JUMP(per, per->day_of_month, DAY_OF_MONTH_BUFSIZE);

          ret = interval2bitfield(mpctx, per->day_of_month, match,

                                  1, DAY_OF_MONTH_MAX, NULL);

          JMP_NEOK(ret);
@@ -754,7 +754,7 @@

      if (ret == EOK) {

          ret = copy_substring(ypctx, str, "day_of_year", &match);

          JMP_NEOK(ret);

-         BUFFER_OR_JUMP(ypctx, per->day_of_year, DAY_OF_YEAR_BUFSIZE);

+         BUFFER_OR_JUMP(per, per->day_of_year, DAY_OF_YEAR_BUFSIZE);

          ret = interval2bitfield(ypctx, per->day_of_year, match,

                                  1, DAY_OF_YEAR_MAX, NULL);

          JMP_NEOK(ret);
@@ -766,7 +766,7 @@

      if (ret == EOK) {

          ret = copy_substring(ypctx, str, "week_of_year", &match);

          JMP_NEOK(ret);

-         BUFFER_OR_JUMP(ypctx, per->week_of_year, WEEK_OF_YEAR_BUFSIZE);

+         BUFFER_OR_JUMP(per, per->week_of_year, WEEK_OF_YEAR_BUFSIZE);

          ret = interval2bitfield(ypctx, per->week_of_year, match,

                                  1, WEEK_OF_YEAR_MAX, NULL);

          JMP_NEOK(ret);
@@ -787,7 +787,7 @@

      talloc_free(match);

      ret = copy_substring(ypctx, str, "month_number", &match);

      JMP_NEOK(ret);

-     BUFFER_OR_JUMP(ypctx, per->month, MONTH_BUFSIZE);

+     BUFFER_OR_JUMP(per, per->month, MONTH_BUFSIZE);

      ret = interval2bitfield(ypctx, per->month, match,

                              1, MONTH_MAX, names_months);

      JMP_NEOK(ret);

file modified
+703 -446
@@ -6,7 +6,7 @@

      Authors:

          Sumit Bose <sbose@redhat.com>

  

-     Copyright (C) 2009 Red Hat

+     Copyright (C) 2009-2010 Red Hat

  

      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
@@ -45,72 +45,47 @@

  #define KRB5_CHILD SSSD_LIBEXEC_PATH"/krb5_child"

  #endif

  

- static errno_t add_krb5_env(struct dp_option *opts, const char *ccname,

-                             struct pam_data *pd)

+ static errno_t safe_remove_old_ccache_file(const char *old_ccache_file,

+                                            const char *new_ccache_file)

  {

      int ret;

-     const char *dummy;

-     char *env;

-     TALLOC_CTX *tmp_ctx = NULL;

+     size_t old_offset = 0;

+     size_t new_offset = 0;

  

-     tmp_ctx = talloc_new(NULL);

-     if (tmp_ctx == NULL) {

-         DEBUG(1, ("talloc_new failed.\n"));

-         return ENOMEM;

+     if (new_ccache_file == NULL) {

+         DEBUG(1, ("Missing new ccache file, "

+                   "old ccache file is not deleted.\n"));

+         return EINVAL;

      }

  

-     if (ccname != NULL) {

-         env = talloc_asprintf(tmp_ctx, "%s=%s",CCACHE_ENV_NAME, ccname);

-         if (env == NULL) {

-             DEBUG(1, ("talloc_asprintf failed.\n"));

-             ret = ENOMEM;

-             goto done;

+     if (old_ccache_file != NULL) {

+         if (strncmp(old_ccache_file, "FILE:", 5) == 0) {

+             old_offset = 5;

          }

-         ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env)+1,

-                                (uint8_t *) env);

-         if (ret != EOK) {

-             DEBUG(1, ("pam_add_response failed.\n"));

-             goto done;

+         if (strncmp(new_ccache_file, "FILE:", 5) == 0) {

+             new_offset = 5;

          }

-     }

- 

-     dummy = dp_opt_get_cstring(opts, KRB5_REALM);

-     if (dummy != NULL) {

-         env = talloc_asprintf(tmp_ctx, "%s=%s", SSSD_KRB5_REALM, dummy);

-         if (env == NULL) {

-             DEBUG(1, ("talloc_asprintf failed.\n"));

-             ret = ENOMEM;

-             goto done;

+         if (strcmp(old_ccache_file + old_offset,

+                    new_ccache_file + new_offset) == 0) {

+             DEBUG(7, ("New and old ccache file are the same, "

+                       "no one will be deleted.\n"));

+             return EOK;

          }

-         ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env)+1,

-                                (uint8_t *) env);

-         if (ret != EOK) {

-             DEBUG(1, ("pam_add_response failed.\n"));

-             goto done;

+         if (old_ccache_file[old_offset] != '/') {

+             DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n",

+                       old_ccache_file + old_offset));

+             return EINVAL;

          }

-     }

- 

-     dummy = dp_opt_get_cstring(opts, KRB5_KDC);

-     if (dummy != NULL) {

-         env = talloc_asprintf(tmp_ctx, "%s=%s", SSSD_KRB5_KDC, dummy);

-         if (env == NULL) {

-             DEBUG(1, ("talloc_asprintf failed.\n"));

-             ret = ENOMEM;

-             goto done;

-         }

-         ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env)+1,

-                                (uint8_t *) env);

-         if (ret != EOK) {

-             DEBUG(1, ("pam_add_response failed.\n"));

-             goto done;

+         ret = unlink(old_ccache_file + old_offset);

+         if (ret == -1 && errno != ENOENT) {

+             ret = errno;

+             DEBUG(1, ("unlink [%s] failed [%d][%s].\n", old_ccache_file, ret,

+                                                         strerror(ret)));

+             return ret;

          }

      }

  

-     ret = EOK;

- 

- done:

-     talloc_free(tmp_ctx);

-     return ret;

+     return EOK;

  }

  

  static errno_t check_if_ccache_file_is_used(uid_t uid, const char *ccname,
@@ -385,13 +360,59 @@

  

  static void krb_reply(struct be_req *req, int dp_err, int result);

  

+ static int krb5_cleanup(void *ptr)

+ {

+     struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);

+ 

+     if (kr == NULL) return EOK;

+ 

+     child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd);

+     memset(kr, 0, sizeof(struct krb5child_req));

+ 

+     return EOK;

+ }

+ 

+ static errno_t krb5_setup(TALLOC_CTX *mem_ctx, struct pam_data *pd,

+                           struct krb5_ctx *krb5_ctx,

+                           struct krb5child_req **krb5_req)

+ {

+     struct krb5child_req *kr = NULL;

+ 

+     kr = talloc_zero(mem_ctx, struct krb5child_req);

+     if (kr == NULL) {

+         DEBUG(1, ("talloc failed.\n"));

+         return ENOMEM;

+     }

+     kr->read_from_child_fd = -1;

+     kr->write_to_child_fd = -1;

+     kr->is_offline = false;

+     kr->active_ccache_present = true;

+     talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);

+ 

+     kr->pd = pd;

+     kr->krb5_ctx = krb5_ctx;

+ 

+     *krb5_req = kr;

+ 

+     return EOK;

+ 

+ }

+ 

+ struct handle_child_state {

+     struct tevent_context *ev;

+     struct krb5child_req *kr;

+     uint8_t *buf;

+     ssize_t len;

+ };

+ 

  static void krb5_child_timeout(struct tevent_context *ev,

                                 struct tevent_timer *te,

                                 struct timeval tv, void *pvt)

  {

-     struct krb5child_req *kr = talloc_get_type(pvt, struct krb5child_req);

-     struct be_req *be_req = kr->req;

-     struct pam_data *pd = kr->pd;

+     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);

+     struct handle_child_state *state = tevent_req_data(req,

+                                                      struct handle_child_state);

+     struct krb5child_req *kr = state->kr;

      int ret;

  

      if (kr->timeout_handler == NULL) {
@@ -405,25 +426,24 @@

          DEBUG(1, ("kill failed [%d][%s].\n", errno, strerror(errno)));

      }

  

-     talloc_zfree(kr);

- 

-     pd->pam_status = PAM_AUTHINFO_UNAVAIL;

-     be_mark_offline(be_req->be_ctx);

- 

-     krb_reply(be_req, DP_ERR_OFFLINE, pd->pam_status);

+     tevent_req_error(req, ETIMEDOUT);

  }

  

- static errno_t activate_child_timeout_handler(struct krb5child_req *kr)

+ static errno_t activate_child_timeout_handler(struct tevent_req *req,

+                                               struct tevent_context *ev,

+                                               struct krb5child_req *kr)

  {

      struct timeval tv;

+     struct handle_child_state *state = tevent_req_data(req,

+                                                     struct handle_child_state);

  

      tv = tevent_timeval_current();

      tv = tevent_timeval_add(&tv,

                              dp_opt_get_int(kr->krb5_ctx->opts,

                                             KRB5_AUTH_TIMEOUT),

                              0);

-     kr->timeout_handler = tevent_add_timer(kr->req->be_ctx->ev, kr, tv,

-                                            krb5_child_timeout, kr);

+     kr->timeout_handler = tevent_add_timer(ev, state, tv,

+                                            krb5_child_timeout, req);

      if (kr->timeout_handler == NULL) {

          DEBUG(1, ("tevent_add_timer failed.\n"));

          return ENOMEM;
@@ -432,61 +452,8 @@

      return EOK;

  }

  

- static int krb5_cleanup(void *ptr)

- {

-     struct krb5child_req *kr = talloc_get_type(ptr, struct krb5child_req);

- 

-     if (kr == NULL) return EOK;

- 

-     child_cleanup(kr->read_from_child_fd, kr->write_to_child_fd);

-     memset(kr, 0, sizeof(struct krb5child_req));

- 

-     return EOK;

- }

- 

- static errno_t krb5_setup(struct be_req *req, struct krb5child_req **krb5_req)

- {

-     struct krb5child_req *kr = NULL;

-     struct krb5_ctx *krb5_ctx;

-     struct pam_data *pd;

-     errno_t err;

- 

-     pd = talloc_get_type(req->req_data, struct pam_data);

- 

-     krb5_ctx = get_krb5_ctx(req);

-     if (krb5_ctx == NULL) {

-         DEBUG(1, ("Kerberos context not available.\n"));

-         err = EINVAL;

-         goto failed;

-     }

- 

-     kr = talloc_zero(req, struct krb5child_req);

-     if (kr == NULL) {

-         DEBUG(1, ("talloc failed.\n"));

-         err = ENOMEM;

-         goto failed;

-     }

-     kr->read_from_child_fd = -1;

-     kr->write_to_child_fd = -1;

-     kr->is_offline = false;

-     kr->active_ccache_present = true;

-     talloc_set_destructor((TALLOC_CTX *) kr, krb5_cleanup);

- 

-     kr->pd = pd;

-     kr->req = req;

-     kr->krb5_ctx = krb5_ctx;

- 

-     *krb5_req = kr;

- 

-     return EOK;

- 

- failed:

-     talloc_zfree(kr);

- 

-     return err;

- }

- 

- static errno_t fork_child(struct krb5child_req *kr)

+ static errno_t fork_child(struct tevent_req *req, struct tevent_context *ev,

+                           struct krb5child_req *kr)

  {

      int pipefd_to_child[2];

      int pipefd_from_child[2];
@@ -513,10 +480,10 @@

          /* We need to keep the root privileges to read the keytab file if

           * validation is enabled, otherwise we can drop them here and run

           * krb5_child with user privileges.

-          * If authtok_size is zero we are offline and want to create an empty

-          * ccache file. In this case we can drop the privileges, too. */

+          * If we are offline and want to create an empty ccache file. In this

+          * case we can drop the privileges, too. */

          if (!dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ||

-             kr->pd->authtok_size == 0) {

+             kr->is_offline) {

              ret = become_user(kr->uid, kr->gid);

              if (ret != EOK) {

                  DEBUG(1, ("become_user failed.\n"));
@@ -541,7 +508,13 @@

          fd_nonblocking(kr->read_from_child_fd);

          fd_nonblocking(kr->write_to_child_fd);

  

-         err = activate_child_timeout_handler(kr);

+         ret = child_handler_setup(ev, pid, NULL, NULL);

+         if (ret != EOK) {

+             DEBUG(1, ("Could not set up child signal handler\n"));

+             return ret;

+         }

+ 

+         err = activate_child_timeout_handler(req, ev, kr);

          if (err != EOK) {

              DEBUG(1, ("activate_child_timeout_handler failed.\n"));

          }
@@ -555,13 +528,6 @@

      return EOK;

  }

  

- struct handle_child_state {

-     struct tevent_context *ev;

-     struct krb5child_req *kr;

-     uint8_t *buf;

-     ssize_t len;

- };

- 

  static void handle_child_step(struct tevent_req *subreq);

  static void handle_child_done(struct tevent_req *subreq);

  
@@ -590,7 +556,7 @@

          goto fail;

      }

  

-     ret = fork_child(kr);

+     ret = fork_child(req, ev, kr);

      if (ret != EOK) {

          DEBUG(1, ("fork_child failed.\n"));

          goto fail;
@@ -675,54 +641,109 @@

      return EOK;

  }

  

- static void get_user_attr_done(void *pvt, int err, struct ldb_result *res);

+ static void krb5_get_user_attr_done(struct tevent_req *req);

  static void krb5_resolve_kdc_done(struct tevent_req *req);

  static void krb5_resolve_kpasswd_done(struct tevent_req *req);

- static void krb5_find_ccache_step(struct krb5child_req *kr);

+ static void krb5_find_ccache_step(struct tevent_req *req);

  static void krb5_save_ccname_done(struct tevent_req *req);

  static void krb5_child_done(struct tevent_req *req);

  static void krb5_pam_handler_cache_done(struct tevent_req *treq);

+ static void krb5_pam_handler_cache_auth_done(struct tevent_req *subreq);

  

- void krb5_pam_handler(struct be_req *be_req)

- {

+ struct krb5_auth_state {

+     struct tevent_context *ev;

+     struct be_ctx *be_ctx;

      struct pam_data *pd;

+     struct krb5_ctx *krb5_ctx;

+     struct krb5child_req *kr;

+ 

+     int pam_status;

+     int dp_err;

+ };

+ 

+ int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err)

+ {

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+ 

+     *pam_status = state->pam_status;

+     *dp_err = state->dp_err;

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,

+                                   struct tevent_context *ev,

+                                   struct be_ctx *be_ctx,

+                                   struct pam_data *pd,

+                                   struct krb5_ctx *krb5_ctx)

+ {

      const char **attrs;

-     int pam_status = PAM_SYSTEM_ERR;

-     int dp_err = DP_ERR_FATAL;

      int ret;

+     struct krb5_auth_state *state;

+     struct tevent_req *req;

+     struct tevent_req *subreq;

  

-     pd = talloc_get_type(be_req->req_data, struct pam_data);

  

-     switch (pd->cmd) {

+     req = tevent_req_create(mem_ctx, &state, struct krb5_auth_state);

+     if (req == NULL) {

+         DEBUG(1, ("tevent_req_create failed.\n"));

+         return NULL;

+     }

+ 

+     state->ev = ev;

+     state->be_ctx = be_ctx;

+     state->pd = pd;

+     state->krb5_ctx = krb5_ctx;

+     state->kr = NULL;

+     state->pam_status = PAM_SYSTEM_ERR;

+     state->dp_err = DP_ERR_FATAL;

+ 

+ 

+     switch (state->pd->cmd) {

          case SSS_PAM_AUTHENTICATE:

          case SSS_PAM_CHAUTHTOK:

+             break;

          case SSS_PAM_CHAUTHTOK_PRELIM:

+             if (state->pd->priv == 1 && state->pd->authtok_size == 0) {

+                 DEBUG(4, ("Password reset by root is not supported.\n"));

+                 state->pam_status = PAM_PERM_DENIED;

+                 state->dp_err = DP_ERR_OK;

+                 ret = EOK;

+                 goto done;

+             }

              break;

          case SSS_PAM_ACCT_MGMT:

          case SSS_PAM_SETCRED:

          case SSS_PAM_OPEN_SESSION:

          case SSS_PAM_CLOSE_SESSION:

-             pam_status = PAM_SUCCESS;

-             dp_err = DP_ERR_OK;

+             state->pam_status = PAM_SUCCESS;

+             state->dp_err = DP_ERR_OK;

+             ret = EOK;

              goto done;

              break;

          default:

-             DEBUG(4, ("krb5 does not handles pam task %d.\n", pd->cmd));

-             pam_status = PAM_MODULE_UNKNOWN;

-             dp_err = DP_ERR_OK;

+             DEBUG(4, ("krb5 does not handles pam task %d.\n", state->pd->cmd));

+             state->pam_status = PAM_MODULE_UNKNOWN;

+             state->dp_err = DP_ERR_OK;

+             ret = EOK;

              goto done;

      }

  

-     if (be_is_offline(be_req->be_ctx) &&

-         (pd->cmd == SSS_PAM_CHAUTHTOK || pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {

+     if (be_is_offline(be_ctx) &&

+         (state->pd->cmd == SSS_PAM_CHAUTHTOK ||

+          state->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM)) {

          DEBUG(9, ("Password changes are not possible while offline.\n"));

-         pam_status = PAM_AUTHINFO_UNAVAIL;

-         dp_err = DP_ERR_OFFLINE;

+         state->pam_status = PAM_AUTHINFO_UNAVAIL;

+         state->dp_err = DP_ERR_OFFLINE;

+         ret = EOK;

          goto done;

      }

  

-     attrs = talloc_array(be_req, const char *, 6);

+     attrs = talloc_array(state, const char *, 6);

      if (attrs == NULL) {

+         ret = ENOMEM;

          goto done;

      }

  
@@ -733,253 +754,251 @@

      attrs[4] = SYSDB_GIDNUM;

      attrs[5] = NULL;

  

-     ret = sysdb_get_user_attr(be_req, be_req->be_ctx->sysdb,

-                               be_req->be_ctx->domain, pd->user, attrs,

-                               get_user_attr_done, be_req);

+     ret = krb5_setup(state, pd, krb5_ctx, &state->kr);

+     if (ret != EOK) {

+         DEBUG(1, ("krb5_setup failed.\n"));

+         goto done;

+     }

  

-     if (ret) {

+     subreq = sysdb_search_user_by_name_send(state, state->ev, be_ctx->sysdb,

+                                             NULL, be_ctx->domain,

+                                             state->pd->user, attrs);

+     if (subreq == NULL) {

+         DEBUG(1, ("sysdb_search_user_by_name_send failed.\n"));

+         ret = ENOMEM;

          goto done;

      }

  

-     return;

+     tevent_req_set_callback(subreq, krb5_get_user_attr_done, req);

  

- done:

-     pd->pam_status = pam_status;

+     return req;

  

-     krb_reply(be_req, dp_err, pd->pam_status);

+ done:

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else {

+         tevent_req_error(req, ret);

+     }

+     tevent_req_post(req, state->ev);

+     return req;

  }

  

- static void get_user_attr_done(void *pvt, int err, struct ldb_result *res)

+ static void krb5_get_user_attr_done(struct tevent_req *subreq)

  {

-     struct be_req *be_req = talloc_get_type(pvt, struct be_req);

-     struct krb5_ctx *krb5_ctx;

-     struct krb5child_req *kr = NULL;

-     struct tevent_req *req;

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+     struct krb5_ctx *krb5_ctx = state->kr->krb5_ctx;

      krb5_error_code kerr;

      int ret;

-     struct pam_data *pd = talloc_get_type(be_req->req_data, struct pam_data);

-     int pam_status = PAM_SYSTEM_ERR;

-     int dp_err = DP_ERR_FATAL;

+     struct pam_data *pd = state->pd;

+     struct krb5child_req *kr =state->kr;

      const char *ccache_file = NULL;

      const char *realm;

+     struct ldb_message *msg;

  

-     ret = krb5_setup(be_req, &kr);

-     if (ret != EOK) {

-         DEBUG(1, ("krb5_setup failed.\n"));

-         goto failed;

-     }

- 

-     krb5_ctx = kr->krb5_ctx;

- 

-     if (err != LDB_SUCCESS) {

-         DEBUG(5, ("sysdb search for upn of user [%s] failed.\n", pd->user));

-         goto failed;

+     ret = sysdb_search_user_recv(subreq, state, &msg);

+     talloc_zfree(subreq);

+     if (ret) {

+         state->pam_status = PAM_SYSTEM_ERR;

+         state->dp_err = DP_ERR_OK;

+         tevent_req_error(req, ret);

+         return;

      }

  

      realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);

      if (realm == NULL) {

          DEBUG(1, ("Missing Kerberos realm.\n"));

+         ret = ENOENT;

          goto failed;

      }

  

-     switch (res->count) {

-     case 0:

-         DEBUG(5, ("No attributes for user [%s] found.\n", pd->user));

-         goto failed;

-         break;

- 

-     case 1:

-         kr->upn = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_UPN, NULL);

+     kr->upn = ldb_msg_find_attr_as_string(msg, SYSDB_UPN, NULL);

+     if (kr->upn == NULL) {

+         /* NOTE: this is a hack, works only in some environments */

+         kr->upn = talloc_asprintf(kr, "%s@%s", pd->user, realm);

          if (kr->upn == NULL) {

-             /* NOTE: this is a hack, works only in some environments */

-             kr->upn = talloc_asprintf(be_req, "%s@%s", pd->user, realm);

-             if (kr->upn == NULL) {

-                 DEBUG(1, ("failed to build simple upn.\n"));

-                 goto failed;

-             }

-             DEBUG(9, ("Using simple UPN [%s].\n", kr->upn));

+             DEBUG(1, ("failed to build simple upn.\n"));

+             ret = ENOMEM;

+             goto failed;

          }

+         DEBUG(9, ("Using simple UPN [%s].\n", kr->upn));

+     }

  

-         kr->homedir = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_HOMEDIR,

-                                                   NULL);

-         if (kr->homedir == NULL) {

-             DEBUG(4, ("Home directory for user [%s] not known.\n", pd->user));

-         }

+     kr->homedir = ldb_msg_find_attr_as_string(msg, SYSDB_HOMEDIR, NULL);

+     if (kr->homedir == NULL) {

+         DEBUG(4, ("Home directory for user [%s] not known.\n", pd->user));

+     }

+ 

+     kr->uid = ldb_msg_find_attr_as_uint64(msg, SYSDB_UIDNUM, 0);

+     if (kr->uid == 0) {

+         DEBUG(4, ("UID for user [%s] not known.\n", pd->user));

+         ret = ENOENT;

+         goto failed;

+     }

  

-         kr->uid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_UIDNUM, 0);

-         if (kr->uid == 0) {

-             DEBUG(4, ("UID for user [%s] not known.\n", pd->user));

+     kr->gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);

+     if (kr->gid == 0) {

+         DEBUG(4, ("GID for user [%s] not known.\n", pd->user));

+         ret = ENOENT;

+         goto failed;

+     }

+ 

+     ccache_file = ldb_msg_find_attr_as_string(msg, SYSDB_CCACHE_FILE, NULL);

+     if (ccache_file != NULL) {

+         ret = check_if_ccache_file_is_used(kr->uid, ccache_file,

+                                            &kr->active_ccache_present);

+         if (ret != EOK) {

+             DEBUG(1, ("check_if_ccache_file_is_used failed.\n"));

              goto failed;

          }

  

-         kr->gid = ldb_msg_find_attr_as_uint64(res->msgs[0], SYSDB_GIDNUM, 0);

-         if (kr->gid == 0) {

-             DEBUG(4, ("GID for user [%s] not known.\n", pd->user));

+         kerr = check_for_valid_tgt(ccache_file, realm, kr->upn,

+                                    &kr->valid_tgt_present);

+         if (kerr != 0) {

+             DEBUG(1, ("check_for_valid_tgt failed.\n"));

+             ret = kerr;

              goto failed;

          }

+     } else {

+         kr->active_ccache_present = false;

+         kr->valid_tgt_present = false;

+         DEBUG(4, ("No ccache file for user [%s] found.\n", pd->user));

+     }

+     DEBUG(9, ("Ccache_file is [%s] and is %s active and TGT is %s valid.\n",

+               ccache_file ? ccache_file : "not set",

+               kr->active_ccache_present ? "" : "not",

+               kr->valid_tgt_present ? "" : "not"));

  

-         ccache_file = ldb_msg_find_attr_as_string(res->msgs[0],

-                                                   SYSDB_CCACHE_FILE,

-                                                   NULL);

-         if (ccache_file != NULL) {

-             ret = check_if_ccache_file_is_used(kr->uid, ccache_file,

-                                                &kr->active_ccache_present);

-             if (ret != EOK) {

-                 DEBUG(1, ("check_if_ccache_file_is_used failed.\n"));

-                 goto failed;

-             }

- 

-             kerr = check_for_valid_tgt(ccache_file, realm, kr->upn,

-                                        &kr->valid_tgt_present);

-             if (kerr != 0) {

-                 DEBUG(1, ("check_for_valid_tgt failed.\n"));

-                 goto failed;

-             }

-         } else {

-             kr->active_ccache_present = false;

-             kr->valid_tgt_present = false;

-             DEBUG(4, ("No ccache file for user [%s] found.\n", pd->user));

-         }

-         DEBUG(9, ("Ccache_file is [%s] and is %s active and TGT is %s valid.\n",

-                   ccache_file ? ccache_file : "not set",

-                   kr->active_ccache_present ? "" : "not",

-                   kr->valid_tgt_present ? "" : "not"));

+     if (ccache_file != NULL) {

          kr->ccname = ccache_file;

-         break;

- 

-     default:

-         DEBUG(1, ("A user search by name (%s) returned > 1 results!\n",

-                   pd->user));

-         goto failed;

-         break;

+         kr->old_ccname = talloc_strdup(kr, ccache_file);

+         if (kr->old_ccname == NULL) {

+             DEBUG(1, ("talloc_strdup failed.\n"));

+             ret = ENOMEM;

+             goto failed;

+         }

+     } else {

+         kr->ccname = NULL;

+         kr->old_ccname = NULL;

      }

  

      kr->srv = NULL;

      kr->kpasswd_srv = NULL;

-     req = be_resolve_server_send(kr, be_req->be_ctx->ev, be_req->be_ctx,

-                                  krb5_ctx->service->name);

-     if (req == NULL) {

+     subreq = be_resolve_server_send(state, state->ev, state->be_ctx,

+                                     krb5_ctx->service->name);

+     if (subreq == NULL) {

          DEBUG(1, ("be_resolve_server_send failed.\n"));

+         ret = ENOMEM;

          goto failed;

      }

  

-     tevent_req_set_callback(req, krb5_resolve_kdc_done, kr);

+     tevent_req_set_callback(subreq, krb5_resolve_kdc_done, req);

  

      return;

  

  failed:

-     talloc_free(kr);

- 

-     pd->pam_status = pam_status;

-     krb_reply(be_req, dp_err, pd->pam_status);

+     tevent_req_error(req, ret);

  }

  

- static void krb5_resolve_kdc_done(struct tevent_req *req)

+ static void krb5_resolve_kdc_done(struct tevent_req *subreq)

  {

-     struct krb5child_req *kr = tevent_req_callback_data(req,

-                                                         struct krb5child_req);

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+     struct krb5child_req *kr = state->kr;

      int ret;

-     struct pam_data *pd = kr->pd;

-     struct be_req *be_req = kr->req;

  

-     ret = be_resolve_server_recv(req, &kr->srv);

-     talloc_zfree(req);

+     ret = be_resolve_server_recv(subreq, &kr->srv);

+     talloc_zfree(subreq);

      if (ret) {

          /* all servers have been tried and none

           * was found good, setting offline,

           * but we still have to call the child to setup

           * the ccache file. */

-         be_mark_offline(be_req->be_ctx);

+         be_mark_offline(state->be_ctx);

          kr->is_offline = true;

      } else {

-         if (pd->cmd == SSS_PAM_CHAUTHTOK &&

+         if (state->pd->cmd == SSS_PAM_CHAUTHTOK &&

              kr->krb5_ctx->kpasswd_service != NULL) {

-             req = be_resolve_server_send(kr, be_req->be_ctx->ev, be_req->be_ctx,

-                                          kr->krb5_ctx->kpasswd_service->name);

-             if (req == NULL) {

+             subreq = be_resolve_server_send(state, state->ev, state->be_ctx,

+                                             kr->krb5_ctx->kpasswd_service->name);

+             if (subreq == NULL) {

                  DEBUG(1, ("be_resolve_server_send failed.\n"));

+                 ret = ENOMEM;

                  goto failed;

              }

  

-             tevent_req_set_callback(req, krb5_resolve_kpasswd_done, kr);

+             tevent_req_set_callback(subreq, krb5_resolve_kpasswd_done, req);

  

              return;

          }

      }

  

-     krb5_find_ccache_step(kr);

+     krb5_find_ccache_step(req);

      return;

  

  failed:

-     talloc_free(kr);

- 

-     pd->pam_status = PAM_SYSTEM_ERR;

-     krb_reply(be_req, DP_ERR_FATAL, pd->pam_status);

+     tevent_req_error(req, ret);

  }

  

- static void krb5_resolve_kpasswd_done(struct tevent_req *req)

+ static void krb5_resolve_kpasswd_done(struct tevent_req *subreq)

  {

-     struct krb5child_req *kr = tevent_req_callback_data(req,

-                                                         struct krb5child_req);

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

      int ret;

-     struct pam_data *pd = kr->pd;

-     struct be_req *be_req = kr->req;

  

-     ret = be_resolve_server_recv(req, &kr->kpasswd_srv);

-     talloc_zfree(req);

+     ret = be_resolve_server_recv(subreq, &state->kr->kpasswd_srv);

+     talloc_zfree(subreq);

      if (ret) {

          /* all kpasswd servers have been tried and none was found good, but the

           * kdc seems ok. Password changes are not possible but

           * authentication. We return an PAM error here, but do not mark the

           * backend offline. */

- 

-         talloc_free(kr);

-         pd->pam_status = PAM_AUTHTOK_LOCK_BUSY;

-         krb_reply(be_req, DP_ERR_OK, pd->pam_status);

+         state->pam_status = PAM_AUTHTOK_LOCK_BUSY;

+         state->dp_err = DP_ERR_OK;

+         tevent_req_done(req);

+         return;

      }

  

-     krb5_find_ccache_step(kr);

+     krb5_find_ccache_step(req);

  }

  

- static void krb5_find_ccache_step(struct krb5child_req *kr)

+ static void krb5_find_ccache_step(struct tevent_req *req)

  {

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

      int ret;

-     int pam_status = PAM_SYSTEM_ERR;

-     int dp_err = DP_ERR_FATAL;

-     struct pam_data *pd = kr->pd;

-     struct be_req *be_req = kr->req;

+     struct krb5child_req *kr = state->kr;

+     struct pam_data *pd = state->pd;

      char *msg;

-     size_t offset = 0;

      bool private_path = false;

-     struct tevent_req *req = NULL;

- 

+     struct tevent_req *subreq = NULL;

+ 

+     if (!kr->is_offline) {

+         kr->is_offline = be_is_offline(state->be_ctx);

+     }

+ 

+     /* The ccache file should be (re)created if one of the following conditions

+      * is true:

+      * - it doesn't exist (kr->ccname == NULL)

+      * - the backend is online and the current ccache file is not used, i.e

+      *   the related user is currently not logged in

+      *   (!kr->is_offline && !kr->active_ccache_present)

+      * - the backend is offline and the current cache file not used and

+      *   it does not contain a valid tgt

+      *   (kr->is_offline &&

+      *    !kr->active_ccache_present && !kr->valid_tgt_present)

+      */

      if (kr->ccname == NULL ||

-         (be_is_offline(be_req->be_ctx) && !kr->active_ccache_present &&

+         (kr->is_offline && !kr->active_ccache_present &&

              !kr->valid_tgt_present) ||

-         (!be_is_offline(be_req->be_ctx) && !kr->active_ccache_present)) {

+         (!kr->is_offline && !kr->active_ccache_present)) {

              DEBUG(9, ("Recreating  ccache file.\n"));

-             if (kr->ccname != NULL) {

-                 if (strncmp(kr->ccname, "FILE:", 5) == 0) {

-                     offset = 5;

-                 }

-                 if (kr->ccname[offset] != '/') {

-                     DEBUG(1, ("Ccache file name [%s] is not an absolute path.\n",

-                               kr->ccname + offset));

-                     goto done;

-                 }

-                 ret = unlink(kr->ccname + offset);

-                 if (ret == -1 && errno != ENOENT) {

-                     DEBUG(1, ("unlink [%s] failed [%d][%s].\n", kr->ccname,

-                              errno, strerror(errno)));

-                     goto done;

-                 }

-             }

              kr->ccname = expand_ccname_template(kr, kr,

                                            dp_opt_get_cstring(kr->krb5_ctx->opts,

                                                               KRB5_CCNAME_TMPL),

                                                  true, &private_path);

              if (kr->ccname == NULL) {

                  DEBUG(1, ("expand_ccname_template failed.\n"));

+                 ret = ENOMEM;

                  goto done;

              }

  
@@ -992,235 +1011,385 @@

              }

      }

  

-     if (be_is_offline(be_req->be_ctx)) {

+     if (kr->is_offline) {

          DEBUG(9, ("Preparing for offline operation.\n"));

-         kr->is_offline = true;

  

-         if (kr->valid_tgt_present) {

-             DEBUG(9, ("Valid TGT available, nothing to do.\n"));

+         if (kr->valid_tgt_present || kr->active_ccache_present) {

+             DEBUG(9, ("Valid TGT available or "

+                       "ccache file is already in use.\n"));

+             kr->ccname = kr->old_ccname;

              msg = talloc_asprintf(pd, "%s=%s", CCACHE_ENV_NAME, kr->ccname);

              if (msg == NULL) {

                  DEBUG(1, ("talloc_asprintf failed.\n"));

-                 goto done;

+             } else {

+                 ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1,

+                                        (uint8_t *) msg);

+                 if (ret != EOK) {

+                     DEBUG(1, ("pam_add_response failed.\n"));

+                 }

              }

  

-             ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1,

-                                    (uint8_t *) msg);

-             if (ret != EOK) {

-                 DEBUG(1, ("pam_add_response failed.\n"));

+             if (dp_opt_get_bool(kr->krb5_ctx->opts,

+                                 KRB5_STORE_PASSWORD_IF_OFFLINE)) {

+                 subreq = sysdb_cache_auth_send(state, state->ev,

+                                                state->be_ctx->sysdb,

+                                                state->be_ctx->domain, pd->user,

+                                                pd->authtok, pd->authtok_size,

+                                                state->be_ctx->cdb, true);

+                 if (subreq == NULL) {

+                     DEBUG(2, ("sysdb_cache_auth_send failed, "

+                               "delayed online authentication not possible.\n"));

+                     /* This is not a fatal error, we continue with standard

+                      * offline authentication. */

+                 } else {

+                     tevent_req_set_callback(subreq,

+                                             krb5_pam_handler_cache_auth_done,

+                                             req);

+                     return;

+                 }

              }

  

-             pam_status = PAM_AUTHINFO_UNAVAIL;

-             dp_err = DP_ERR_OFFLINE;

+             state->pam_status = PAM_AUTHINFO_UNAVAIL;

+             state->dp_err = DP_ERR_OFFLINE;

+             ret = EOK;

              goto done;

          }

-         memset(pd->authtok, 0, pd->authtok_size);

-         pd->authtok_size = 0;

- 

-         if (kr->active_ccache_present) {

-             req = krb5_save_ccname_send(kr, be_req->be_ctx->ev,

-                                         be_req->be_ctx->sysdb,

-                                         be_req->be_ctx->domain, pd->user,

-                                         kr->ccname);

-             if (req == NULL) {

-                 DEBUG(1, ("krb5_save_ccname_send failed.\n"));

-                 goto done;

-             }

- 

-             tevent_req_set_callback(req, krb5_save_ccname_done, kr);

-             return;

-         }

      }

  

-     req = handle_child_send(kr, be_req->be_ctx->ev, kr);

-     if (req == NULL) {

+     subreq = handle_child_send(state, state->ev, kr);

+     if (subreq == NULL) {

          DEBUG(1, ("handle_child_send failed.\n"));

+         ret = ENOMEM;

          goto done;

      }

  

-     tevent_req_set_callback(req, krb5_child_done, kr);

+     tevent_req_set_callback(subreq, krb5_child_done, req);

      return;

  

  done:

-     talloc_free(kr);

-     pd->pam_status = pam_status;

-     krb_reply(be_req, dp_err, pd->pam_status);

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else {

+         tevent_req_error(req, ret);

+     }

  }

  

- static void krb5_child_done(struct tevent_req *req)

+ static struct tevent_req *krb5_next_server(struct tevent_req *req);

+ static struct tevent_req *krb5_next_kdc(struct tevent_req *req);

+ static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req);

+ 

+ static void krb5_child_done(struct tevent_req *subreq)

  {

-     struct krb5child_req *kr = tevent_req_callback_data(req,

-                                                         struct krb5child_req);

-     struct pam_data *pd = kr->pd;

-     struct be_req *be_req = kr->req;

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+ 

+     struct krb5child_req *kr = state->kr;

+     struct pam_data *pd = state->pd;

      int ret;

      uint8_t *buf = NULL;

      ssize_t len = -1;

      ssize_t pref_len;

-     int p;

-     int32_t *msg_status;

-     int32_t *msg_type;

-     int32_t *msg_len;

-     int pam_status = PAM_SYSTEM_ERR;

-     int dp_err = DP_ERR_FATAL;

- 

-     ret = handle_child_recv(req, pd, &buf, &len);

+     size_t p;

+     int32_t msg_status;

+     int32_t msg_type;

+     int32_t msg_len;

+ 

+     ret = handle_child_recv(subreq, pd, &buf, &len);

      talloc_zfree(kr->timeout_handler);

-     talloc_zfree(req);

+     talloc_zfree(subreq);

      if (ret != EOK) {

          DEBUG(1, ("child failed (%d [%s])\n", ret, strerror(ret)));

-         goto done;

+         if (ret == ETIMEDOUT) {

+             if (krb5_next_server(req) == NULL) {

+                 tevent_req_error(req, ENOMEM);

+             }

+         } else {

+             tevent_req_error(req, ret);

+         }

+         return;

      }

  

-     if ((size_t) len < 3*sizeof(int32_t)) {

+     /* A buffer with the following structure is expected.

+      * int32_t status of the request (required)

+      * message (zero or more)

+      *

+      * A message consists of:

+      * int32_t type of the message

+      * int32_t length of the following data

+      * uint8_t[len] data

+      */

+ 

+     if ((size_t) len < sizeof(int32_t)) {

          DEBUG(1, ("message too short.\n"));

+         ret = EINVAL;

          goto done;

      }

  

      p=0;

-     msg_status = ((int32_t *)(buf+p));

-     p += sizeof(int32_t);

+     SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);

  

-     msg_type = ((int32_t *)(buf+p));

-     p += sizeof(int32_t);

+     while (p < len) {

+         SAFEALIGN_COPY_INT32(&msg_type, buf+p, &p);

+         SAFEALIGN_COPY_INT32(&msg_len, buf+p, &p);

  

-     msg_len = ((int32_t *)(buf+p));

-     p += sizeof(int32_t);

+         DEBUG(9, ("child response [%d][%d][%d].\n", msg_status, msg_type,

+                                                     msg_len));

  

-     DEBUG(4, ("child response [%d][%d][%d].\n", *msg_status, *msg_type,

-                                                 *msg_len));

- 

-     if ((p + *msg_len) != len) {

-         DEBUG(1, ("message format error [%d] != [%d].\n", p+*msg_len, len));

-         goto done;

-     }

+         if ((p + msg_len) > len) {

+             DEBUG(1, ("message format error [%d] > [%d].\n", p+msg_len, len));

+             ret = EINVAL;

+             goto done;

+         }

  

-     if (*msg_status != PAM_SUCCESS && *msg_status != PAM_AUTHINFO_UNAVAIL) {

-         pam_status = *msg_status;

-         dp_err = DP_ERR_OK;

+         /* We need to save the name of the credential cache file. To find it

+          * we check if the data part of a message starts with

+          * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because

+          * sizeof() counts the trailing '\0' of a string. */

+         pref_len = sizeof(CCACHE_ENV_NAME);

+         if (msg_len > pref_len &&

+             strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) {

+             kr->ccname = talloc_strndup(kr, (char *) &buf[p+pref_len],

+                                         msg_len-pref_len);

+             if (kr->ccname == NULL) {

+                 DEBUG(1, ("talloc_strndup failed.\n"));

+                 ret = ENOMEM;

+                 goto done;

+             }

+         }

  

-         ret = pam_add_response(pd, *msg_type, *msg_len, &buf[p]);

+         ret = pam_add_response(pd, msg_type, msg_len, &buf[p]);

          if (ret != EOK) {

+             /* This is not a fatal error */

              DEBUG(1, ("pam_add_response failed.\n"));

          }

+         p += msg_len;

  

+         if ((p < len) && (p + 2*sizeof(int32_t) >= len)) {

+             DEBUG(1, ("The remainder of the message is too short.\n"));

+             ret = EINVAL;

+             goto done;

+         }

+     }

+ 

+     /* If the child request failed, but did not return an offline error code,

+      * return with the status */

+     if (msg_status != PAM_SUCCESS && msg_status != PAM_AUTHINFO_UNAVAIL &&

+         msg_status != PAM_AUTHTOK_LOCK_BUSY) {

+         state->pam_status = msg_status;

+         state->dp_err = DP_ERR_OK;

+         ret = EOK;

          goto done;

      } else {

-         pd->pam_status = *msg_status;

+         state->pam_status = msg_status;

      }

  

-     if (*msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {

-         pam_status = PAM_SUCCESS;

-         dp_err = DP_ERR_OK;

+     /* If the child request was successful and we run the first pass of the

+      * change password request just return success. */

+     if (msg_status == PAM_SUCCESS && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {

+         state->pam_status = PAM_SUCCESS;

+         state->dp_err = DP_ERR_OK;

+         ret = EOK;

          goto done;

      }

  

-     pref_len = strlen(CCACHE_ENV_NAME)+1;

-     if (*msg_len > pref_len &&

-         strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0) {

-         kr->ccname = talloc_strndup(kr, (char *) &buf[p+pref_len],

-                                    *msg_len-pref_len);

-         if (kr->ccname == NULL) {

-             DEBUG(1, ("talloc_strndup failed.\n"));

-             goto done;

+     /* if using a dedicated kpasswd server.. */

+     if (kr->kpasswd_srv != NULL) {

+         /* ..which is unreachable by now.. */

+         if (msg_status == PAM_AUTHTOK_LOCK_BUSY) {

+             fo_set_port_status(kr->kpasswd_srv, PORT_NOT_WORKING);

+             /* ..try to resolve next kpasswd server */

+             if (krb5_next_kpasswd(req) == NULL) {

+                 tevent_req_error(req, ENOMEM);

+             }

+             return;

+         } else {

+             fo_set_port_status(kr->kpasswd_srv, PORT_WORKING);

          }

-     } else {

-         DEBUG(1, ("Missing ccache name in child response [%.*s].\n", *msg_len,

-                                                                      &buf[p]));

-         goto done;

      }

  

-     if (*msg_status == PAM_AUTHINFO_UNAVAIL) {

+     /* if the KDC for auth (PAM_AUTHINFO_UNAVAIL) or

+      * chpass (PAM_AUTHTOK_LOCK_BUSY) was not available while using KDC

+      * also for chpass operation... */

+     if (msg_status == PAM_AUTHINFO_UNAVAIL ||

+         (kr->kpasswd_srv == NULL && msg_status == PAM_AUTHTOK_LOCK_BUSY)) {

          if (kr->srv != NULL) {

              fo_set_port_status(kr->srv, PORT_NOT_WORKING);

+             /* ..try to resolve next KDC */

+             if (krb5_next_kdc(req) == NULL) {

+                 tevent_req_error(req, ENOMEM);

+             }

+             return;

          }

-         be_mark_offline(be_req->be_ctx);

-         kr->is_offline = true;

      } else if (kr->srv != NULL) {

          fo_set_port_status(kr->srv, PORT_WORKING);

      }

  

-     if (kr->kpasswd_srv != NULL) {

-         if (*msg_status == PAM_AUTHTOK_LOCK_BUSY) {

-             fo_set_port_status(kr->kpasswd_srv, PORT_NOT_WORKING);

-         } else {

-             fo_set_port_status(kr->kpasswd_srv, PORT_WORKING);

+     /* Now only a successful authentication or password change is left.

+      *

+      * We expect that one of the messages in the received buffer contains

+      * the name of the credential cache file. */

+     if (kr->ccname == NULL) {

+         DEBUG(1, ("Missing ccache name in child response.\n"));

+         ret = EINVAL;

+         goto done;

+     }

+ 

+     if (kr->old_ccname != NULL) {

+         ret = safe_remove_old_ccache_file(kr->old_ccname, kr->ccname);

+         if (ret != EOK) {

+             DEBUG(1, ("Failed to remove old ccache file [%s], please remove it manually.\n"));

          }

      }

  

      struct sysdb_attrs *attrs;

-     attrs = sysdb_new_attrs(kr);

+     attrs = sysdb_new_attrs(state);

      ret = sysdb_attrs_add_string(attrs, SYSDB_CCACHE_FILE, kr->ccname);

      if (ret != EOK) {

          DEBUG(1, ("sysdb_attrs_add_string failed.\n"));

          goto done;

      }

  

-     req = krb5_save_ccname_send(kr, be_req->be_ctx->ev, be_req->be_ctx->sysdb,

-                                 be_req->be_ctx->domain, pd->user, kr->ccname);

-     if (req == NULL) {

+     subreq = krb5_save_ccname_send(state, state->ev, state->be_ctx->sysdb,

+                                    state->be_ctx->domain, pd->user, kr->ccname);

+     if (subreq == NULL) {

          DEBUG(1, ("krb5_save_ccname_send failed.\n"));

+         ret = ENOMEM;

          goto done;

      }

  

-     tevent_req_set_callback(req, krb5_save_ccname_done, kr);

+     tevent_req_set_callback(subreq, krb5_save_ccname_done, req);

      return;

  done:

-     talloc_free(kr);

-     pd->pam_status = pam_status;

-     krb_reply(be_req, dp_err, pd->pam_status);

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else {

+         tevent_req_error(req, ret);

+     }

  }

  

- static void krb5_save_ccname_done(struct tevent_req *req)

+ static struct tevent_req *krb5_next_server(struct tevent_req *req)

  {

-     struct krb5child_req *kr = tevent_req_callback_data(req,

-                                                         struct krb5child_req);

-     struct pam_data *pd = kr->pd;

-     struct be_req *be_req = kr->req;

-     struct krb5_ctx *krb5_ctx = kr->krb5_ctx;

-     int pam_status = PAM_SYSTEM_ERR;

-     int dp_err = DP_ERR_FATAL;

-     int ret;

-     char *password = NULL;

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+     struct pam_data *pd = state->pd;

+     struct tevent_req *next_req = NULL;

  

-     if (pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) {

-         ret = add_krb5_env(krb5_ctx->opts, kr->ccname, pd);

-         if (ret != EOK) {

-             DEBUG(1, ("add_krb5_env failed.\n"));

-             goto failed;

-         }

+     switch (pd->cmd) {

+         case SSS_PAM_AUTHENTICATE:

+             fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);

+             next_req = krb5_next_kdc(req);

+             break;

+         case SSS_PAM_CHAUTHTOK:

+         case SSS_PAM_CHAUTHTOK_PRELIM:

+             if (state->kr->kpasswd_srv) {

+                 fo_set_port_status(state->kr->kpasswd_srv, PORT_NOT_WORKING);

+                 next_req = krb5_next_kpasswd(req);

+                 break;

+             } else {

+                 fo_set_port_status(state->kr->srv, PORT_NOT_WORKING);

+                 next_req = krb5_next_kdc(req);

+                 break;

+             }

+         default:

+             DEBUG(1, ("Unexpected PAM task\n"));

      }

  

-     ret = sysdb_set_user_attr_recv(req);

-     talloc_zfree(req);

+     return next_req;

+ }

+ 

+ static struct tevent_req *krb5_next_kdc(struct tevent_req *req)

+ {

+     struct tevent_req *next_req;

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+ 

+     next_req = be_resolve_server_send(state, state->ev,

+                                       state->be_ctx,

+                                       state->krb5_ctx->service->name);

+     if (next_req == NULL) {

+         DEBUG(1, ("be_resolve_server_send failed.\n"));

+         return NULL;

+     }

+     tevent_req_set_callback(next_req, krb5_resolve_kdc_done, req);

+ 

+     return next_req;

+ }

+ 

+ static struct tevent_req *krb5_next_kpasswd(struct tevent_req *req)

+ {

+     struct tevent_req *next_req;

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+ 

+     next_req = be_resolve_server_send(state, state->ev,

+                                 state->be_ctx,

+                                 state->krb5_ctx->kpasswd_service->name);

+     if (next_req == NULL) {

+         DEBUG(1, ("be_resolve_server_send failed.\n"));

+         return NULL;

+     }

+     tevent_req_set_callback(next_req, krb5_resolve_kpasswd_done, req);

+ 

+     return next_req;

+ }

+ 

+ static void krb5_save_ccname_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+     struct krb5child_req *kr = state->kr;

+     struct pam_data *pd = state->pd;

+     int ret;

+     char *password = NULL;

+ 

+     ret = sysdb_set_user_attr_recv(subreq);

+     talloc_zfree(subreq);

      if (ret != EOK) {

          DEBUG(1, ("Saving ccache name failed.\n"));

-         goto failed;

+         tevent_req_error(req, ret);

+         return;

      }

  

      if (kr->is_offline) {

+         if (dp_opt_get_bool(kr->krb5_ctx->opts,KRB5_STORE_PASSWORD_IF_OFFLINE)) {

+             subreq = sysdb_cache_auth_send(state, state->ev,

+                                            state->be_ctx->sysdb,

+                                            state->be_ctx->domain, pd->user,

+                                            pd->authtok, pd->authtok_size,

+                                            state->be_ctx->cdb, true);

+             if (subreq == NULL) {

+                 DEBUG(2, ("sysdb_cache_auth_send failed, "

+                           "delayed online authentication not possible.\n"));

+                 /* This is not a fatal error, we continue with standard

+                  * offline authentication. */

+             } else {

+                 tevent_req_set_callback(subreq,

+                                         krb5_pam_handler_cache_auth_done, req);

+                 return;

+             }

+         }

+ 

          DEBUG(4, ("Backend is marked offline, retry later!\n"));

-         pam_status = PAM_AUTHINFO_UNAVAIL;

-         dp_err = DP_ERR_OFFLINE;

-         goto failed;

+         state->pam_status = PAM_AUTHINFO_UNAVAIL;

+         state->dp_err = DP_ERR_OFFLINE;

+         ret = EOK;

+         goto done;

      }

  

-     if (be_req->be_ctx->domain->cache_credentials == TRUE) {

+     if (state->be_ctx->domain->cache_credentials == TRUE) {

  

          /* password caching failures are not fatal errors */

-         pd->pam_status = PAM_SUCCESS;

+         state->pam_status = PAM_SUCCESS;

+         state->dp_err = DP_ERR_OK;

  

          switch(pd->cmd) {

              case SSS_PAM_AUTHENTICATE:

              case SSS_PAM_CHAUTHTOK_PRELIM:

-                 password = talloc_size(be_req, pd->authtok_size + 1);

+                 password = talloc_size(state, pd->authtok_size + 1);

                  if (password != NULL) {

                      memcpy(password, pd->authtok, pd->authtok_size);

                      password[pd->authtok_size] = '\0';

                  }

                  break;

              case SSS_PAM_CHAUTHTOK:

-                 password = talloc_size(be_req, pd->newauthtok_size + 1);

+                 password = talloc_size(state, pd->newauthtok_size + 1);

                  if (password != NULL) {

                      memcpy(password, pd->newauthtok, pd->newauthtok_size);

                      password[pd->newauthtok_size] = '\0';
@@ -1232,49 +1401,84 @@

  

          if (password == NULL) {

              DEBUG(0, ("password not available, offline auth may not work.\n"));

-             goto failed;

+             ret = EOK; /* password caching failures are not fatal errors */

+             goto done;

          }

  

          talloc_set_destructor((TALLOC_CTX *)password, password_destructor);

  

-         req = sysdb_cache_password_send(be_req, be_req->be_ctx->ev,

-                                         be_req->be_ctx->sysdb, NULL,

-                                         be_req->be_ctx->domain, pd->user,

-                                         password);

-         if (req == NULL) {

-             DEBUG(2, ("cache_password_send failed, offline auth may not work.\n"));

-             goto failed;

+         subreq = sysdb_cache_password_send(state, state->ev,

+                                            state->be_ctx->sysdb, NULL,

+                                            state->be_ctx->domain, pd->user,

+                                            password);

+         if (subreq == NULL) {

+             DEBUG(2, ("cache_password_send failed, "

+                       "offline auth may not work.\n"));

+             ret = EOK; /* password caching failures are not fatal errors */

+             goto done;

          }

-         tevent_req_set_callback(req, krb5_pam_handler_cache_done, be_req);

+         tevent_req_set_callback(subreq, krb5_pam_handler_cache_done, req);

          return;

      }

  

-     pam_status = PAM_SUCCESS;

-     dp_err = DP_ERR_OK;

- 

- failed:

-     talloc_free(kr);

+     state->pam_status = PAM_SUCCESS;

+     state->dp_err = DP_ERR_OK;

+     ret = EOK;

  

-     pd->pam_status = pam_status;

-     krb_reply(be_req, dp_err, pd->pam_status);

+ done:

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else {

+         tevent_req_error(req, ret);

+     }

  }

  

  static void krb5_pam_handler_cache_done(struct tevent_req *subreq)

  {

-     struct be_req *be_req = tevent_req_callback_data(subreq, struct be_req);

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

      int ret;

  

-     /* password caching failures are not fatal errors */

      ret = sysdb_cache_password_recv(subreq);

      talloc_zfree(subreq);

  

-     /* so we just log it any return */

+     /* password caching failures are not fatal errors,

+      * so we just log it and return */

      if (ret) {

          DEBUG(2, ("Failed to cache password (%d)[%s]!?\n",

                    ret, strerror(ret)));

      }

  

-     krb_reply(be_req, DP_ERR_OK, PAM_SUCCESS);

+     tevent_req_done(req);

+ }

+ 

+ static void krb5_pam_handler_cache_auth_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req);

+     struct krb5_auth_state *state = tevent_req_data(req, struct krb5_auth_state);

+     struct pam_data *pd = state->pd;

+     struct krb5_ctx *krb5_ctx = state->kr->krb5_ctx;

+     int ret;

+     time_t expire_date;

+     time_t delayed_until;

+ 

+     ret = sysdb_cache_auth_recv(subreq, &expire_date, &delayed_until);

+     talloc_zfree(subreq);

+ 

+     if (ret) {

+         DEBUG(2, ("Offline authentication failed.\n"));

+     } else {

+         ret = add_user_to_delayed_online_authentication(krb5_ctx, pd,

+                                                         state->kr->uid);

+         if (ret != EOK) {

+             /* This error is not fatal */

+             DEBUG(1, ("add_user_to_delayed_online_authentication failed.\n"));

+         }

+     }

+ 

+     state->pam_status = PAM_AUTHINFO_UNAVAIL;

+     state->dp_err = DP_ERR_OFFLINE;

+ 

+     tevent_req_done(req);

  }

  

  static void krb_reply(struct be_req *req, int dp_err, int result)
@@ -1282,3 +1486,56 @@

      req->fn(req, dp_err, result, NULL);

  }

  

+ void krb5_auth_done(struct tevent_req *req);

+ 

+ void krb5_pam_handler(struct be_req *be_req)

+ {

+     struct tevent_req *req;

+     struct pam_data *pd;

+     struct krb5_ctx *krb5_ctx;

+ 

+     pd = talloc_get_type(be_req->req_data, struct pam_data);

+ 

+     krb5_ctx = get_krb5_ctx(be_req);

+     if (krb5_ctx == NULL) {

+         DEBUG(1, ("Kerberos context not available.\n"));

+         goto failed;

+     }

+ 

+     req = krb5_auth_send(be_req, be_req->be_ctx->ev, be_req->be_ctx, pd,

+                          krb5_ctx);

+     if (req == NULL) {

+         DEBUG(1, ("krb5_auth_send failed.\n"));

+         goto failed;

+     }

+ 

+     tevent_req_set_callback(req, krb5_auth_done, be_req);

+ 

+     return;

+ 

+ failed:

+     pd->pam_status = PAM_SYSTEM_ERR;

+     krb_reply(be_req, DP_ERR_FATAL, pd->pam_status);

+ }

+ 

+ void krb5_auth_done(struct tevent_req *req)

+ {

+     int ret;

+     struct be_req *be_req = tevent_req_callback_data(req, struct be_req);

+     int pam_status;

+     int dp_err;

+     struct pam_data *pd;

+ 

+     pd = talloc_get_type(be_req->req_data, struct pam_data);

+ 

+     ret = krb5_auth_recv(req, &pam_status, &dp_err);

+     talloc_zfree(req);

+     if (ret) {

+         pd->pam_status = PAM_SYSTEM_ERR;

+         dp_err = DP_ERR_OK;

+     } else {

+         pd->pam_status = pam_status;

+     }

+ 

+     krb_reply(be_req, dp_err, pd->pam_status);

+ }

file modified
+15 -39
@@ -33,24 +33,22 @@

  #include "providers/krb5/krb5_common.h"

  

  #define CCACHE_ENV_NAME "KRB5CCNAME"

- #define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE"

+ #define SSSD_KRB5_CHANGEPW_PRINCIPAL "SSSD_KRB5_CHANGEPW_PRINCIPAL"

  

  #define ILLEGAL_PATH_PATTERN "//|/\\./|/\\.\\./"

  

- typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;

- 

  struct krb5child_req {

      pid_t child_pid;

      int read_from_child_fd;

      int write_to_child_fd;

  

-     struct be_req *req;

      struct pam_data *pd;

      struct krb5_ctx *krb5_ctx;

  

      struct tevent_timer *timeout_handler;

  

      const char *ccname;

+     const char *old_ccname;

      const char *homedir;

      const char *upn;

      uid_t uid;
@@ -62,41 +60,19 @@

      bool valid_tgt_present;

  };

  

- struct fo_service;

- 

- struct krb5_ctx {

-     /* opts taken from kinit */

-     /* in seconds */

-     krb5_deltat starttime;

-     krb5_deltat lifetime;

-     krb5_deltat rlife;

- 

-     int forwardable;

-     int proxiable;

-     int addresses;

- 

-     int not_forwardable;

-     int not_proxiable;

-     int no_addresses;

- 

-     int verbose;

- 

-     char* principal_name;

-     char* service_name;

-     char* keytab_name;

-     char* k5_cache_name;

-     char* k4_cache_name;

- 

-     action_type action;

- 

-     struct dp_option *opts;

-     struct krb5_service *service;

-     struct krb5_service *kpasswd_service;

-     int child_debug_fd;

- 

-     pcre *illegal_path_re;

- };

- 

  void krb5_pam_handler(struct be_req *be_req);

  

+ struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,

+                                   struct tevent_context *ev,

+                                   struct be_ctx *be_ctx,

+                                   struct pam_data *pd,

+                                   struct krb5_ctx *krb5_ctx);

+ int krb5_auth_recv(struct tevent_req *req, int *pam_status, int *dp_err);

+ 

+ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,

+                                                   struct pam_data *pd,

+                                                   uid_t uid);

+ errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx,

+                                            struct be_ctx *be_ctx,

+                                            struct tevent_context *ev);

  #endif /* __KRB5_AUTH_H__ */

file modified
+130 -63
@@ -6,7 +6,7 @@

      Authors:

          Sumit Bose <sbose@redhat.com>

  

-     Copyright (C) 2009 Red Hat

+     Copyright (C) 2009-2010 Red Hat

  

      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
@@ -63,7 +63,7 @@

  

      char *kdcip;

      char *realm;

-     char *changepw_principle;

+     char *changepw_principal;

      char *ccache_dir;

      char *ccname_template;

      int auth_timeout;
@@ -103,6 +103,36 @@

      sss_krb5_free_error_message(krb5_error_ctx, __krb5_error_msg); \

  } while(0);

  

+ 

+ static krb5_error_code sss_krb5_prompter(krb5_context context, void *data,

+                                          const char *name, const char *banner,

+                                          int num_prompts, krb5_prompt prompts[])

+ {

+     int ret;

+     struct krb5_req *kr = talloc_get_type(data, struct krb5_req);

+ 

+     if (num_prompts != 0) {

+         DEBUG(1, ("Cannot handle password prompts.\n"));

+         return KRB5_LIBOS_CANTREADPWD;

+     }

+ 

+     if (banner == NULL || *banner == '\0') {

+         DEBUG(5, ("Prompter called with empty banner, nothing to do.\n"));

+         return EOK;

+     }

+ 

+     DEBUG(9, ("Prompter called with [%s].\n", banner));

+ 

+     ret = pam_add_response(kr->pd, SSS_PAM_TEXT_MSG, strlen(banner)+1,

+                            (const uint8_t *) banner);

+     if (ret != EOK) {

+         DEBUG(1, ("pam_add_response failed.\n"));

+     }

+ 

+     return EOK;

+ }

+ 

+ 

  static krb5_error_code create_empty_cred(struct krb5_req *kr, krb5_creds **_cred)

  {

      krb5_error_code kerr;
@@ -247,22 +277,49 @@

      return kerr;

  }

  

- static errno_t pack_response_packet(struct response *resp, int status, int type,

-                                     size_t len, const uint8_t *data)

+ static errno_t pack_response_packet(struct response *resp, int status,

+                                     struct pam_data *pd)

  {

+     size_t size = 0;

      size_t p = 0;

+     struct response_data *pdr;

+ 

+     /* A buffer with the following structure must be created:

+      * int32_t status of the request (required)

+      * message (zero or more)

+      *

+      * A message consists of:

+      * int32_t type of the message

+      * int32_t length of the following data

+      * uint8_t[len] data

+      */

  

-     resp->buf = talloc_array(resp, uint8_t,

-                              3*sizeof(int32_t) + len);

+     size = sizeof(int32_t);

+ 

+     pdr = pd->resp_list;

+     while (pdr != NULL) {

+         size += 2*sizeof(int32_t) + pdr->len;

+         pdr = pdr->next;

+     }

+ 

+ 

+     resp->buf = talloc_array(resp, uint8_t, size);

      if (!resp->buf) {

          DEBUG(1, ("Insufficient memory to create message.\n"));

          return ENOMEM;

      }

  

      SAFEALIGN_SET_INT32(&resp->buf[p], status, &p);

-     SAFEALIGN_SET_INT32(&resp->buf[p], type, &p);

-     SAFEALIGN_SET_INT32(&resp->buf[p], len, &p);

-     safealign_memcpy(&resp->buf[p], data, len, &p);

+ 

+     pdr = pd->resp_list;

+     while(pdr != NULL) {

+         SAFEALIGN_SET_INT32(&resp->buf[p], pdr->type, &p);

+         SAFEALIGN_SET_INT32(&resp->buf[p], pdr->len, &p);

+         safealign_memcpy(&resp->buf[p], pdr->data, pdr->len, &p);

+ 

+         pdr = pdr->next;

+     }

+ 

  

      resp->size = p;

  
@@ -271,15 +328,12 @@

  

  static struct response *prepare_response_message(struct krb5_req *kr,

                                                   krb5_error_code kerr,

-                                                  char *user_error_message,

                                                   int pam_status)

  {

      char *msg = NULL;

      const char *krb5_msg = NULL;

      int ret;

      struct response *resp;

-     size_t user_resp_len;

-     uint8_t *user_resp;

  

      resp = talloc_zero(kr, struct response);

      if (resp == NULL) {
@@ -289,9 +343,8 @@

  

      if (kerr == 0) {

          if(kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {

-             ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_SYSTEM_INFO,

-                                        strlen("success") + 1,

-                                        (const uint8_t *) "success");

+             pam_status = PAM_SUCCESS;

+             ret = EOK;

          } else {

              if (kr->ccname == NULL) {

                  DEBUG(1, ("Error obtaining ccname.\n"));
@@ -304,44 +357,28 @@

                  return NULL;

              }

  

-             ret = pack_response_packet(resp, PAM_SUCCESS, SSS_PAM_ENV_ITEM,

-                                        strlen(msg) + 1, (uint8_t *) msg);

+             pam_status = PAM_SUCCESS;

+             ret = pam_add_response(kr->pd, SSS_PAM_ENV_ITEM, strlen(msg) + 1,

+                                    (uint8_t *) msg);

              talloc_zfree(msg);

          }

      } else {

-         if (user_error_message != NULL) {

-             ret = pack_user_info_chpass_error(kr, user_error_message,

-                                               &user_resp_len, &user_resp);

-             if (ret != EOK) {

-                 DEBUG(1, ("pack_user_info_chpass_error failed.\n"));

-                 talloc_zfree(user_error_message);

-             } else {

-                 ret = pack_response_packet(resp, pam_status, SSS_PAM_USER_INFO,

-                                            user_resp_len, user_resp);

-                 if (ret != EOK) {

-                     DEBUG(1, ("pack_response_packet failed.\n"));

-                     talloc_zfree(user_error_message);

-                 }

-             }

-         }

- 

-         if (user_error_message == NULL) {

-             krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr);

-             if (krb5_msg == NULL) {

-                 DEBUG(1, ("sss_krb5_get_error_message failed.\n"));

-                 return NULL;

-             }

- 

-             ret = pack_response_packet(resp, pam_status, SSS_PAM_SYSTEM_INFO,

-                                        strlen(krb5_msg) + 1,

-                                        (const uint8_t *) krb5_msg);

-             sss_krb5_free_error_message(krb5_error_ctx, krb5_msg);

-         } else {

- 

+         krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr);

+         if (krb5_msg == NULL) {

+             DEBUG(1, ("sss_krb5_get_error_message failed.\n"));

+             return NULL;

          }

  

+         ret = pam_add_response(kr->pd, SSS_PAM_SYSTEM_INFO,

+                                strlen(krb5_msg) + 1,

+                                (const uint8_t *) krb5_msg);

+         sss_krb5_free_error_message(krb5_error_ctx, krb5_msg);

+     }

+     if (ret != EOK) {

+         DEBUG(1, ("pam_add_response failed.\n"));

      }

  

+     ret = pack_response_packet(resp, pam_status, kr->pd);

      if (ret != EOK) {

          DEBUG(1, ("pack_response_packet failed.\n"));

          return NULL;
@@ -350,15 +387,14 @@

      return resp;

  }

  

- static errno_t sendresponse(int fd, krb5_error_code kerr,

-                             char *user_error_message, int pam_status,

+ static errno_t sendresponse(int fd, krb5_error_code kerr, int pam_status,

                              struct krb5_req *kr)

  {

      struct response *resp;

      size_t written;

      int ret;

  

-     resp = prepare_response_message(kr, kerr, user_error_message, pam_status);

+     resp = prepare_response_message(kr, kerr, pam_status);

      if (resp == NULL) {

          DEBUG(1, ("prepare_response_message failed.\n"));

          return ENOMEM;
@@ -385,7 +421,7 @@

  {

      krb5_error_code kerr;

      krb5_error_code kt_err;

-     char *principal;

+     char *principal = NULL;

      krb5_keytab keytab;

      krb5_kt_cursor cursor;

      krb5_keytab_entry entry;
@@ -481,8 +517,8 @@

      int ret;

  

      kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,

-                                         password, NULL, NULL, 0, NULL,

-                                         kr->options);

+                                         password, sss_krb5_prompter, kr, 0,

+                                         NULL, kr->options);

      if (kerr != 0) {

          KRB5_DEBUG(1, kerr);

          return kerr;
@@ -533,6 +569,9 @@

      krb5_data result_code_string;

      krb5_data result_string;

      char *user_error_message = NULL;

+     size_t user_resp_len;

+     uint8_t *user_resp;

+     krb5_prompter_fct prompter = sss_krb5_prompter;

  

      pass_str = talloc_strndup(kr, (const char *) kr->pd->authtok,

                                kr->pd->authtok_size);
@@ -542,9 +581,14 @@

          goto sendresponse;

      }

  

+     if (kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) {

+         /* We do not need a password expiration warning here. */

+         prompter = NULL;

+     }

+ 

      kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,

-                                         pass_str, NULL, NULL, 0,

-                                         kr->krb5_ctx->changepw_principle,

+                                         pass_str, prompter, kr, 0,

+                                         kr->krb5_ctx->changepw_principal,

                                          kr->options);

      if (kerr != 0) {

          KRB5_DEBUG(1, kerr);
@@ -612,6 +656,20 @@

              }

          }

  

+         if (user_error_message != NULL) {

+             ret = pack_user_info_chpass_error(kr->pd, user_error_message,

+                                               &user_resp_len, &user_resp);

+             if (ret != EOK) {

+                 DEBUG(1, ("pack_user_info_chpass_error failed.\n"));

+             } else {

+                 ret = pam_add_response(kr->pd, SSS_PAM_USER_INFO, user_resp_len,

+                                        user_resp);

+                 if (ret != EOK) {

+                     DEBUG(1, ("pack_response_packet failed.\n"));

+                 }

+             }

+         }

+ 

          pam_status = PAM_AUTHTOK_ERR;

          goto sendresponse;

      }
@@ -631,7 +689,7 @@

      }

  

  sendresponse:

-     ret = sendresponse(fd, kerr, user_error_message, pam_status, kr);

+     ret = sendresponse(fd, kerr, pam_status, kr);

      if (ret != EOK) {

          DEBUG(1, ("sendresponse failed.\n"));

      }
@@ -662,8 +720,8 @@

         So we validate the password by trying to get a changepw ticket. */

      if (kerr == KRB5KDC_ERR_KEY_EXP) {

          kerr = krb5_get_init_creds_password(kr->ctx, kr->creds, kr->princ,

-                                             pass_str, NULL, NULL, 0,

-                                             kr->krb5_ctx->changepw_principle,

+                                             pass_str, sss_krb5_prompter, kr, 0,

+                                             kr->krb5_ctx->changepw_principal,

                                              kr->options);

          krb5_free_cred_contents(kr->ctx, kr->creds);

          if (kerr == 0) {
@@ -693,7 +751,7 @@

      }

  

  sendresponse:

-     ret = sendresponse(fd, kerr, NULL, pam_status, kr);

+     ret = sendresponse(fd, kerr, pam_status, kr);

      if (ret != EOK) {

          DEBUG(1, ("sendresponse failed.\n"));

      }
@@ -712,7 +770,7 @@

          pam_status = PAM_SYSTEM_ERR;

      }

  

-     ret = sendresponse(fd, ret, NULL, pam_status, kr);

+     ret = sendresponse(fd, ret, pam_status, kr);

      if (ret != EOK) {

          DEBUG(1, ("sendresponse failed.\n"));

      }
@@ -814,10 +872,10 @@

          goto failed;

      }

  

-     kr->krb5_ctx->changepw_principle = getenv(SSSD_KRB5_CHANGEPW_PRINCIPLE);

-     if (kr->krb5_ctx->changepw_principle == NULL) {

+     kr->krb5_ctx->changepw_principal = getenv(SSSD_KRB5_CHANGEPW_PRINCIPAL);

+     if (kr->krb5_ctx->changepw_principal == NULL) {

          DEBUG(1, ("Cannot read [%s] from environment.\n",

-                   SSSD_KRB5_CHANGEPW_PRINCIPLE));

+                   SSSD_KRB5_CHANGEPW_PRINCIPAL));

          if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {

              goto failed;

          }
@@ -878,6 +936,15 @@

          goto failed;

      }

  

+     /* A prompter is used to catch messages about when a password will

+      * expired. The library shall not use the prompter to ask for a new password

+      * but shall return KRB5KDC_ERR_KEY_EXP. */

+     krb5_get_init_creds_opt_set_change_password_prompt(kr->options, 0);

+     if (kerr != 0) {

+         KRB5_DEBUG(1, kerr);

+         goto failed;

+     }

+ 

  /* TODO: set options, e.g.

   *  krb5_get_init_creds_opt_set_tkt_life

   *  krb5_get_init_creds_opt_set_renew_life
@@ -937,7 +1004,7 @@

  

      DEBUG(7, ("krb5_child started.\n"));

  

-     pd = talloc(NULL, struct pam_data);

+     pd = talloc_zero(NULL, struct pam_data);

      if (pd == NULL) {

          DEBUG(1, ("malloc failed.\n"));

          _exit(-1);

file modified
+231 -13
@@ -40,7 +40,8 @@

      { "krb5_auth_timeout", DP_OPT_NUMBER, { .number = 15 }, NULL_NUMBER },

      { "krb5_keytab", DP_OPT_STRING, { "/etc/krb5.keytab" }, NULL_STRING },

      { "krb5_validate", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },

-     { "krb5_kpasswd", DP_OPT_STRING, NULL_STRING, NULL_STRING }

+     { "krb5_kpasswd", DP_OPT_STRING, NULL_STRING, NULL_STRING },

+     { "krb5_store_password_if_offline", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE }

  };

  

  errno_t check_and_export_options(struct dp_option *opts,
@@ -69,13 +70,13 @@

  

      dummy = dp_opt_get_cstring(opts, KRB5_KDC);

      if (dummy == NULL) {

-         DEBUG(1, ("No KDC explicitly configured, using defaults"));

+         DEBUG(1, ("No KDC explicitly configured, using defaults.\n"));

      }

  

      dummy = dp_opt_get_cstring(opts, KRB5_KPASSWD);

      if (dummy == NULL) {

          DEBUG(1, ("No kpasswd server explicitly configured, "

-                   "using the KDC or defaults"));

+                   "using the KDC or defaults.\n"));

      }

  

      dummy = dp_opt_get_cstring(opts, KRB5_CCNAME_TMPL);
@@ -91,7 +92,7 @@

  

      dummy = dp_opt_get_cstring(opts, KRB5_CHANGEPW_PRINC);

      if (dummy == NULL) {

-         DEBUG(1, ("Missing change password principle.\n"));

+         DEBUG(1, ("Missing change password principal.\n"));

          return EINVAL;

      }

      if (strchr(dummy, '@') == NULL) {
@@ -108,10 +109,10 @@

          dummy = value;

      }

  

-     ret = setenv(SSSD_KRB5_CHANGEPW_PRINCIPLE, dummy, 1);

+     ret = setenv(SSSD_KRB5_CHANGEPW_PRINCIPAL, dummy, 1);

      if (ret != EOK) {

          DEBUG(2, ("setenv %s failed, password change might fail.\n",

-                   SSSD_KRB5_CHANGEPW_PRINCIPLE));

+                   SSSD_KRB5_CHANGEPW_PRINCIPAL));

      }

  

      return EOK;
@@ -157,6 +158,7 @@

      TALLOC_CTX *tmp_ctx = NULL;

      const char *name_tmpl = NULL;

      int server_len;

+     ssize_t written;

  

      if (realm == NULL || *realm == '\0' || server == NULL || *server == '\0' ||

          service == NULL || service == '\0') {
@@ -202,14 +204,24 @@

          goto done;

      }

  

-     ret = write(fd, server, server_len);

-     if (ret == -1) {

-         DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno)));

-         goto done;

+     written = 0;

+     while (written < server_len) {

+         ret = write(fd, server+written, server_len-written);

+         if (ret == -1) {

+             if (errno == EINTR || errno == EAGAIN) {

+                 continue;

+             }

+             DEBUG(1, ("write failed [%d][%s].\n", errno, strerror(errno)));

+             goto done;

+         }

+         else {

+             written += ret;

+         }

      }

-     if (ret != server_len) {

-         DEBUG(1, ("Partial write occured, this should never happen.\n"));

-         ret = EINTR;

+ 

+     if (written != server_len) {

+         DEBUG(1, ("Write error, wrote [%d] bytes, expected [%d]\n",

+                    written, server_len));

          goto done;

      }

  
@@ -332,6 +344,10 @@

          goto done;

      }

  

+     if (!servers) {

+         servers = BE_SRV_IDENTIFIER;

+     }

+ 

      ret = split_on_separator(tmp_ctx, servers, ',', true, &list, NULL);

      if (ret != EOK) {

          DEBUG(1, ("Failed to parse server list!\n"));
@@ -342,6 +358,23 @@

  

          talloc_steal(service, list[i]);

          server_spec = talloc_strdup(service, list[i]);

+         if (!server_spec) {

+             ret = ENOMEM;

+             goto done;

+         }

+ 

+         if (be_fo_is_srv_identifier(server_spec)) {

+             ret = be_fo_add_srv_server(ctx, service_name, service_name,

+                                        FO_PROTO_TCP, ctx->domain->name, NULL);

+             if (ret) {

+                 DEBUG(0, ("Failed to add server\n"));

+                 goto done;

+             }

+ 

+             DEBUG(6, ("Added service lookup\n"));

+             continue;

+         }

+ 

          port_str = strrchr(server_spec, ':');

          if (port_str == NULL) {

              port = 0;
@@ -413,3 +446,188 @@

      return ret;

  }

  

+ 

+ static errno_t remove_krb5_info_files(TALLOC_CTX *mem_ctx, const char *realm)

+ {

+     int ret;

+     errno_t err;

+     char *file;

+ 

+     file = talloc_asprintf(mem_ctx, KDCINFO_TMPL, realm);

+     if(file == NULL) {

+         DEBUG(1, ("talloc_asprintf failed.\n"));

+         return ENOMEM;

+     }

+ 

+     errno = 0;

+     ret = unlink(file);

+     if (ret == -1) {

+         err = errno;

+         DEBUG(5, ("Could not remove [%s], [%d][%s]\n", file,

+                   err, strerror(err)));

+     }

+ 

+     file = talloc_asprintf(mem_ctx, KPASSWDINFO_TMPL, realm);

+     if(file == NULL) {

+         DEBUG(1, ("talloc_asprintf failed.\n"));

+         return ENOMEM;

+     }

+ 

+     errno = 0;

+     ret = unlink(file);

+     if (ret == -1) {

+         err = errno;

+         DEBUG(5, ("Could not remove [%s], [%d][%s]\n", file,

+                   err, strerror(err)));

+     }

+ 

+     return EOK;

+ }

+ 

+ void remove_krb5_info_files_callback(void *pvt)

+ {

+     int ret;

+     TALLOC_CTX *tmp_ctx = NULL;

+     struct remove_info_files_ctx *ctx = talloc_get_type(pvt,

+                                                   struct remove_info_files_ctx);

+ 

+     ret = be_fo_run_callbacks_at_next_request(ctx->be_ctx,

+                                               ctx->kdc_service_name);

+     if (ret != EOK) {

+         DEBUG(1, ("be_fo_run_callbacks_at_next_request failed, "

+                   "krb5 info files will not be removed, because "

+                   "it is unclear if they will be recreated properly.\n"));

+         return;

+     }

+     if (ctx->kpasswd_service_name != NULL) {

+         ret = be_fo_run_callbacks_at_next_request(ctx->be_ctx,

+                                             ctx->kpasswd_service_name);

+         if (ret != EOK) {

+             DEBUG(1, ("be_fo_run_callbacks_at_next_request failed, "

+                       "krb5 info files will not be removed, because "

+                       "it is unclear if they will be recreated properly.\n"));

+             return;

+         }

+     }

+ 

+     tmp_ctx = talloc_new(NULL);

+     if (tmp_ctx == NULL) {

+         DEBUG(1, ("talloc_new failed, cannot remove krb5 info files.\n"));

+         return;

+     }

+ 

+     ret = remove_krb5_info_files(tmp_ctx, ctx->realm);

+     if (ret != EOK) {

+         DEBUG(1, ("remove_krb5_info_files failed.\n"));

+     }

+ 

+     talloc_zfree(tmp_ctx);

+ }

+ 

+ void krb5_finalize(struct tevent_context *ev,

+                    struct tevent_signal *se,

+                    int signum,

+                    int count,

+                    void *siginfo,

+                    void *private_data)

+ {

+     char *realm = (char *)private_data;

+     int ret;

+ 

+     ret = remove_krb5_info_files(se, realm);

+     if (ret != EOK) {

+         DEBUG(1, ("remove_krb5_info_files failed.\n"));

+     }

+ 

+     sig_term(signum);

+ }

+ 

+ errno_t krb5_install_offline_callback(struct be_ctx *be_ctx,

+                                       struct krb5_ctx *krb5_ctx)

+ {

+     int ret;

+     struct remove_info_files_ctx *ctx;

+     const char *krb5_realm;

+ 

+     if (krb5_ctx->service == NULL || krb5_ctx->service->name == NULL) {

+         DEBUG(1, ("Missing KDC service name!\n"));

+         return EINVAL;

+     }

+ 

+     ctx = talloc_zero(krb5_ctx, struct remove_info_files_ctx);

+     if (ctx == NULL) {

+         DEBUG(1, ("talloc_zfree failed.\n"));

+         return ENOMEM;

+     }

+ 

+     krb5_realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);

+     if (krb5_realm == NULL) {

+         DEBUG(1, ("Missing krb5_realm option!\n"));

+         ret = EINVAL;

+         goto done;

+     }

+ 

+     ctx->realm = talloc_strdup(ctx, krb5_realm);

+     if (ctx->realm == NULL) {

+         DEBUG(1, ("talloc_strdup failed!\n"));

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     ctx->be_ctx = be_ctx;

+     ctx->kdc_service_name = krb5_ctx->service->name;

+     if (krb5_ctx->kpasswd_service == NULL) {

+         ctx->kpasswd_service_name =NULL;

+     } else {

+         ctx->kpasswd_service_name = krb5_ctx->kpasswd_service->name;

+     }

+ 

+     ret = be_add_offline_cb(ctx, be_ctx, remove_krb5_info_files_callback, ctx,

+                             NULL);

+     if (ret != EOK) {

+         DEBUG(1, ("be_add_offline_cb failed.\n"));

+         goto done;

+     }

+ 

+     ret = EOK;

+ 

+ done:

+     if (ret != EOK) {

+         talloc_zfree(ctx);

+     }

+ 

+     return ret;

+ }

+ 

+ errno_t krb5_install_sigterm_handler(struct tevent_context *ev,

+                                      struct krb5_ctx *krb5_ctx)

+ {

+     const char *krb5_realm;

+     char *sig_realm;

+     struct tevent_signal *sige;

+ 

+     BlockSignals(false, SIGTERM);

+ 

+     krb5_realm = dp_opt_get_cstring(krb5_ctx->opts, KRB5_REALM);

+     if (krb5_realm == NULL) {

+         DEBUG(1, ("Missing krb5_realm option!\n"));

+         return EINVAL;

+     }

+ 

+     sig_realm = talloc_strdup(krb5_ctx, krb5_realm);

+     if (sig_realm == NULL) {

+         DEBUG(1, ("talloc_strdup failed!\n"));

+         return ENOMEM;

+     }

+ 

+     sige = tevent_add_signal(ev, krb5_ctx, SIGTERM, SA_SIGINFO, krb5_finalize,

+                              sig_realm);

+     if (sige == NULL) {

+         DEBUG(1, ("tevent_add_signal failed.\n"));

+         talloc_free(sig_realm);

+         return ENOMEM;

+     }

+     talloc_steal(sige, sig_realm);

+ 

+     return EOK;

+ }

@@ -35,13 +35,13 @@

  

  #define SSSD_KRB5_KDC "SSSD_KRB5_KDC"

  #define SSSD_KRB5_REALM "SSSD_KRB5_REALM"

- #define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE"

+ #define SSSD_KRB5_CHANGEPW_PRINCIPAL "SSSD_KRB5_CHANGEPW_PRINCIPAL"

  

  #define KDCINFO_TMPL PUBCONF_PATH"/kdcinfo.%s"

  #define KPASSWDINFO_TMPL PUBCONF_PATH"/kpasswdinfo.%s"

  

- #define SSS_KRB5KDC_FO_SRV "KRB5KDC"

- #define SSS_KRB5KPASSWD_FO_SRV "KRB5KPASSWD"

+ #define SSS_KRB5KDC_FO_SRV "KERBEROS"

+ #define SSS_KRB5KPASSWD_FO_SRV "KPASSWD"

  

  enum krb5_opts {

      KRB5_KDC = 0,
@@ -53,16 +53,64 @@

      KRB5_KEYTAB,

      KRB5_VALIDATE,

      KRB5_KPASSWD,

+     KRB5_STORE_PASSWORD_IF_OFFLINE,

  

      KRB5_OPTS

  };

  

+ typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;

+ 

  struct krb5_service {

      char *name;

      char *address;

      char *realm;

  };

  

+ struct fo_service;

+ struct deferred_auth_ctx;

+ 

+ struct krb5_ctx {

+     /* opts taken from kinit */

+     /* in seconds */

+     krb5_deltat starttime;

+     krb5_deltat lifetime;

+     krb5_deltat rlife;

+ 

+     int forwardable;

+     int proxiable;

+     int addresses;

+ 

+     int not_forwardable;

+     int not_proxiable;

+     int no_addresses;

+ 

+     int verbose;

+ 

+     char* principal_name;

+     char* service_name;

+     char* keytab_name;

+     char* k5_cache_name;

+     char* k4_cache_name;

+ 

+     action_type action;

+ 

+     struct dp_option *opts;

+     struct krb5_service *service;

+     struct krb5_service *kpasswd_service;

+     int child_debug_fd;

+ 

+     pcre *illegal_path_re;

+ 

+     struct deferred_auth_ctx *deferred_auth_ctx;

+ };

+ 

+ struct remove_info_files_ctx {

+     char *realm;

+     struct be_ctx *be_ctx;

+     const char *kdc_service_name;

+     const char *kpasswd_service_name;

+ };

+ 

  errno_t check_and_export_options(struct dp_option *opts,

                                   struct sss_domain_info *dom);

  
@@ -75,4 +123,19 @@

  int krb5_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,

                        const char *service_name, const char *servers,

                        const char *realm, struct krb5_service **_service);

+ 

+ void remove_krb5_info_files_callback(void *pvt);

+ 

+ void krb5_finalize(struct tevent_context *ev,

+                    struct tevent_signal *se,

+                    int signum,

+                    int count,

+                    void *siginfo,

+                    void *private_data);

+ 

+ errno_t krb5_install_offline_callback(struct be_ctx *be_ctx,

+                                       struct krb5_ctx *krb_ctx);

+ 

+ errno_t krb5_install_sigterm_handler(struct tevent_context *ev,

+                                      struct krb5_ctx *krb5_ctx);

  #endif /* __KRB5_COMMON_H__ */

@@ -0,0 +1,354 @@

+ /*

+     SSSD

+ 

+     Kerberos 5 Backend Module -- Request a TGT when the system gets online

+ 

+     Authors:

+         Sumit Bose <sbose@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include <security/pam_modules.h>

+ #ifdef USE_KEYRING

+ #include <sys/types.h>

+ #include <keyutils.h>

+ #endif

+ 

+ #include "providers/krb5/krb5_auth.h"

+ #include "dhash.h"

+ #include "util/util.h"

+ #include "util/find_uid.h"

+ 

+ #define INITIAL_USER_TABLE_SIZE 10

+ 

+ struct deferred_auth_ctx {

+     hash_table_t *user_table;

+     struct be_ctx *be_ctx;

+     struct tevent_context *ev;

+     struct krb5_ctx *krb5_ctx;

+ };

+ 

+ struct auth_data {

+     struct be_ctx *be_ctx;

+     struct krb5_ctx *krb5_ctx;

+     struct pam_data *pd;

+ };

+ 

+ static void *hash_talloc(const size_t size, void *pvt)

+ {

+     return talloc_size(pvt, size);

+ }

+ 

+ static void hash_talloc_free(void *ptr, void *pvt)

+ {

+     talloc_free(ptr);

+ }

+ 

+ static void authenticate_user_done(struct tevent_req *req);

+ static void authenticate_user(struct tevent_context *ev,

+                               struct tevent_timer *te,

+                               struct timeval current_time,

+                               void *private_data)

+ {

+     struct auth_data *auth_data = talloc_get_type(private_data,

+                                                   struct auth_data);

+     struct pam_data *pd = auth_data->pd;

+     struct tevent_req *req;

+ 

+     DEBUG_PAM_DATA(9, pd);

+ 

+     if (pd->authtok == NULL || pd->authtok_size == 0) {

+         DEBUG(1, ("Missing authtok for user [%s].\n", pd->user));

+         return;

+     }

+ 

+ #ifdef USE_KEYRING

+     long keysize;

+     long keyrevoke;

+     int ret;

+     keysize = keyctl_read(pd->key_serial, (char *) pd->authtok,

+                           pd->authtok_size);

+     keyrevoke = keyctl_revoke(pd->key_serial);

+     if (keysize == -1) {

+         ret = errno;

+         DEBUG(1, ("keyctl_read failed [%d][%s].\n", ret, strerror(ret)));

+         return;

+     } else if (keysize != pd->authtok_size) {

+         DEBUG(1, ("keyctl_read returned key with wrong size, "

+                   "expect [%d] got [%d].\n", pd->authtok_size, keysize));

+         return;

+     }

+     if (keyrevoke == -1) {

+         ret = errno;

+         DEBUG(1, ("keyctl_revoke failed [%d][%s].\n", ret, strerror(ret)));

+     }

+ #endif

+ 

+     req = krb5_auth_send(auth_data, ev, auth_data->be_ctx, auth_data->pd,

+                          auth_data->krb5_ctx);

+     if (req == NULL) {

+         DEBUG(1, ("krb5_auth_send failed.\n"));

+         talloc_free(auth_data);

+         return;

+     }

+ 

+     tevent_req_set_callback(req, authenticate_user_done, auth_data);

+ }

+ 

+ static void authenticate_user_done(struct tevent_req *req) {

+     struct auth_data *auth_data = tevent_req_callback_data(req,

+                                                            struct auth_data);

+     int ret;

+     int pam_status = PAM_SYSTEM_ERR;

+     int dp_err;

+ 

+     ret = krb5_auth_recv(req, &pam_status, &dp_err);

+     talloc_free(req);

+     if (ret) {

+         DEBUG(1, ("krb5_auth request failed.\n"));

+     } else {

+         if (pam_status == PAM_SUCCESS) {

+             DEBUG(4, ("Successfully authenticated user [%s].\n",

+                       auth_data->pd->user));

+         } else {

+             DEBUG(1, ("Failed to authenticate user [%s].\n",

+                       auth_data->pd->user));

+         }

+     }

+ 

+     talloc_free(auth_data);

+ }

+ 

+ static errno_t authenticate_stored_users(

+             struct deferred_auth_ctx *deferred_auth_ctx)

+ {

+     int ret;

+     hash_table_t *uid_table;

+     struct hash_iter_context_t *iter;

+     hash_entry_t *entry;

+     hash_key_t key;

+     hash_value_t value;

+     struct pam_data *pd;

+     struct auth_data *auth_data;

+     struct tevent_timer *te;

+ 

+     ret = get_uid_table(deferred_auth_ctx, &uid_table);

+     if (ret != HASH_SUCCESS) {

+         DEBUG(1, ("get_uid_table failed.\n"));

+         return ret;

+     }

+ 

+     iter = new_hash_iter_context(deferred_auth_ctx->user_table);

+     if (iter == NULL) {

+         DEBUG(1, ("new_hash_iter_context failed.\n"));

+         return EINVAL;

+     }

+ 

+     while ((entry = iter->next(iter)) != NULL) {

+         key.type = HASH_KEY_ULONG;

+         key.ul = entry->key.ul;

+         pd = talloc_get_type(entry->value.ptr, struct pam_data);

+ 

+         ret = hash_lookup(uid_table, &key, &value);

+ 

+         if (ret == HASH_SUCCESS) {

+             DEBUG(1, ("User [%s] is still logged in, "

+                       "trying online authentication.\n", pd->user));

+ 

+             auth_data = talloc_zero(deferred_auth_ctx->be_ctx,

+                                     struct auth_data);

+             if (auth_data == NULL) {

+                 DEBUG(1, ("talloc_zero failed.\n"));

+             } else {

+                 auth_data->pd = talloc_steal(auth_data, pd);

+                 auth_data->krb5_ctx = deferred_auth_ctx->krb5_ctx;

+                 auth_data->be_ctx = deferred_auth_ctx->be_ctx;

+ 

+                 te = tevent_add_timer(deferred_auth_ctx->ev,

+                                       auth_data, tevent_timeval_current(),

+                                       authenticate_user, auth_data);

+                 if (te == NULL) {

+                     DEBUG(1, ("tevent_add_timer failed.\n"));

+                 }

+             }

+         } else {

+             DEBUG(1, ("User [%s] is not logged in anymore, "

+                       "discarding online authentication.\n", pd->user));

+             talloc_free(pd);

+         }

+ 

+         ret = hash_delete(deferred_auth_ctx->user_table,

+                           &entry->key);

+         if (ret != HASH_SUCCESS) {

+             DEBUG(1, ("hash_delete failed [%s].\n",

+                       hash_error_string(ret)));

+         }

+     }

+ 

+     talloc_free(iter);

+ 

+     return EOK;

+ }

+ 

+ static void delayed_online_authentication_callback(void *private_data)

+ {

+     struct deferred_auth_ctx *deferred_auth_ctx =

+             talloc_get_type(private_data, struct deferred_auth_ctx);

+     int ret;

+ 

+     if (deferred_auth_ctx->user_table == NULL) {

+         DEBUG(1, ("Delayed online authentication activated, "

+                   "but user table does not exists.\n"));

+         return;

+     }

+ 

+     DEBUG(5, ("Backend is online, starting delayed online authentication.\n"));

+     ret = authenticate_stored_users(deferred_auth_ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("authenticate_stored_users failed.\n"));

+     }

+ 

+     return;

+ }

+ 

+ errno_t add_user_to_delayed_online_authentication(struct krb5_ctx *krb5_ctx,

+                                                   struct pam_data *pd,

+                                                   uid_t uid)

+ {

+     int ret;

+     hash_key_t key;

+     hash_value_t value;

+     struct pam_data *new_pd;

+ 

+     if (krb5_ctx->deferred_auth_ctx == NULL) {

+         DEBUG(1, ("Missing context for delayed online authentication.\n"));

+         return EINVAL;

+     }

+ 

+     if (krb5_ctx->deferred_auth_ctx->user_table == NULL) {

+         DEBUG(1, ("user_table not available.\n"));

+         return EINVAL;

+     }

+ 

+     if (pd->authtok_size == 0 || pd->authtok == NULL) {

+         DEBUG(1, ("Missing authtok for user [%s].\n", pd->user));

+         return EINVAL;

+     }

+ 

+     ret = copy_pam_data(krb5_ctx->deferred_auth_ctx, pd, &new_pd);

+     if (ret != EOK) {

+         DEBUG(1, ("copy_pam_data failed\n"));

+         return ENOMEM;

+     }

+ 

+ 

+ #ifdef USE_KEYRING

+     new_pd->key_serial = add_key("user", new_pd->user, new_pd->authtok,

+                                  new_pd->authtok_size, KEY_SPEC_THREAD_KEYRING);

+     if (new_pd->key_serial == -1) {

+         ret = errno;

+         DEBUG(1, ("add_key fialed [%d][%s].\n", ret, strerror(ret)));

+         talloc_free(new_pd);

+         return ret;

+     }

+     DEBUG(9, ("Saved authtok of user [%s] with serial [%ld].\n",

+               new_pd->user, new_pd->key_serial));

+     memset(new_pd->authtok, 0, new_pd->authtok_size);

+ #endif

+ 

+     key.type = HASH_KEY_ULONG;

+     key.ul = uid;

+     value.type = HASH_VALUE_PTR;

+     value.ptr = new_pd;

+ 

+     ret = hash_enter(krb5_ctx->deferred_auth_ctx->user_table,

+                      &key, &value);

+     if (ret != HASH_SUCCESS) {

+         DEBUG(1, ("Cannot add user [%s] to table [%s], "

+                   "delayed online authentication not possible.\n",

+                   pd->user, hash_error_string(ret)));

+         talloc_free(new_pd);

+         return ENOMEM;

+     }

+ 

+     DEBUG(9, ("Added user [%s] successfully to "

+               "delayed online authentication.\n", pd->user));

+ 

+     return EOK;

+ }

+ 

+ errno_t init_delayed_online_authentication(struct krb5_ctx *krb5_ctx,

+                                            struct be_ctx *be_ctx,

+                                            struct tevent_context *ev)

+ {

+     int ret;

+     hash_table_t *tmp_table;

+ 

+     ret = get_uid_table(krb5_ctx, &tmp_table);

+     if (ret != EOK) {

+         if (ret == ENOSYS) {

+             DEBUG(0, ("Delayed online auth was requested "

+                       "on an unsupported system.\n"));

+         } else {

+             DEBUG(0, ("Delayed online auth was requested "

+                       "but initialisation failed.\n"));

+         }

+         return ret;

+     }

+     ret = hash_destroy(tmp_table);

+     if (ret != HASH_SUCCESS) {

+         DEBUG(1, ("hash_destroy failed [%s].\n", hash_error_string(ret)));

+         return EFAULT;

+     }

+ 

+     krb5_ctx->deferred_auth_ctx = talloc_zero(krb5_ctx,

+                                           struct deferred_auth_ctx);

+     if (krb5_ctx->deferred_auth_ctx == NULL) {

+         DEBUG(1, ("talloc_zero failed.\n"));

+         return ENOMEM;

+     }

+ 

+     ret = hash_create_ex(INITIAL_USER_TABLE_SIZE,

+                          &krb5_ctx->deferred_auth_ctx->user_table,

+                          0, 0, 0, 0, hash_talloc, hash_talloc_free,

+                          krb5_ctx->deferred_auth_ctx,

+                          NULL, NULL);

+     if (ret != HASH_SUCCESS) {

+         DEBUG(1, ("hash_create_ex failed [%s]\n", hash_error_string(ret)));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     krb5_ctx->deferred_auth_ctx->be_ctx = be_ctx;

+     krb5_ctx->deferred_auth_ctx->krb5_ctx = krb5_ctx;

+     krb5_ctx->deferred_auth_ctx->ev = ev;

+ 

+     ret = be_add_online_cb(krb5_ctx, be_ctx,

+                            delayed_online_authentication_callback,

+                            krb5_ctx->deferred_auth_ctx, NULL);

+     if (ret != EOK) {

+         DEBUG(1, ("be_add_online_cb failed.\n"));

+         goto fail;

+     }

+ 

+     /* TODO: add destructor */

+ 

+     return EOK;

+ fail:

+     talloc_zfree(krb5_ctx->deferred_auth_ctx);

+     return ret;

+ }

file modified
+21 -10
@@ -48,7 +48,6 @@

  {

      struct krb5_ctx *ctx = NULL;

      int ret;

-     struct tevent_signal *sige;

      unsigned v;

      FILE *debug_filep;

      const char *krb5_servers;
@@ -89,8 +88,7 @@

  

      krb5_servers = dp_opt_get_string(ctx->opts, KRB5_KDC);

      if (krb5_servers == NULL) {

-         DEBUG(0, ("Missing krb5_kdcip option!\n"));

-         return EINVAL;

+         DEBUG(1, ("Missing krb5_kdcip option, using service discovery!\n"));

      }

  

      krb5_realm = dp_opt_get_string(ctx->opts, KRB5_REALM);
@@ -107,8 +105,9 @@

      }

  

      krb5_kpasswd_servers = dp_opt_get_string(ctx->opts, KRB5_KPASSWD);

-     if (krb5_kpasswd_servers == NULL) {

-         DEBUG(0, ("Missing krb5_kpasswd option, using KDC!\n"));

+     if (krb5_kpasswd_servers == NULL && krb5_servers != NULL) {

+         DEBUG(0, ("Missing krb5_kpasswd option and KDC set explicitly, "

+                   "will use KDC for pasword change operations!\n"));

          ctx->kpasswd_service = NULL;

      } else {

          ret = krb5_service_init(ctx, bectx, SSS_KRB5KPASSWD_FO_SRV,
@@ -120,17 +119,29 @@

          }

      }

  

+     if (dp_opt_get_bool(ctx->opts, KRB5_STORE_PASSWORD_IF_OFFLINE)) {

+         ret = init_delayed_online_authentication(ctx, bectx, bectx->ev);

+         if (ret != EOK) {

+             DEBUG(1, ("init_delayed_online_authentication failed.\n"));

+             goto fail;

+         }

+     }

+ 

      ret = check_and_export_options(ctx->opts, bectx->domain);

      if (ret != EOK) {

          DEBUG(1, ("check_and_export_options failed.\n"));

          goto fail;

      }

  

-     sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO,

-                              child_sig_handler, NULL);

-     if (sige == NULL) {

-         DEBUG(1, ("tevent_add_signal failed.\n"));

-         ret = ENOMEM;

+     ret = krb5_install_sigterm_handler(bectx->ev, ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("krb5_install_sigterm_handler failed.\n"));

+         goto fail;

+     }

+ 

+     ret = krb5_install_offline_callback(bectx, ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("krb5_install_offline_callback failed.\n"));

          goto fail;

      }

  

@@ -90,7 +90,7 @@

                  break;

              case 'p':

                  if (kr->upn == NULL) {

-                     DEBUG(1, ("Cannot expand user principle name template "

+                     DEBUG(1, ("Cannot expand user principal name template "

                                "because upn is empty.\n"));

                      return NULL;

                  }

file modified
+124 -12
@@ -46,6 +46,12 @@

  #include "providers/ldap/ldap_common.h"

  #include "providers/ldap/sdap_async.h"

  

+ /* MIT Kerberos has the same hardcoded warning interval of 7 days. Due to the

+  * fact that using the expiration time of a Kerberos password with LDAP

+  * authentication is presumably a rare case a separate config option is not

+  * necessary. */

+ #define KERBEROS_PWEXPIRE_WARNING_TIME (7 * 24 * 60 * 60)

+ 

  enum pwexpire {

      PWEXPIRE_NONE = 0,

      PWEXPIRE_LDAP_PASSWORD_POLICY,
@@ -53,12 +59,42 @@

      PWEXPIRE_SHADOW

  };

  

+ static errno_t add_expired_warning(struct pam_data *pd, long exp_time)

+ {

+     int ret;

+     uint32_t *data;

+ 

+     if (exp_time < 0 || exp_time > UINT32_MAX) {

+         DEBUG(1, ("Time to expire out of range.\n"));

+         return EINVAL;

+     }

+ 

+     data = talloc_array(pd, uint32_t, 2);

+     if (data == NULL) {

+         DEBUG(1, ("talloc_size failed.\n"));

+         return ENOMEM;

+     }

+ 

+     data[0] = SSS_PAM_USER_INFO_EXPIRE_WARN;

+     data[1] = (uint32_t) exp_time;

+ 

+     ret = pam_add_response(pd, SSS_PAM_USER_INFO, 2 * sizeof(uint32_t),

+                            (uint8_t *) data);

+     if (ret != EOK) {

+         DEBUG(1, ("pam_add_response failed.\n"));

+     }

+ 

+     return EOK;

+ }

+ 

  static errno_t check_pwexpire_kerberos(const char *expire_date, time_t now,

+                                        struct pam_data *pd,

                                         enum sdap_result *result)

  {

      char *end;

      struct tm tm;

      time_t expire_time;

+     int ret;

  

      memset(&tm, 0, sizeof(tm));

  
@@ -92,16 +128,27 @@

          *result = SDAP_AUTH_PW_EXPIRED;

      } else {

          *result = SDAP_AUTH_SUCCESS;

+ 

+         if (pd != NULL &&

+             difftime(now + KERBEROS_PWEXPIRE_WARNING_TIME, expire_time) > 0.0) {

+             ret = add_expired_warning(pd, (long) difftime(expire_time, now));

+             if (ret != EOK) {

+                 DEBUG(1, ("add_expired_warning failed.\n"));

+             }

+         }

      }

  

      return EOK;

  }

  

  static errno_t check_pwexpire_shadow(struct spwd *spwd, time_t now,

+                                      struct pam_data *pd,

                                       enum sdap_result *result)

  {

      long today;

      long password_age;

+     long exp;

+     int ret;

  

      if (spwd->sp_lstchg <= 0) {

          DEBUG(4, ("Last change day is not set, new password needed.\n"));
@@ -132,7 +179,21 @@

          return EOK;

      }

  

- /* TODO: evaluate spwd->min and spwd->warn */

+     if (pd != NULL && spwd->sp_max != -1 && spwd->sp_warn != -1 &&

+         password_age > spwd->sp_max - spwd->sp_warn ) {

+ 

+         /* add_expired_warning() expects time in seconds */

+         exp = (spwd->sp_max - password_age) * (60 * 60 * 24);

+         if (exp == 0) {

+             /* Seconds until next midnight */

+             exp = ((today + 1) * (60 * 60 * 24)) - now;

+         }

+ 

+         ret = add_expired_warning(pd, exp);

+         if (ret != EOK) {

+             DEBUG(1, ("add_expired_warning failed.\n"));

+         }

+     }

  

      *result = SDAP_AUTH_SUCCESS;

      return EOK;
@@ -478,6 +539,7 @@

      struct fo_server *srv;

  };

  

+ static struct tevent_req *auth_get_server(struct tevent_req *req);

  static void auth_resolve_done(struct tevent_req *subreq);

  static void auth_connect_done(struct tevent_req *subreq);

  static void auth_get_user_dn_done(struct tevent_req *subreq);
@@ -489,22 +551,26 @@

                                      const char *username,

                                      struct dp_opt_blob password)

  {

-     struct tevent_req *req, *subreq;

+     struct tevent_req *req;

      struct auth_state *state;

  

      req = tevent_req_create(memctx, &state, struct auth_state);

      if (!req) return NULL;

  

+     /* Treat a zero-length password as a failure */

+     if (password.length == 0) {

+         state->result = SDAP_AUTH_FAILED;

+         tevent_req_done(req);

+         return tevent_req_post(req, ev);

+     }

+ 

      state->ev = ev;

      state->ctx = ctx;

      state->username = username;

      state->password = password;

      state->srv = NULL;

  

-     subreq = be_resolve_server_send(state, ev, ctx->be, ctx->service->name);

-     if (!subreq) goto fail;

- 

-     tevent_req_set_callback(subreq, auth_resolve_done, req);

+     if (!auth_get_server(req)) goto fail;

  

      return req;

  
@@ -513,6 +579,27 @@

      return NULL;

  }

  

+ static struct tevent_req *auth_get_server(struct tevent_req *req)

+ {

+     struct tevent_req *next_req;

+     struct auth_state *state = tevent_req_data(req,

+                                                struct auth_state);

+ 

+      /* NOTE: this call may cause service->uri to be refreshed

+       * with a new valid server. Do not use service->uri before */

+     next_req = be_resolve_server_send(state,

+                                       state->ev,

+                                       state->ctx->be,

+                                       state->ctx->service->name);

+     if (!next_req) {

+         DEBUG(1, ("be_resolve_server_send failed.\n"));

+         return NULL;

+     }

+ 

+     tevent_req_set_callback(next_req, auth_resolve_done, req);

+     return next_req;

+ }

+ 

  static void auth_resolve_done(struct tevent_req *subreq)

  {

      struct tevent_req *req = tevent_req_callback_data(subreq,
@@ -520,16 +607,26 @@

      struct auth_state *state = tevent_req_data(req,

                                                      struct auth_state);

      int ret;

+     bool use_tls = true;

  

      ret = be_resolve_server_recv(subreq, &state->srv);

      talloc_zfree(subreq);

      if (ret) {

-         tevent_req_error(req, ret);

+         /* all servers have been tried and none

+          * was found good, go offline */

+         tevent_req_error(req, EIO);

          return;

      }

  

+     /* Determine whether we need to use TLS */

+     if (sdap_is_secure_uri(state->ctx->service->uri)) {

+         DEBUG(8, ("[%s] is a secure channel. No need to run START_TLS\n",

+                   state->ctx->service->uri));

+         use_tls = false;

+     }

+ 

      subreq = sdap_connect_send(state, state->ev, state->ctx->opts,

-                                state->ctx->service->uri, true);

+                                state->ctx->service->uri, use_tls);

      if (!subreq) {

          tevent_req_error(req, ENOMEM);

          return;
@@ -553,6 +650,12 @@

              /* mark this server as bad if connection failed */

              fo_set_port_status(state->srv, PORT_NOT_WORKING);

          }

+         if (ret == ETIMEDOUT) {

+             if (auth_get_server(req) == NULL) {

+                 tevent_req_error(req, ENOMEM);

+             }

+             return;

+         }

  

          tevent_req_error(req, ret);

          return;
@@ -701,6 +804,14 @@

          goto done;

      }

  

+     if (pd->priv == 1 && pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM &&

+         pd->authtok_size == 0) {

+         DEBUG(4, ("Password reset by root is not supported.\n"));

+         pd->pam_status = PAM_PERM_DENIED;

+         dp_err = DP_ERR_OK;

+         goto done;

+     }

+ 

      DEBUG(2, ("starting password change request for user [%s].\n", pd->user));

  

      pd->pam_status = PAM_SYSTEM_ERR;
@@ -769,13 +880,14 @@

          DEBUG(9, ("Initial authentication for change password operation "

                    "successful.\n"));

          state->pd->pam_status = PAM_SUCCESS;

+         dp_err = DP_ERR_OK;

          goto done;

      }

  

      if (result == SDAP_AUTH_SUCCESS) {

          switch (pw_expire_type) {

              case PWEXPIRE_SHADOW:

-                 ret = check_pwexpire_shadow(pw_expire_data, time(NULL),

+                 ret = check_pwexpire_shadow(pw_expire_data, time(NULL), NULL,

                                              &result);

                  if (ret != EOK) {

                      DEBUG(1, ("check_pwexpire_shadow failed.\n"));
@@ -784,7 +896,7 @@

                  }

                  break;

              case PWEXPIRE_KERBEROS:

-                 ret = check_pwexpire_kerberos(pw_expire_data, time(NULL),

+                 ret = check_pwexpire_kerberos(pw_expire_data, time(NULL), NULL,

                                                &result);

                  if (ret != EOK) {

                      DEBUG(1, ("check_pwexpire_kerberos failed.\n"));
@@ -986,7 +1098,7 @@

          switch (pw_expire_type) {

              case PWEXPIRE_SHADOW:

                  ret = check_pwexpire_shadow(pw_expire_data, time(NULL),

-                                             &result);

+                                             state->pd, &result);

                  if (ret != EOK) {

                      DEBUG(1, ("check_pwexpire_shadow failed.\n"));

                      state->pd->pam_status = PAM_SYSTEM_ERR;
@@ -995,7 +1107,7 @@

                  break;

              case PWEXPIRE_KERBEROS:

                  ret = check_pwexpire_kerberos(pw_expire_data, time(NULL),

-                                               &result);

+                                               state->pd, &result);

                  if (ret != EOK) {

                      DEBUG(1, ("check_pwexpire_kerberos failed.\n"));

                      state->pd->pam_status = PAM_SYSTEM_ERR;

@@ -40,6 +40,7 @@

      const char *realm_str;

      const char *princ_str;

      const char *keytab_name;

+     krb5_deltat lifetime;

  };

  

  static errno_t unpack_buffer(uint8_t *buf, size_t size,
@@ -86,6 +87,10 @@

          p += len;

      }

  

+     /* ticket lifetime */

+     SAFEALIGN_COPY_INT32_CHECK(&ibuf->lifetime, buf + p, size, &p);

+     DEBUG(7, ("lifetime: %d\n", ibuf->lifetime));

+ 

      return EOK;

  }

  
@@ -118,6 +123,7 @@

                                    const char *realm_str,

                                    const char *princ_str,

                                    const char *keytab_name,

+                                   const krb5_deltat lifetime,

                                    const char **ccname_out)

  {

      char *ccname;
@@ -130,6 +136,10 @@

      krb5_creds my_creds;

      krb5_get_init_creds_opt options;

      krb5_error_code krberr;

+     krb5_kt_cursor cursor;

+     krb5_keytab_entry entry;

+     char *principal;

+     bool found;

      int ret;

  

      krberr = krb5_init_context(&context);
@@ -194,8 +204,57 @@

          krberr = krb5_kt_default(context, &keytab);

      }

      if (krberr) {

-         DEBUG(2, ("Failed to read keytab file: %s\n",

+         DEBUG(0, ("Failed to read keytab file: %s\n",

                    sss_krb5_get_error_message(context, krberr)));

+ 

+         ret = EFAULT;

+         goto done;

+     }

+ 

+     /* Verify the keytab */

+     krberr = krb5_kt_start_seq_get(context, keytab, &cursor);

+     if (krberr) {

+         DEBUG(0, ("Cannot read keytab [%s].\n", keytab_name));

+ 

+         sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. "

+                              "Unable to create GSSAPI-encrypted LDAP connection.",

+                              keytab_name, krberr,

+                              sss_krb5_get_error_message(context, krberr));

+ 

+         ret = EFAULT;

+         goto done;

+     }

+ 

+     found = false;

+     while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){

+         krb5_unparse_name(context, entry.principal, &principal);

+         if (strcmp(full_princ, principal) == 0) {

+             found = true;

+         }

+         free(principal);

+         krb5_free_keytab_entry_contents(context, &entry);

+ 

+         if (found) {

+             break;

+         }

+     }

+     krberr = krb5_kt_end_seq_get(context, keytab, &cursor);

+     if (krberr) {

+         DEBUG(0, ("Could not close keytab.\n"));

+         sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].",

+                              keytab_name);

+         ret = EFAULT;

+         goto done;

+     }

+ 

+     if (!found) {

+         DEBUG(0, ("Principal [%s] not found in keytab [%s]\n",

+                   full_princ, keytab_name));

+         sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: "

+                              "Principal [%s] was not found. "

+                              "Unable to create GSSAPI-encrypted LDAP connection.",

+                              keytab_name, full_princ);

+ 

          ret = EFAULT;

          goto done;

      }
@@ -220,15 +279,17 @@

      krb5_get_init_creds_opt_set_address_list(&options, NULL);

      krb5_get_init_creds_opt_set_forwardable(&options, 0);

      krb5_get_init_creds_opt_set_proxiable(&options, 0);

-     /* set a very short lifetime, we don't keep the ticket around */

-     krb5_get_init_creds_opt_set_tkt_life(&options, 300);

+     krb5_get_init_creds_opt_set_tkt_life(&options, lifetime);

  

      krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc,

                                          keytab, 0, NULL, &options);

  

      if (krberr) {

-         DEBUG(2, ("Failed to init credentials: %s\n",

+         DEBUG(0, ("Failed to init credentials: %s\n",

                    sss_krb5_get_error_message(context, krberr)));

+         sss_log(SSS_LOG_ERR, "Failed to initialize credentials using keytab [%s]: %s. "

+                              "Unable to create GSSAPI-encrypted LDAP connection.",

+                              keytab_name, sss_krb5_get_error_message(context, krberr));

          ret = EFAULT;

          goto done;

      }
@@ -392,7 +453,7 @@

  

      kerr = ldap_child_get_tgt_sync(main_ctx,

                                     ibuf->realm_str, ibuf->princ_str,

-                                    ibuf->keytab_name, &ccname);

+                                    ibuf->keytab_name, ibuf->lifetime, &ccname);

      if (kerr != EOK) {

          DEBUG(1, ("ldap_child_get_tgt_sync failed.\n"));

          /* Do not return, must report failure */

@@ -6,7 +6,7 @@

      Authors:

          Simo Sorce <ssorce@redhat.com>

  

-     Copyright (C) 2008-2009 Red Hat

+     Copyright (C) 2008-2010 Red Hat

  

      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
@@ -24,6 +24,7 @@

  

  #include "providers/ldap/ldap_common.h"

  #include "providers/fail_over.h"

+ #include "providers/ldap/sdap_async_private.h"

  

  #include "util/sss_krb5.h"

  
@@ -31,12 +32,12 @@

  int ldap_child_debug_fd = -1;

  

  struct dp_option default_basic_opts[] = {

-     { "ldap_uri", DP_OPT_STRING, { "ldap://localhost" }, NULL_STRING },

+     { "ldap_uri", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_search_base", DP_OPT_STRING, { "dc=example,dc=com" }, NULL_STRING },

      { "ldap_default_bind_dn", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_default_authtok_type", DP_OPT_STRING, NULL_STRING, NULL_STRING},

      { "ldap_default_authtok", DP_OPT_BLOB, NULL_BLOB, NULL_BLOB },

-     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },

+     { "ldap_search_timeout", DP_OPT_NUMBER, { .number = 5 }, NULL_NUMBER },

      { "ldap_network_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },

      { "ldap_opt_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },

      { "ldap_tls_reqcert", DP_OPT_STRING, { "hard" }, NULL_STRING },
@@ -47,10 +48,9 @@

      { "ldap_group_search_scope", DP_OPT_STRING, { "sub" }, NULL_STRING },

      { "ldap_group_search_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_schema", DP_OPT_STRING, { "rfc2307" }, NULL_STRING },

-     { "ldap_offline_timeout", DP_OPT_NUMBER, { .number = 60 }, NULL_NUMBER },

      { "ldap_force_upper_case_realm", DP_OPT_BOOL, BOOL_FALSE, BOOL_FALSE },

      { "ldap_enumeration_refresh_timeout", DP_OPT_NUMBER, { .number = 300 }, NULL_NUMBER },

-     { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 10800 }, NULL_NUMBER },

+     { "ldap_purge_cache_timeout", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },

      { "entry_cache_timeout", DP_OPT_NUMBER, { .number = 5400 }, NULL_NUMBER },

      { "ldap_tls_cacert", DP_OPT_STRING, NULL_STRING, NULL_STRING },

      { "ldap_tls_cacertdir", DP_OPT_STRING, NULL_STRING, NULL_STRING },
@@ -61,9 +61,13 @@

      { "ldap_krb5_init_creds", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },

      /* use the same parm name as the krb5 module so we set it only once */

      { "krb5_realm", DP_OPT_STRING, NULL_STRING, NULL_STRING },

-     { "ldap_pwd_policy", DP_OPT_STRING, { "none" } , NULL_STRING },

+     { "ldap_pwd_policy", DP_OPT_STRING, { "none" }, NULL_STRING },

      { "ldap_referrals", DP_OPT_BOOL, BOOL_TRUE, BOOL_TRUE },

-     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER }

+     { "account_cache_expiration", DP_OPT_NUMBER, { .number = 0 }, NULL_NUMBER },

+     { "ldap_dns_service_name", DP_OPT_STRING, { SSS_LDAP_SRV_NAME }, NULL_STRING },

+     { "ldap_access_filter", DP_OPT_STRING, NULL_STRING, NULL_STRING },

+     { "ldap_krb5_ticket_lifetime", DP_OPT_NUMBER, { .number = (24 * 60 * 60) }, NULL_NUMBER },

+     { "ldap_group_nesting_level", DP_OPT_NUMBER, { .number = 2 }, NULL_NUMBER }

  };

  

  struct sdap_attr_map generic_attr_map[] = {
@@ -356,10 +360,19 @@

  

  void sdap_mark_offline(struct sdap_id_ctx *ctx)

  {

+     int ret;

+ 

      if (ctx->gsh) {

          /* make sure we mark the connection as gone when we go offline so that

           * we do not try to reuse a bad connection by mistale later */

-         talloc_zfree(ctx->gsh);

+         ctx->gsh->connected = false;

+         ret = remove_ldap_connection_callbacks(ctx->gsh);

+         if (ret != EOK) {

+             DEBUG(1, ("Could not clear ldap connection callbacks\n"));

+             /* Not really anything we can do about this, so proceed

+              * and hope for the best.

+              */

+         }

      }

  

      be_mark_offline(ctx->be);
@@ -507,6 +520,7 @@

  {

      struct timeval tv;

      int ret = EOK;

+     int delay;

  

      /* set up enumeration task */

      if (ctx->be->domain->enumerate) {
@@ -516,7 +530,14 @@

          ret = ldap_id_enumerate_set_timer(ctx, tv);

      } else {

          /* the enumeration task, runs the cleanup process by itself,

-          * but if enumeration is not runnig we need to schedule it */

+          * but if enumeration is not running we need to schedule it */

+         delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);

+         if (delay == 0) {

+             /* Cleanup has been explicitly disabled, so we won't

+              * schedule any cleanup tasks.

+              */

+             return EOK;

+         }

  

          /* run the first one in a couple of seconds so that we have time to

           * finish initializations first*/
@@ -537,30 +558,46 @@

      if (!service) return;

  

      tmp = (const char *)fo_get_server_user_data(server);

-     if (tmp && ldap_is_ldap_url(tmp)) {

-         new_uri = talloc_strdup(service, tmp);

+ 

+     if (fo_is_srv_lookup(server)) {

+         if (!tmp) {

+             DEBUG(1, ("Unknown service, using ldap\n"));

+             tmp = SSS_LDAP_SRV_NAME;

+         }

+         new_uri = talloc_asprintf(service, "%s://%s:%d",

+                                   tmp,

+                                   fo_get_server_name(server),

+                                   fo_get_server_port(server));

      } else {

-         new_uri = talloc_asprintf(service, "ldap://%s",

-                                   fo_get_server_name(server));

+         if (tmp && ldap_is_ldap_url(tmp)) {

+             new_uri = talloc_strdup(service, tmp);

+         } else {

+             new_uri = talloc_asprintf(service, "ldap://%s",

+                                     fo_get_server_name(server));

+         }

      }

+ 

      if (!new_uri) {

          DEBUG(2, ("Failed to copy URI ...\n"));

          return;

      }

  

+     DEBUG(6, ("Constructed uri '%s'\n", new_uri));

+ 

      /* free old one and replace with new one */

      talloc_zfree(service->uri);

      service->uri = new_uri;

  }

  

  int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,

-                       const char *service_name, const char *urls,

-                       struct sdap_service **_service)

+                       const char *service_name, const char *dns_service_name,

+                       const char *urls, struct sdap_service **_service)

  {

      TALLOC_CTX *tmp_ctx;

      struct sdap_service *service;

      LDAPURLDesc *lud;

      char **list = NULL;

+     char *srv_user_data;

      int ret;

      int i;

  
@@ -587,6 +624,10 @@

          goto done;

      }

  

+     if (!urls) {

+         urls = BE_SRV_IDENTIFIER;

+     }

+ 

      /* split server parm into a list */

      ret = split_on_separator(tmp_ctx, urls, ',', true, &list, NULL);

      if (ret != EOK) {
@@ -596,6 +637,26 @@

  

      /* now for each URI add a new server to the failover service */

      for (i = 0; list[i]; i++) {

+         if (be_fo_is_srv_identifier(list[i])) {

+             srv_user_data = talloc_strdup(service, dns_service_name);

+             if (!srv_user_data) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+ 

+             ret = be_fo_add_srv_server(ctx, service_name,

+                                        dns_service_name, FO_PROTO_TCP,

+                                        ctx->domain->name,

+                                        srv_user_data);

+             if (ret) {

+                 DEBUG(0, ("Failed to add server\n"));

+                 goto done;

+             }

+ 

+             DEBUG(6, ("Added service lookup\n"));

+             continue;

+         }

+ 

          ret = ldap_url_parse(list[i], &lud);

          if (ret != LDAP_SUCCESS) {

              DEBUG(0, ("Failed to parse ldap URI (%s)!\n", list[i]));
@@ -632,3 +693,21 @@

      return ret;

  }

  

+ void sdap_gsh_disconnect_callback(void *pvt)

+ {

+     struct sdap_id_ctx *ctx = talloc_get_type(pvt, struct sdap_id_ctx);

+ 

+     if (ctx->gsh) {

+         ctx->gsh->connected = false;

+     }

+ }

+ 

+ bool sdap_is_secure_uri(const char *uri)

+ {

+     /* LDAPS and LDAPI URI's are secure channels */

+     if ((strncasecmp(uri, LDAP_SSL_URI, strlen(LDAP_SSL_URI)) == 0) ||

+         (strncasecmp(uri, LDAP_LDAPI_URI, strlen(LDAP_LDAPI_URI)) == 0)) {

+         return true;

+     }

+     return false;

+ }

@@ -30,6 +30,12 @@

  #define PWD_POL_OPT_SHADOW "shadow"

  #define PWD_POL_OPT_MIT "mit_kerberos"

  

+ #define SSS_LDAP_SRV_NAME "ldap"

+ 

+ #define LDAP_STANDARD_URI "ldap://"

+ #define LDAP_SSL_URI "ldaps://"

+ #define LDAP_LDAPI_URI "ldapi://"

+ 

  /* a fd the child process would log into */

  extern int ldap_child_debug_fd;

  
@@ -71,14 +77,17 @@

  /* chpass */

  void sdap_pam_chpass_handler(struct be_req *breq);

  

+ /* access */

+ void sdap_pam_access_handler(struct be_req *breq);

+ 

  

  

  void sdap_handler_done(struct be_req *req, int dp_err,

                         int error, const char *errstr);

  

- int sdap_service_init(TALLOC_CTX *mmectx, struct be_ctx *ctx,

-                       const char *service_name, const char *urls,

-                       struct sdap_service **service);

+ int sdap_service_init(TALLOC_CTX *memctx, struct be_ctx *ctx,

+                       const char *service_name, const char *dns_service_name,

+                       const char *urls, struct sdap_service **_service);

  

  /* options parser */

  int ldap_get_options(TALLOC_CTX *memctx,
@@ -112,4 +121,8 @@

  /* setup child logging */

  int setup_child(struct sdap_id_ctx *ctx);

  

+ void sdap_gsh_disconnect_callback(void *pvt);

+ 

+ bool sdap_is_secure_uri(const char *uri);

+ 

  #endif /* _LDAP_COMMON_H_ */

file modified
+71 -68
@@ -27,6 +27,7 @@

  #include <sys/time.h>

  

  #include "util/util.h"

+ #include "util/strtonum.h"

  #include "db/sysdb.h"

  #include "providers/ldap/ldap_common.h"

  #include "providers/ldap/sdap_async.h"
@@ -100,8 +101,6 @@

  

      if (!sdap_connected(ctx)) {

  

-         if (ctx->gsh) talloc_zfree(ctx->gsh);

- 

          /* FIXME: add option to decide if tls should be used

           * or SASL/GSSAPI, etc ... */

          subreq = sdap_cli_connect_send(state, ev, ctx->opts,
@@ -202,10 +201,9 @@

              return;

  

          case BE_FILTER_IDNUM:

-             errno = 0;

-             uid = (uid_t)strtol(state->name, &endptr, 0);

+             uid = (uid_t) strtouint32(state->name, &endptr, 0);

              if (errno || *endptr || (state->name == endptr)) {

-                 tevent_req_error(req, errno);

+                 tevent_req_error(req, errno ? errno : EINVAL);

                  return;

              }

  
@@ -323,8 +321,6 @@

  

      if (!sdap_connected(ctx)) {

  

-         if (ctx->gsh) talloc_zfree(ctx->gsh);

- 

          /* FIXME: add option to decide if tls should be used

           * or SASL/GSSAPI, etc ... */

          subreq = sdap_cli_connect_send(state, ev, ctx->opts,
@@ -425,10 +421,9 @@

              return;

  

          case BE_FILTER_IDNUM:

-             errno = 0;

-             gid = (gid_t)strtol(state->name, &endptr, 0);

+             gid = (gid_t) strtouint32(state->name, &endptr, 0);

              if (errno || *endptr || (state->name == endptr)) {

-                 tevent_req_error(req, errno);

+                 tevent_req_error(req, errno ? errno : EINVAL);

                  return;

              }

  
@@ -511,8 +506,6 @@

  

      if (!sdap_connected(ctx)) {

  

-         if (ctx->gsh) talloc_zfree(ctx->gsh);

- 

          /* FIXME: add option to decide if tls should be used

           * or SASL/GSSAPI, etc ... */

          subreq = sdap_cli_connect_send(state, ev, ctx->opts,
@@ -700,96 +693,106 @@

      if (ret != EOK) return sdap_handler_done(breq, DP_ERR_FATAL, ret, err);

  }

  

- static void sdap_account_info_users_done(struct tevent_req *req)

+ static void sdap_account_info_immediate(struct tevent_context *ctx,

+                                         struct tevent_immediate *im,

+                                         void *private_data)

+ {

+     struct be_req *breq = talloc_get_type(private_data, struct be_req);

+ 

+     sdap_account_info_handler(breq);

+ }

+ 

+ static int sdap_account_info_restart(struct be_req *breq)

+ {

+     struct tevent_immediate *im;

+ 

+     breq->restarts++;

+     if (breq->restarts > MAX_BE_REQ_RESTARTS) {

+         return ELOOP;

+     }

+ 

+     im = tevent_create_immediate(breq);

+     if (!im) {

+         return ENOMEM;

+     }

+ 

+     /* schedule a completely new event to avoid deep recursions */

+     tevent_schedule_immediate(im, breq->be_ctx->ev,

+                               sdap_account_info_immediate, breq);

+ 

+     return EOK;

+ }

+ 

+ static void sdap_account_info_common_done(int ret, struct be_req *breq,

+                                           const char *str_on_err)

  {

-     struct be_req *breq = tevent_req_callback_data(req, struct be_req);

      struct sdap_id_ctx *ctx;

      int dp_err = DP_ERR_OK;

-     const char *error = NULL;

-     int ret;

- 

-     ret = users_get_recv(req);

-     talloc_zfree(req);

+     const char *errstr = NULL;

+     errno_t err;

  

-     if (ret) {

+     if (ret != EOK) {

          dp_err = DP_ERR_FATAL;

-         error = "Enum Users Failed";

+         errstr = str_on_err;

  

          if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) {

-             dp_err = DP_ERR_OFFLINE;

              ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,

                                    struct sdap_id_ctx);

              if (sdap_check_gssapi_reconnect(ctx)) {

-                 talloc_zfree(ctx->gsh);

-                 sdap_account_info_handler(breq);

-                 return;

+                 if (ctx->gsh) {

+                     /* Mark the connection as false so we don't try to use an

+                      * invalid connection by mistake later.

+                      * If the global sdap handler is NULL, it's ok not to do

+                      * anything here. It's always checked by sdap_connected()

+                      * before being used.

+                      */

+                     ctx->gsh->connected = false;

+                 }

+                 err = sdap_account_info_restart(breq);

+                 if (err == EOK) return;

              }

+ 

+             /* Couldn't reconnect, that was our last try

+              * Go offline now

+              */

+             dp_err = DP_ERR_OFFLINE;

              sdap_mark_offline(ctx);

          }

      }

  

-     sdap_handler_done(breq, dp_err, ret, error);

+     sdap_handler_done(breq, dp_err, ret, errstr);

  }

  

- static void sdap_account_info_groups_done(struct tevent_req *req)

+ static void sdap_account_info_users_done(struct tevent_req *req)

  {

      struct be_req *breq = tevent_req_callback_data(req, struct be_req);

-     struct sdap_id_ctx *ctx;

-     int dp_err = DP_ERR_OK;

-     const char *error = NULL;

      int ret;

  

-     ret = groups_get_recv(req);

+     ret = users_get_recv(req);

      talloc_zfree(req);

  

-     if (ret) {

-         dp_err = DP_ERR_FATAL;

-         error = "Enum Groups Failed";

+     sdap_account_info_common_done(ret, breq, "User lookup failed");

+ }

  

-         if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) {

-             dp_err = DP_ERR_OFFLINE;

-             ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,

-                                   struct sdap_id_ctx);

-             if (sdap_check_gssapi_reconnect(ctx)) {

-                 talloc_zfree(ctx->gsh);

-                 sdap_account_info_handler(breq);

-                 return;

-             }

-             sdap_mark_offline(ctx);

-         }

-     }

+ static void sdap_account_info_groups_done(struct tevent_req *req)

+ {

+     struct be_req *breq = tevent_req_callback_data(req, struct be_req);

+     int ret;

  

-     return sdap_handler_done(breq, dp_err, ret, error);

+     ret = groups_get_recv(req);

+     talloc_zfree(req);

+ 

+     sdap_account_info_common_done(ret, breq, "Group lookup failed");

  }

  

  static void sdap_account_info_initgr_done(struct tevent_req *req)

  {

      struct be_req *breq = tevent_req_callback_data(req, struct be_req);

-     struct sdap_id_ctx *ctx;

-     int dp_err = DP_ERR_OK;

-     const char *error = NULL;

      int ret;

  

      ret = groups_by_user_recv(req);

      talloc_zfree(req);

  

-     if (ret) {

-         dp_err = DP_ERR_FATAL;

-         error = "Init Groups Failed";

- 

-         if (ret == ETIMEDOUT || ret == EFAULT || ret == EIO) {

-             dp_err = DP_ERR_OFFLINE;

-             ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data,

-                                   struct sdap_id_ctx);

-             if (sdap_check_gssapi_reconnect(ctx)) {

-                 talloc_zfree(ctx->gsh);

-                 sdap_account_info_handler(breq);

-                 return;

-             }

-             sdap_mark_offline(ctx);

-         }

-     }

- 

-     return sdap_handler_done(breq, dp_err, ret, error);

+     sdap_account_info_common_done(ret, breq, "Init Groups Failed");

  }

  

@@ -51,6 +51,7 @@

      struct tevent_timer *timeout;

      struct tevent_req *req;

      int delay;

+     errno_t ret;

  

      if (be_is_offline(ctx->be)) {

          DEBUG(4, ("Backend is marked offline, retry later!\n"));
@@ -67,7 +68,10 @@

          /* schedule starting from now, not the last run */

          delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);

          tv = tevent_timeval_current_ofs(delay, 0);

-         ldap_id_cleanup_set_timer(ctx, tv);

+         ret = ldap_id_cleanup_set_timer(ctx, tv);

+         if (ret != EOK) {

+             DEBUG(1, ("Error setting up cleanup timer\n"));

+         }

          return;

      }

      tevent_req_set_callback(req, ldap_id_cleanup_reschedule, ctx);
@@ -78,6 +82,24 @@

      tv = tevent_timeval_current_ofs(delay, 0);

      timeout = tevent_add_timer(ctx->be->ev, req, tv,

                                 ldap_id_cleanup_timeout, req);

+     if (timeout == NULL) {

+         /* If we can't guarantee a timeout, we

+          * need to cancel the request, to avoid

+          * the possibility of starting another

+          * concurrently

+          */

+         talloc_zfree(req);

+ 

+         DEBUG(1, ("Failed to schedule cleanup, retrying later!\n"));

+         /* schedule starting from now, not the last run */

+         delay = dp_opt_get_int(ctx->opts->basic, SDAP_CACHE_PURGE_TIMEOUT);

+         tv = tevent_timeval_current_ofs(delay, 0);

+         ret = ldap_id_cleanup_set_timer(ctx, tv);

+         if (ret != EOK) {

+             DEBUG(1, ("Error setting up cleanup timer\n"));

+         }

+         return;

+     }

      return;

  }

  
@@ -391,7 +413,8 @@

          ret = cleanup_users_logged_in(state->uid_table, state->msgs[state->cur]);

          if (ret == EOK) {

              /* If the user is logged in, proceed to the next one */

-             DEBUG(5, ("User %s is still logged in, keeping his data\n", name));

+             DEBUG(5, ("User %s is still logged in or a dummy entry, "

+                       "keeping his data\n", name));

              cleanup_users_next(req);

              return;

          } else if (ret != ENOENT) {
@@ -424,9 +447,9 @@

      uid = ldb_msg_find_attr_as_uint64(msg,

                                        SYSDB_UIDNUM, 0);

      if (!uid) {

-         DEBUG(2, ("Entry %s has no UID Attribute ?!?\n",

+         DEBUG(2, ("Entry %s has no UID Attribute, fake user perhaps?\n",

                    ldb_dn_get_linearized(msg->dn)));

-         return EFAULT;

+         return ENOENT;

      }

  

      key.type = HASH_KEY_ULONG;
@@ -502,7 +525,7 @@

  {

      struct tevent_req *req, *subreq;

      struct cleanup_groups_state *state;

-     static const char *attrs[] = { SYSDB_NAME, NULL };

+     static const char *attrs[] = { SYSDB_NAME, SYSDB_GIDNUM, NULL };

      time_t now = time(NULL);

      char *subfilter;

  
@@ -575,6 +598,7 @@

      struct tevent_req *subreq;

      const char *subfilter;

      const char *dn;

+     gid_t gid;

  

      dn = ldb_dn_get_linearized(state->msgs[state->cur]->dn);

      if (!dn) {
@@ -582,8 +606,19 @@

          return;

      }

  

-     subfilter = talloc_asprintf(state, "(%s=%s)",

-                                 SYSDB_MEMBEROF, dn);

+     gid = (gid_t) ldb_msg_find_attr_as_uint(state->msgs[state->cur],

+                                             SYSDB_GIDNUM, 0);

+     if (!gid) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     /* Search for users that are members of this group, or

+      * that have this group as their primary GID

+      */

+     subfilter = talloc_asprintf(state, "(|(%s=%s)(%s=%lu))",

+                                 SYSDB_MEMBEROF, dn,

+                                 SYSDB_GIDNUM, (unsigned long) gid);

      if (!subfilter) {

          DEBUG(2, ("Failed to build filter\n"));

          tevent_req_error(req, ENOMEM);

@@ -54,6 +54,7 @@

      struct tevent_timer *timeout;

      struct tevent_req *req;

      int delay;

+     errno_t ret;

  

      if (be_is_offline(ctx->be)) {

          DEBUG(4, ("Backend is marked offline, retry later!\n"));
@@ -70,7 +71,10 @@

          /* schedule starting from now, not the last run */

          delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);

          tv = tevent_timeval_current_ofs(delay, 0);

-         ldap_id_enumerate_set_timer(ctx, tv);

+         ret = ldap_id_enumerate_set_timer(ctx, tv);

+         if (ret != EOK) {

+             DEBUG(1, ("Error setting up enumerate timer\n"));

+         }

          return;

      }

      tevent_req_set_callback(req, ldap_id_enumerate_reschedule, ctx);
@@ -81,6 +85,24 @@

      tv = tevent_timeval_current_ofs(delay, 0);

      timeout = tevent_add_timer(ctx->be->ev, req, tv,

                                 ldap_id_enumerate_timeout, req);

+     if (timeout == NULL) {

+         /* If we can't guarantee a timeout, we

+          * need to cancel the request, to avoid

+          * the possibility of starting another

+          * concurrently

+          */

+         talloc_zfree(req);

+ 

+         DEBUG(1, ("Failed to schedule enumeration, retrying later!\n"));

+         /* schedule starting from now, not the last run */

+         delay = dp_opt_get_int(ctx->opts->basic, SDAP_ENUM_REFRESH_TIMEOUT);

+         tv = tevent_timeval_current_ofs(delay, 0);

+         ret = ldap_id_enumerate_set_timer(ctx, tv);

+         if (ret != EOK) {

+             DEBUG(1, ("Error setting up enumerate timer\n"));

+         }

+         return;

+     }

      return;

  }

  
@@ -143,12 +165,14 @@

      return EOK;

  }

  

+ #define MAX_ENUM_RESTARTS 3

  

  struct global_enum_state {

      struct tevent_context *ev;

      struct sdap_id_ctx *ctx;

  

      bool purge;

+     int restarts;

  };

  

  static struct tevent_req *enum_users_send(TALLOC_CTX *memctx,
@@ -162,6 +186,8 @@

                                            bool purge);

  static void ldap_id_enum_groups_done(struct tevent_req *subreq);

  static void ldap_id_enum_cleanup_done(struct tevent_req *subreq);

+ static int ldap_id_enum_users_restart(struct tevent_req *req);

+ static int ldap_id_enum_groups_restart(struct tevent_req *req);

  

  static struct tevent_req *ldap_id_enumerate_send(struct tevent_context *ev,

                                                   struct sdap_id_ctx *ctx)
@@ -175,6 +201,7 @@

  

      state->ev = ev;

      state->ctx = ctx;

+     state->restarts = 0;

  

      ctx->last_enum = tevent_timeval_current();

  
@@ -203,6 +230,7 @@

                                                   struct global_enum_state);

      enum tevent_req_state tstate;

      uint64_t err = 0;

+     int ret;

  

      if (tevent_req_is_error(subreq, &tstate, &err)) {

          if (tstate != TEVENT_REQ_USER_ERROR) {
@@ -228,12 +256,11 @@

                    (int)err, strerror(err)));

  

          if (sdap_check_gssapi_reconnect(state->ctx)) {

-             talloc_zfree(state->ctx->gsh);

-             subreq = enum_users_send(state, state->ev, state->ctx, state->purge);

-             if (subreq != NULL) {

-                 tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);

-                 return;

+             if (state->ctx->gsh) {

+                 state->ctx->gsh->connected = false;

              }

+             ret = ldap_id_enum_users_restart(req);

+             if (ret == EOK) return;

          }

          sdap_mark_offline(state->ctx);

      }
@@ -250,6 +277,7 @@

                                                   struct global_enum_state);

      enum tevent_req_state tstate;

      uint64_t err = 0;

+     int ret;

  

      if (tevent_req_is_error(subreq, &tstate, &err)) {

          if (tstate != TEVENT_REQ_USER_ERROR) {
@@ -278,12 +306,11 @@

  fail:

      /* check if credentials are expired otherwise go offline on failures */

      if (sdap_check_gssapi_reconnect(state->ctx)) {

-         talloc_zfree(state->ctx->gsh);

-         subreq = enum_groups_send(state, state->ev, state->ctx, state->purge);

-         if (subreq != NULL) {

-             tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);

-             return;

+         if (state->ctx->gsh) {

+             state->ctx->gsh->connected = false;

          }

+         ret = ldap_id_enum_groups_restart(req);

+         if (ret == EOK) return;

      }

      sdap_mark_offline(state->ctx);

      DEBUG(1, ("Failed to enumerate groups (%d [%s]), retrying later!\n",
@@ -299,6 +326,88 @@

      tevent_req_done(req);

  }

  

+ static void ldap_id_enum_users_immediate(struct tevent_context *ctx,

+                                          struct tevent_immediate *im,

+                                          void *private_data)

+ {

+     struct tevent_req *req = talloc_get_type(private_data,

+                                              struct tevent_req);

+     struct global_enum_state *state = tevent_req_data(req,

+                                                  struct global_enum_state);

+     struct tevent_req *subreq;

+ 

+     subreq = enum_users_send(state, state->ev, state->ctx, state->purge);

+     if (subreq == NULL) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, ldap_id_enum_users_done, req);

+ }

+ 

+ static int ldap_id_enum_users_restart(struct tevent_req *req)

+ {

+     struct global_enum_state *state = tevent_req_data(req,

+                                                  struct global_enum_state);

+     struct tevent_immediate *im;

+ 

+     state->restarts++;

+     if (state->restarts < MAX_ENUM_RESTARTS) {

+         return ELOOP;

+     }

+ 

+     im = tevent_create_immediate(req);

+     if (!im) {

+         return ENOMEM;

+     }

+ 

+     /* schedule a completely new event to avoid deep recursions */

+     tevent_schedule_immediate(im, state->ev,

+                               ldap_id_enum_users_immediate, req);

+ 

+     return EOK;

+ }

+ 

+ static void ldap_id_enum_groups_immediate(struct tevent_context *ctx,

+                                           struct tevent_immediate *im,

+                                           void *private_data)

+ {

+     struct tevent_req *req = talloc_get_type(private_data,

+                                              struct tevent_req);

+     struct global_enum_state *state = tevent_req_data(req,

+                                                  struct global_enum_state);

+     struct tevent_req *subreq;

+ 

+     subreq = enum_groups_send(state, state->ev, state->ctx, state->purge);

+     if (subreq == NULL) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, ldap_id_enum_groups_done, req);

+ }

+ 

+ static int ldap_id_enum_groups_restart(struct tevent_req *req)

+ {

+     struct global_enum_state *state = tevent_req_data(req,

+                                                  struct global_enum_state);

+     struct tevent_immediate *im;

+ 

+     state->restarts++;

+     if (state->restarts < MAX_ENUM_RESTARTS) {

+         return ELOOP;

+     }

+ 

+     im = tevent_create_immediate(req);

+     if (!im) {

+         return ENOMEM;

+     }

+ 

+     /* schedule a completely new event to avoid deep recursions */

+     tevent_schedule_immediate(im, state->ev,

+                               ldap_id_enum_groups_immediate, req);

+ 

+     return EOK;

+ }

+ 

  

  /* ==User-Enumeration===================================================== */

  
@@ -357,8 +466,6 @@

  

      if (!sdap_connected(ctx)) {

  

-         if (ctx->gsh) talloc_zfree(ctx->gsh);

- 

          /* FIXME: add option to decide if tls should be used

           * or SASL/GSSAPI, etc ... */

          subreq = sdap_cli_connect_send(state, ev, ctx->opts,
@@ -512,8 +619,6 @@

  

      if (!sdap_connected(ctx)) {

  

-         if (ctx->gsh) talloc_zfree(ctx->gsh);

- 

          /* FIXME: add option to decide if tls should be used

           * or SASL/GSSAPI, etc ... */

          subreq = sdap_cli_connect_send(state, ev, ctx->opts,

file modified
+111 -11
@@ -25,6 +25,7 @@

  #include "providers/child_common.h"

  #include "providers/ldap/ldap_common.h"

  #include "providers/ldap/sdap_async_private.h"

+ #include "providers/ldap/sdap_access.h"

  

  static void sdap_shutdown(struct be_req *req);

  
@@ -46,14 +47,30 @@

      .finalize = sdap_shutdown

  };

  

- int sssm_ldap_init(struct be_ctx *bectx,

-                    struct bet_ops **ops,

-                    void **pvt_data)

+ /* Access Handler */

+ struct bet_ops sdap_access_ops = {

+     .handler = sdap_pam_access_handler,

+     .finalize = sdap_shutdown

+ };

+ 

+ int sssm_ldap_id_init(struct be_ctx *bectx,

+                       struct bet_ops **ops,

+                       void **pvt_data)

  {

      struct sdap_id_ctx *ctx;

      const char *urls;

+     const char *dns_service_name;

      int ret;

  

+     /* If we're already set up, just return that */

+     if(bectx->bet_info[BET_ID].mod_name &&

+        strcmp("ldap", bectx->bet_info[BET_ID].mod_name) == 0) {

+         DEBUG(8, ("Re-using sdap_id_ctx for this provider\n"));

+         *ops = bectx->bet_info[BET_ID].bet_ops;

+         *pvt_data = bectx->bet_info[BET_ID].pvt_bet_data;

+         return EOK;

+     }

+ 

      ctx = talloc_zero(bectx, struct sdap_id_ctx);

      if (!ctx) return ENOMEM;

  
@@ -65,14 +82,27 @@

          goto done;

      }

  

+     /* FIXME: This is a workaround for 1.2.0. In the future, we need to have

+      * separate timeouts for enumeration operations

+      * If enumeration is enabled and the search timeout is less

+      * than 30s, force it to a minimum of 30s.

+      */

+     if(bectx->domain->enumerate &&

+             dp_opt_get_int(ctx->opts->basic, SDAP_SEARCH_TIMEOUT) < 30) {

+         dp_opt_set_int(ctx->opts->basic, SDAP_SEARCH_TIMEOUT, 30);

+     }

+ 

+     dns_service_name = dp_opt_get_string(ctx->opts->basic,

+                                          SDAP_DNS_SERVICE_NAME);

+     DEBUG(7, ("Service name for discovery set to %s\n", dns_service_name));

+ 

      urls = dp_opt_get_string(ctx->opts->basic, SDAP_URI);

      if (!urls) {

-         DEBUG(0, ("Missing ldap_uri\n"));

-         ret = EINVAL;

-         goto done;

+         DEBUG(1, ("Missing ldap_uri, will use service discovery\n"));

      }

  

-     ret = sdap_service_init(ctx, ctx->be, "LDAP", urls, &ctx->service);

+     ret = sdap_service_init(ctx, ctx->be, "LDAP",

+                             dns_service_name, urls, &ctx->service);

      if (ret != EOK) {

          DEBUG(1, ("Failed to initialize failover service!\n"));

          goto done;
@@ -85,6 +115,13 @@

          goto done;

      }

  

+     ret = be_add_offline_cb(ctx, bectx, sdap_gsh_disconnect_callback, ctx,

+                             NULL);

+     if (ret != EOK) {

+         DEBUG(1, ("be_add_offline_cb failed.\n"));

+         goto done;

+     }

+ 

      ret = sdap_id_setup_tasks(ctx);

      if (ret != EOK) {

          goto done;
@@ -114,6 +151,7 @@

  {

      struct sdap_auth_ctx *ctx;

      const char *urls;

+     const char *dns_service_name;

      int ret;

  

      ctx = talloc(bectx, struct sdap_auth_ctx);
@@ -127,14 +165,17 @@

          goto done;

      }

  

+     dns_service_name = dp_opt_get_string(ctx->opts->basic,

+                                          SDAP_DNS_SERVICE_NAME);

+     DEBUG(7, ("Service name for discovery set to %s\n", dns_service_name));

+ 

      urls = dp_opt_get_string(ctx->opts->basic, SDAP_URI);

      if (!urls) {

-         DEBUG(0, ("Missing ldap_uri\n"));

-         ret = EINVAL;

-         goto done;

+         DEBUG(1, ("Missing ldap_uri, will use service discovery\n"));

      }

  

-     ret = sdap_service_init(ctx, ctx->be, "LDAP", urls, &ctx->service);

+     ret = sdap_service_init(ctx, ctx->be, "LDAP", dns_service_name,

+                             urls, &ctx->service);

      if (ret != EOK) {

          DEBUG(1, ("Failed to initialize failover service!\n"));

          goto done;
@@ -171,6 +212,65 @@

      return ret;

  }

  

+ int sssm_ldap_access_init(struct be_ctx *bectx,

+                           struct bet_ops **ops,

+                           void **pvt_data)

+ {

+     int ret;

+     struct sdap_access_ctx *access_ctx;

+     const char *filter;

+ 

+     access_ctx = talloc_zero(bectx, struct sdap_access_ctx);

+     if(access_ctx == NULL) {

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     ret = sssm_ldap_id_init(bectx, ops, (void **)&access_ctx->id_ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("sssm_ldap_id_init failed.\n"));

+         goto done;

+     }

+ 

+     filter = dp_opt_get_cstring(access_ctx->id_ctx->opts->basic,

+                                             SDAP_ACCESS_FILTER);

+     if (filter == NULL) {

+         /* It's okay if this is NULL. In that case we will simply act

+          * like the 'deny' provider.

+          */

+         DEBUG(0, ("Warning: access_provider=ldap set, "

+                   "but no ldap_access_filter configured. "

+                   "All domain users will be denied access.\n"));

+     }

+     else {

+         if (filter[0] == '(') {

+             /* This filter is wrapped in parentheses.

+              * Pass it as-is to the openldap libraries.

+              */

+             access_ctx->filter = filter;

+         }

+         else {

+             /* Add parentheses around the filter */

+             access_ctx->filter = talloc_asprintf(access_ctx, "(%s)", filter);

+             if (access_ctx->filter == NULL) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+         }

+     }

+ 

+     *ops = &sdap_access_ops;

+     *pvt_data = access_ctx;

+ 

+     ret = EOK;

+ 

+ done:

+     if (ret != EOK) {

+         talloc_free(access_ctx);

+     }

+     return ret;

+ }

+ 

  static void sdap_shutdown(struct be_req *req)

  {

      /* TODO: Clean up any internal data */

file modified
+21 -6
@@ -26,6 +26,16 @@

  #include <ldap.h>

  #include "util/sss_ldap.h"

  

+ #ifdef LDAP_OPT_DIAGNOSTIC_MESSAGE

+ #define SDAP_DIAGNOSTIC_MESSAGE LDAP_OPT_DIAGNOSTIC_MESSAGE

+ #else

+ #ifdef LDAP_OPT_ERROR_STRING

+ #define SDAP_DIAGNOSTIC_MESSAGE LDAP_OPT_ERROR_STRING

+ #else

+ #error No extended diagnostic message available

+ #endif

+ #endif

+ 

  struct sdap_msg {

      struct sdap_msg *next;

      LDAPMessage *msg;
@@ -71,13 +81,15 @@

      LDAP *ldap;

      bool connected;

  

- #ifdef HAVE_LDAP_CONNCB

-     struct ldap_conncb *conncb;

- #else

-     struct tevent_fd *fde;

- #endif

+     struct sdap_fd_events *sdap_fd_events;

  

      struct sdap_op *ops;

+ 

+     /* during release we need to lock access to the handler

+      * from the destructor to avoid recursion */

+     bool destructor_lock;

+     /* mark when it is safe to finally release the handler memory */

+     bool release_memory;

  };

  

  struct sdap_service {
@@ -132,7 +144,6 @@

      SDAP_GROUP_SEARCH_SCOPE,

      SDAP_GROUP_SEARCH_FILTER,

      SDAP_SCHEMA,

-     SDAP_OFFLINE_TIMEOUT,

      SDAP_FORCE_UPPER_CASE_REALM,

      SDAP_ENUM_REFRESH_TIMEOUT,

      SDAP_CACHE_PURGE_TIMEOUT,
@@ -148,6 +159,10 @@

      SDAP_PWD_POLICY,

      SDAP_REFERRALS,

      SDAP_ACCOUNT_CACHE_EXPIRATION,

+     SDAP_DNS_SERVICE_NAME,

+     SDAP_ACCESS_FILTER,

+     SDAP_KRB5_TICKET_LIFETIME,

+     SDAP_NESTING_LEVEL,

  

      SDAP_OPTS_BASIC /* opts counter */

  };

@@ -0,0 +1,584 @@

+ /*

+     SSSD

+ 

+     sdap_access.c

+ 

+     Authors:

+         Stephen Gallagher <sgallagh@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include <sys/param.h>

+ #include <security/pam_modules.h>

+ #include <talloc.h>

+ #include <tevent.h>

+ #include <errno.h>

+ 

+ #include "util/util.h"

+ #include "db/sysdb.h"

+ #include "providers/ldap/ldap_common.h"

+ #include "providers/ldap/sdap.h"

+ #include "providers/ldap/sdap_access.h"

+ #include "providers/ldap/sdap_async.h"

+ #include "providers/data_provider.h"

+ #include "providers/dp_backend.h"

+ 

+ static void sdap_access_reply(struct be_req *be_req, int pam_status)

+ {

+     struct pam_data *pd;

+     pd = talloc_get_type(be_req->req_data, struct pam_data);

+     pd->pam_status = pam_status;

+ 

+     if (pam_status == PAM_SUCCESS || pam_status == PAM_PERM_DENIED) {

+         be_req->fn(be_req, DP_ERR_OK, pam_status, NULL);

+     }

+ 

+     else {

+         be_req->fn(be_req, DP_ERR_FATAL, pam_status, NULL);

+     }

+ }

+ 

+ static struct tevent_req *sdap_access_send(TALLOC_CTX *mem_ctx,

+                                            struct tevent_context *ev,

+                                            struct be_ctx *be_ctx,

+                                            struct sdap_access_ctx *access_ctx,

+                                            const char *username);

+ static void sdap_access_done(struct tevent_req *req);

+ void sdap_pam_access_handler(struct be_req *breq)

+ {

+     struct pam_data *pd;

+     struct tevent_req *req;

+     struct sdap_access_ctx *access_ctx;

+ 

+     pd = talloc_get_type(breq->req_data, struct pam_data);

+ 

+     access_ctx =

+             talloc_get_type(breq->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,

+                             struct sdap_access_ctx);

+ 

+     req = sdap_access_send(breq,

+                            breq->be_ctx->ev,

+                            breq->be_ctx,

+                            access_ctx,

+                            pd->user);

+     if (req == NULL) {

+         DEBUG(1, ("Unable to start sdap_access request\n"));

+         sdap_access_reply(breq, PAM_SYSTEM_ERR);

+         return;

+     }

+ 

+     tevent_req_set_callback(req, sdap_access_done, breq);

+ }

+ 

+ struct sdap_access_req_ctx {

+     const char *username;

+     const char *filter;

+     struct tevent_context *ev;

+     struct sdap_access_ctx *access_ctx;

+     struct sdap_id_ctx *sdap_ctx;

+     struct sysdb_handle *handle;

+     struct be_ctx *be_ctx;

+     const char **attrs;

+     int pam_status;

+     bool cached_access;

+     char *basedn;

+ };

+ static void sdap_access_get_dn_done(void *pvt, int ldb_status,

+                                     struct ldb_result *res);

+ static struct tevent_req *sdap_access_send(TALLOC_CTX *mem_ctx,

+                                            struct tevent_context *ev,

+                                            struct be_ctx *be_ctx,

+                                            struct sdap_access_ctx *access_ctx,

+                                            const char *username)

+ {

+     errno_t ret;

+     struct sdap_access_req_ctx *state;

+     struct tevent_req *req;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct sdap_access_req_ctx);

+     if (req == NULL) {

+         return NULL;

+     }

+ 

+     if (access_ctx->filter == NULL || *access_ctx->filter == '\0') {

+         /* If no filter is set, default to restrictive */

+         DEBUG(6, ("No filter set. Access is denied.\n"));

+         state->pam_status = PAM_PERM_DENIED;

+         tevent_req_done(req);

+         tevent_req_post(req, be_ctx->ev);

+         return req;

+     }

+ 

+     state->filter = NULL;

+     state->be_ctx = be_ctx;

+     state->username = username;

+     state->pam_status = PAM_SYSTEM_ERR;

+     state->sdap_ctx = access_ctx->id_ctx;

+     state->ev = ev;

+     state->access_ctx = access_ctx;

+ 

+     state->attrs = talloc_array(state, const char *, 3);

+     if (state->attrs == NULL) {

+         DEBUG(1, ("Could not allocate attributes\n"));

+         goto failed;

+     }

+ 

+     state->attrs[0] = SYSDB_ORIG_DN;

+     state->attrs[1] = SYSDB_LDAP_ACCESS;

+     state->attrs[2] = NULL;

+ 

+     DEBUG(6, ("Performing access check for user [%s]\n", username));

+ 

+     /* Get original user DN */

+     ret = sysdb_get_user_attr(state, be_ctx->sysdb,

+                               be_ctx->domain, username,

+                               state->attrs,

+                               sdap_access_get_dn_done, req);

+     return req;

+ 

+ failed:

+     talloc_free(req);

+     return NULL;

+ }

+ 

+ static void sdap_access_connect_done(struct tevent_req *subreq);

+ static void sdap_access_get_access_done(struct tevent_req *req);

+ static void sdap_access_get_dn_done(void *pvt, int ldb_status,

+                                     struct ldb_result *res)

+ {

+     errno_t ret;

+     struct sdap_access_req_ctx *state;

+     const char *basedn;

+     struct tevent_req *req;

+     struct tevent_req *subreq;

+ 

+     req = talloc_get_type(pvt, struct tevent_req);

+ 

+     state = tevent_req_data(req, struct sdap_access_req_ctx);

+     talloc_zfree(state->attrs);

+ 

+     /* Verify our results */

+     if (ldb_status == LDB_ERR_NO_SUCH_OBJECT) {

+         DEBUG(4, ("User not found in LDB.\n"));

+         ret = EOK;

+         state->pam_status = PAM_USER_UNKNOWN;

+         goto done;

+     }

+     else if (ldb_status != LDB_SUCCESS) {

+         DEBUG(1, ("LDB search failed.\n"));

+         ret = sysdb_error_to_errno(ldb_status);

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+ 

+     /* Make sure we got exactly one result */

+     if (res->count < 1) {

+         DEBUG(4, ("User not found in LDB.\n"));

+         ret = EOK;

+         state->pam_status = PAM_USER_UNKNOWN;

+         goto done;

+     }

+ 

+     if (res->count > 1) {

+         DEBUG(1, ("More than one user found.\n"));

+         ret = EIO;

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+ 

+     state->cached_access = ldb_msg_find_attr_as_bool(res->msgs[0],

+                                                      SYSDB_LDAP_ACCESS,

+                                                      false);

+ 

+     /* Ok, we have one result, check if we are online or offline */

+     if (be_is_offline(state->be_ctx)) {

+         /* Ok, we're offline. Return from the cache */

+         if (state->cached_access) {

+             DEBUG(6, ("Access granted by cached credentials\n"));

+             ret = EOK;

+             state->pam_status = PAM_SUCCESS;

+             goto done;

+         }

+ 

+         /* Access denied */

+         DEBUG(6, ("Access denied by cached credentials\n"));

+         ret = EOK;

+         state->pam_status = PAM_PERM_DENIED;

+         goto done;

+     }

+ 

+     /* Perform online operation */

+     basedn = ldb_msg_find_attr_as_string(res->msgs[0],

+                                          SYSDB_ORIG_DN,

+                                          NULL);

+     if(basedn == NULL) {

+         DEBUG(1,("Could not find originalDN for user [%s]\n",

+                  state->username));

+         ret = EIO;

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+ 

+     state->basedn = talloc_strdup(state, basedn);

+     if (state->basedn == NULL) {

+         DEBUG(1, ("Could not allocate memory for originalDN\n"));

+         ret = ENOMEM;

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+     talloc_zfree(res);

+ 

+     /* Construct the filter */

+     state->filter = talloc_asprintf(

+         state,

+         "(&(%s=%s)(objectclass=%s)%s)",

+         state->sdap_ctx->opts->user_map[SDAP_AT_USER_NAME].name,

+         state->username,

+         state->sdap_ctx->opts->user_map[SDAP_OC_USER].name,

+         state->access_ctx->filter);

+     if (state->filter == NULL) {

+         DEBUG(0, ("Could not construct access filter\n"));

+         ret = ENOMEM;

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+ 

+     DEBUG(6, ("Checking filter against LDAP\n"));

+ 

+     /* Check whether we have an active LDAP connection */

+     if (state->sdap_ctx->gsh == NULL || ! state->sdap_ctx->gsh->connected) {

+         subreq = sdap_cli_connect_send(state, state->ev,

+                                        state->sdap_ctx->opts,

+                                        state->sdap_ctx->be,

+                                        state->sdap_ctx->service,

+                                        NULL);

+         if (!subreq) {

+             DEBUG(1, ("sdap_cli_connect_send failed.\n"));

+             ret = EIO;

+             state->pam_status = PAM_SYSTEM_ERR;

+             goto done;

+         }

+ 

+         tevent_req_set_callback(subreq, sdap_access_connect_done, req);

+         return;

+     }

+ 

+     /* Make the LDAP request */

+     subreq = sdap_get_generic_send(state,

+                                    state->ev,

+                                    state->sdap_ctx->opts,

+                                    state->sdap_ctx->gsh,

+                                    state->basedn, LDAP_SCOPE_BASE,

+                                    state->filter, NULL,

+                                    NULL, 0);

+     if (subreq == NULL) {

+         DEBUG(1, ("Could not start LDAP communication\n"));

+         ret = EIO;

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+ 

+     tevent_req_set_callback(subreq, sdap_access_get_access_done, req);

+     return;

+ 

+ done:

+     if (ret == EOK) {

+         tevent_req_done(req);

+     }

+     else {

+         tevent_req_error(req, ret);

+     }

+ }

+ 

+ static void sdap_access_connect_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_access_req_ctx *state =

+             tevent_req_data(req, struct sdap_access_req_ctx);

+ 

+     ret = sdap_cli_connect_recv(subreq, state->sdap_ctx,

+                                 &state->sdap_ctx->gsh, NULL);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         /* Could not connect to LDAP. Mark as offline and return

+          * from cache.

+          */

+         be_mark_offline(state->be_ctx);

+         if (state->cached_access) {

+             DEBUG(6, ("Access granted by cached credentials\n"));

+             state->pam_status = PAM_SUCCESS;

+             tevent_req_done(req);

+             return;

+         }

+ 

+         /* Access denied */

+         DEBUG(6, ("Access denied by cached credentials\n"));

+         state->pam_status = PAM_PERM_DENIED;

+         tevent_req_done(req);

+     }

+ 

+     /* Connection to LDAP succeeded

+      * Send filter request

+      */

+     subreq = sdap_get_generic_send(state,

+                                    state->ev,

+                                    state->sdap_ctx->opts,

+                                    state->sdap_ctx->gsh,

+                                    state->basedn,

+                                    LDAP_SCOPE_BASE,

+                                    state->filter, NULL,

+                                    NULL, 0);

+     if (subreq == NULL) {

+         DEBUG(1, ("Could not start LDAP communication\n"));

+         state->pam_status = PAM_SYSTEM_ERR;

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq, sdap_access_get_access_done, req);

+ }

+ 

+ static void sdap_access_save_cache(struct tevent_req *req);

+ static void sdap_access_get_access_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     size_t num_results;

+     bool found = false;

+     struct sysdb_attrs **results;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_access_req_ctx *state =

+             tevent_req_data(req, struct sdap_access_req_ctx);

+     ret = sdap_get_generic_recv(subreq, state,

+                                 &num_results, &results);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(1, ("sdap_get_generic_send() returned error [%d][%s]",

+                   ret, strerror(ret)));

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+ 

+     /* Check the number of responses we got

+      * If it's exactly 1, we passed the check

+      * If it's < 1, we failed the check

+      * Anything else is an error

+      */

+     if (num_results < 1) {

+         DEBUG(4, ("User [%s] was not found with the specified filter. "

+                   "Denying access.\n", state->username));

+         found = false;

+     }

+     else if (results == NULL) {

+         DEBUG(1, ("num_results > 0, but results is NULL\n"));

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+     else if (num_results > 1) {

+         /* It should not be possible to get more than one reply

+          * here, since we're doing a base-scoped search

+          */

+         DEBUG(1, ("Received multiple replies\n"));

+         state->pam_status = PAM_SYSTEM_ERR;

+         goto done;

+     }

+     else { /* Ok, we got a single reply */

+         found = true;

+     }

+ 

+     if (found) {

+         /* Save "allow" to the cache for future offline

+          * access checks.

+          */

+         DEBUG(6, ("Access granted by online lookup\n"));

+         state->pam_status = PAM_SUCCESS;

+     }

+     else {

+         /* Save "disallow" to the cache for future offline

+          * access checks.

+          */

+         DEBUG(6, ("Access denied by online lookup\n"));

+         state->pam_status = PAM_PERM_DENIED;

+     }

+ 

+     /* Start a transaction to cache the access result */

+     subreq = sysdb_transaction_send(state, state->ev,

+                                     state->be_ctx->sysdb);

+     if (subreq == NULL) {

+         /* Failing to save the cache is non-fatal.

+          * Just return the result.

+          */

+         ret = EOK;

+         DEBUG(1, ("Failed to create transaction for user access attr\n"));

+         goto done;

+     }

+     tevent_req_set_callback(subreq, sdap_access_save_cache, req);

+     return;

+ 

+ done:

+     if (ret == EOK) {

+         tevent_req_done(req);

+     }

+     else {

+         tevent_req_error(req, ret);

+     }

+ }

+ 

+ static void sdap_access_cache_commit(struct tevent_req *subreq);

+ static void sdap_access_save_cache(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct sysdb_attrs *attrs;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_access_req_ctx *state =

+             tevent_req_data(req, struct sdap_access_req_ctx);

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         /* Failing to save the cache is non-fatal.

+          * Just return the result.

+          */

+         ret = EOK;

+         DEBUG(1, ("Failed to create transaction for user access attr\n"));

+         goto done;

+     }

+ 

+     attrs = sysdb_new_attrs(state);

+     if (attrs == NULL) {

+         ret = ENOMEM;

+         DEBUG(1, ("Could not set up attrs\n"));

+         goto done;

+     }

+ 

+     ret = sysdb_attrs_add_bool(attrs, SYSDB_LDAP_ACCESS,

+                                state->pam_status == PAM_SUCCESS ?

+                                                     true :

+                                                     false);

+     if (ret != EOK) {

+         DEBUG(1, ("Could not set up attrs\n"));

+         goto done;

+     }

+ 

+     subreq = sysdb_set_user_attr_send(attrs,

+                                       state->ev,

+                                       state->handle,

+                                       state->be_ctx->domain,

+                                       state->username,

+                                       attrs, SYSDB_MOD_REP);

+     if (subreq == NULL) {

+         /* Failing to save to the cache is non-fatal.

+          * Just return the result.

+          */

+         DEBUG(1, ("Failed to set user access attribute\n"));

+         goto done;

+     }

+     tevent_req_set_callback(subreq, sdap_access_cache_commit, req);

+     return;

+ 

+ done:

+     if (ret == EOK) {

+         tevent_req_done(req);

+     }

+     else {

+         tevent_req_error(req, ret);

+     }

+ }

+ 

+ static void sdap_access_cache_done(struct tevent_req *subreq);

+ static void sdap_access_cache_commit(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_access_req_ctx *state =

+             tevent_req_data(req, struct sdap_access_req_ctx);

+ 

+     ret = sysdb_set_entry_attr_recv(subreq);

+     talloc_zfree(subreq);

+ 

+     if(ret != EOK) {

+         goto failed;

+     }

+ 

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (subreq == NULL) {

+         goto failed;

+     }

+     tevent_req_set_callback(subreq,sdap_access_cache_done,req);

+     return;

+ 

+ failed:

+     /* Failing to save to the cache is non-fatal.

+      * Just return the result.

+      */

+     DEBUG(1, ("Failed to set user access attribute\n"));

+     tevent_req_done(req);

+     return;

+ }

+ 

+ static void sdap_access_cache_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = sysdb_transaction_commit_recv(subreq);

+     talloc_zfree(subreq);

+ 

+     if(ret != EOK) {

+         /* Failing to save to the cache is non-fatal */

+         DEBUG(1,("Unable to save access results to the cache\n"));

+     }

+     else {

+         DEBUG(6, ("Saved access result to the user cache\n"));

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ static errno_t sdap_access_recv(struct tevent_req *req, int *pam_status)

+ {

+     struct sdap_access_req_ctx *state =

+             tevent_req_data(req, struct sdap_access_req_ctx);

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     *pam_status = state->pam_status;

+ 

+     return EOK;

+ }

+ 

+ static void sdap_access_done(struct tevent_req *req)

+ {

+     errno_t ret;

+     int pam_status;

+     struct be_req *breq =

+             tevent_req_callback_data(req, struct be_req);

+ 

+     ret = sdap_access_recv(req, &pam_status);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(1, ("Error retrieving access check result.\n"));

+         pam_status = PAM_SYSTEM_ERR;

+     }

+ 

+     sdap_access_reply(breq, pam_status);

+ }

@@ -0,0 +1,39 @@

+ /*

+     SSSD

+ 

+     sdap_access.h

+ 

+     Authors:

+         Stephen Gallagher <sgallagh@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #ifndef SDAP_ACCESS_H_

+ #define SDAP_ACCESS_H_

+ 

+ #include "providers/dp_backend.h"

+ 

+ #define SYSDB_LDAP_ACCESS "ldap_access_allow"

+ 

+ struct sdap_access_ctx {

+     struct sdap_id_ctx *id_ctx;

+     const char *filter;

+ };

+ 

+ void ldap_pam_access_handler(struct be_req *breq);

+ 

+ #endif /* SDAP_ACCESS_H_ */

file modified
+80 -146
@@ -84,43 +84,57 @@

  {

      struct sdap_handle *sh = talloc_get_type(mem, struct sdap_handle);

  

-     sdap_handle_release(sh);

+     /* if the structure is currently locked, then mark it to be released

+      * and prevent talloc from freeing the memory */

+     if (sh->destructor_lock) {

+         sh->release_memory = true;

+         return -1;

+     }

  

+     sdap_handle_release(sh);

      return 0;

  }

  

  static void sdap_handle_release(struct sdap_handle *sh)

  {

-     DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p]\n",

-               sh, (int)sh->connected, sh->ops, sh->ldap));

+     struct sdap_op *op;

  

-     if (sh->connected) {

-         struct sdap_op *op;

- 

- #ifdef HAVE_LDAP_CONNCB

-         /* remove all related fd events from the event loop */

-         talloc_zfree(sh->conncb->lc_arg);

- #else

-         talloc_zfree(sh->fde);

- #endif

- 

-         while (sh->ops) {

-             op = sh->ops;

-             op->callback(op, NULL, EIO, op->data);

-             /* calling the callback may result in freeing the op */

-             /* check if it is still the same or avoid freeing */

-             if (op == sh->ops) talloc_free(op);

-         }

+     DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], ldap[%p], "

+               "destructor_lock[%d], release_memory[%d]\n",

+               sh, (int)sh->connected, sh->ops, sh->ldap,

+               (int)sh->destructor_lock, (int)sh->release_memory));

  

-         if (sh->ldap) {

-             ldap_unbind_ext(sh->ldap, NULL, NULL);

-         }

- #ifdef HAVE_LDAP_CONNCB

-         talloc_zfree(sh->conncb);

- #endif

-         sh->connected = false;

+     if (sh->destructor_lock) return;

+     sh->destructor_lock = true;

+ 

+     /* make sure nobody tries to reuse this connection from now on */

+     sh->connected = false;

+ 

+     talloc_zfree(sh->sdap_fd_events);

+ 

+     while (sh->ops) {

+         op = sh->ops;

+         op->callback(op, NULL, EIO, op->data);

+         /* calling the callback may result in freeing the op */

+         /* check if it is still the same or avoid freeing */

+         if (op == sh->ops) talloc_free(op);

+     }

+ 

+     if (sh->ldap) {

+         ldap_unbind_ext(sh->ldap, NULL, NULL);

          sh->ldap = NULL;

-         sh->ops = NULL;

+     }

+ 

+     /* ok, we have done the job, unlock now */

+     sh->destructor_lock = false;

+ 

+     /* finally if a destructor was ever called, free sh before

+      * exiting */

+     if (sh->release_memory) {

+         /* neutralize the destructor as we already handled

+          * all was needed to be released */

+         talloc_set_destructor((TALLOC_CTX *)sh, NULL);

+         talloc_free(sh);

      }

  }

  
@@ -132,9 +146,8 @@

                                      struct tevent_timer *te,

                                      struct timeval tv, void *pvt);

  

- static void sdap_ldap_result(struct tevent_context *ev,

-                              struct tevent_fd *fde,

-                              uint16_t flags, void *pvt)

+ void sdap_ldap_result(struct tevent_context *ev, struct tevent_fd *fde,

+                       uint16_t flags, void *pvt)

  {

      sdap_process_result(ev, pvt);

  }
@@ -336,118 +349,6 @@

      op->callback(op, op->list, EOK, op->data);

  }

  

- #ifdef HAVE_LDAP_CONNCB

- int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv,

-                            struct sockaddr *addr, struct ldap_conncb *ctx)

- {

-     int ret;

-     ber_socket_t ber_fd;

-     struct fd_event_item *fd_event_item;

-     struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg,

-                                                    struct ldap_cb_data);

- 

-     ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd);

-     if (ret == -1) {

-         DEBUG(1, ("ber_sockbuf_ctrl failed.\n"));

-         return EINVAL;

-     }

-     DEBUG(9, ("New LDAP connection to [%s] with fd [%d].\n",

-               ldap_url_desc2str(srv), ber_fd));

- 

-     fd_event_item = talloc_zero(cb_data, struct fd_event_item);

-     if (fd_event_item == NULL) {

-         DEBUG(1, ("talloc failed.\n"));

-         return ENOMEM;

-     }

- 

-     fd_event_item->fde = tevent_add_fd(cb_data->ev, fd_event_item, ber_fd,

-                                        TEVENT_FD_READ, sdap_ldap_result,

-                                        cb_data->sh);

-     if (fd_event_item->fde == NULL) {

-         DEBUG(1, ("tevent_add_fd failed.\n"));

-         talloc_free(fd_event_item);

-         return ENOMEM;

-     }

-     fd_event_item->fd = ber_fd;

- 

-     DLIST_ADD(cb_data->fd_list, fd_event_item);

- 

-     return LDAP_SUCCESS;

- }

- 

- void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb,

-                                     struct ldap_conncb *ctx)

- {

-     int ret;

-     ber_socket_t ber_fd;

-     struct fd_event_item *fd_event_item;

-     struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg,

-                                                    struct ldap_cb_data);

- 

-     if (sb == NULL || cb_data == NULL) {

-         return;

-     }

- 

-     ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd);

-     if (ret == -1) {

-         DEBUG(1, ("ber_sockbuf_ctrl failed.\n"));

-         return;

-     }

-     DEBUG(9, ("Closing LDAP connection with fd [%d].\n", ber_fd));

- 

-     DLIST_FOR_EACH(fd_event_item, cb_data->fd_list) {

-         if (fd_event_item->fd == ber_fd) {

-             break;

-         }

-     }

-     if (fd_event_item == NULL) {

-         DEBUG(1, ("No event for fd [%d] found.\n", ber_fd));

-         return;

-     }

- 

-     DLIST_REMOVE(cb_data->fd_list, fd_event_item);

-     talloc_zfree(fd_event_item);

- 

-     return;

- }

- 

- #else

- 

- static int get_fd_from_ldap(LDAP *ldap, int *fd)

- {

-     int ret;

- 

-     ret = ldap_get_option(ldap, LDAP_OPT_DESC, fd);

-     if (ret != LDAP_OPT_SUCCESS) {

-         DEBUG(1, ("Failed to get fd from ldap!!\n"));

-         *fd = -1;

-         return EIO;

-     }

- 

-     return EOK;

- }

- 

- int sdap_install_ldap_callbacks(struct sdap_handle *sh,

-                                 struct tevent_context *ev)

- {

-     int fd;

-     int ret;

- 

-     ret = get_fd_from_ldap(sh->ldap, &fd);

-     if (ret) return ret;

- 

-     sh->fde = tevent_add_fd(ev, sh, fd, TEVENT_FD_READ, sdap_ldap_result, sh);

-     if (!sh->fde) return ENOMEM;

- 

-     DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n",

-               sh, (int)sh->connected, sh->ops, sh->fde, sh->ldap));

- 

-     return EOK;

- }

- 

- #endif

- 

- 

  /* ==LDAP-Operations-Helpers============================================== */

  

  static int sdap_op_destructor(void *mem)
@@ -736,6 +637,17 @@

  {

      struct tevent_req *req, *subreq;

      struct sdap_get_rootdse_state *state;

+     const char *attrs[] = {

+ 	    "*",

+ 	    "altServer",

+ 	    "namingContexts",

+ 	    "supportedControl",

+ 	    "supportedExtension",

+ 	    "supportedFeatures",

+ 	    "supportedLDAPVersion",

+ 	    "supportedSASLMechanisms",

+ 	    NULL

+     };

  

      DEBUG(9, ("Getting rootdse\n"));

  
@@ -749,7 +661,7 @@

  

      subreq = sdap_get_generic_send(state, ev, opts, sh,

                                     "", LDAP_SCOPE_BASE,

-                                    "(objectclass=*)", NULL, NULL, 0);

+                                    "(objectclass=*)", attrs, NULL, 0);

      if (!subreq) {

          talloc_zfree(req);

          return NULL;
@@ -777,7 +689,9 @@

      }

  

      if (num_results == 0 || !results) {

-         DEBUG(2, ("No RootDSE for server ?!\n"));

+         DEBUG(2, ("RootDSE could not be retrieved. "

+                   "Please check that anonymous access to RootDSE is allowed\n"

+               ));

          tevent_req_error(req, ENOENT);

          return;

      }
@@ -850,7 +764,9 @@

  {

      struct tevent_req *req = NULL;

      struct sdap_get_generic_state *state = NULL;

+     char *errmsg;

      int lret;

+     int optret;

      int ret;

      int msgid;

  
@@ -889,7 +805,25 @@

                             false, NULL, NULL, NULL, 0, &msgid);

      if (lret != LDAP_SUCCESS) {

          DEBUG(3, ("ldap_search_ext failed: %s\n", ldap_err2string(lret)));

-         ret = EIO;

+         if (lret == LDAP_SERVER_DOWN) {

+             ret = ETIMEDOUT;

+             optret = ldap_get_option(state->sh->ldap,

+                                      SDAP_DIAGNOSTIC_MESSAGE,

+                                      (void*)&errmsg);

+             if (optret == LDAP_SUCCESS) {

+                 DEBUG(3, ("Connection error: %s\n", errmsg));

+                 sss_log(SSS_LOG_ERR, "LDAP connection error: %s", errmsg);

+                 ldap_memfree(errmsg);

+             }

+             else {

+                 sss_log(SSS_LOG_ERR, "LDAP connection error, %s",

+                                      ldap_err2string(lret));

+             }

+         }

+ 

+         else {

+             ret = EIO;

+         }

          goto fail;

      }

      DEBUG(8, ("ldap_search_ext called, msgid = %d\n", msgid));

@@ -65,7 +65,8 @@

                                     int    timeout,

                                     const char *keytab,

                                     const char *principal,

-                                    const char *realm);

+                                    const char *realm,

+                                    int lifetime);

  int sdap_kinit_recv(struct tevent_req *req, enum sdap_result *result);

  

  struct tevent_req *sdap_auth_send(TALLOC_CTX *memctx,

@@ -57,7 +57,6 @@

      const char *gecos;

      const char *homedir;

      const char *shell;

-     long int l;

      uid_t uid;

      gid_t gid;

      struct sysdb_attrs *user_attrs;
@@ -111,22 +110,15 @@

      if (el->num_values == 0) shell = NULL;

      else shell = (const char *)el->values[0].data;

  

-     ret = sysdb_attrs_get_el(state->attrs,

-                              opts->user_map[SDAP_AT_USER_UID].sys_name, &el);

-     if (ret) goto fail;

-     if (el->num_values == 0) {

+     ret = sysdb_attrs_get_uint32_t(attrs,

+                                    opts->user_map[SDAP_AT_USER_UID].sys_name,

+                                    &uid);

+     if (ret != EOK) {

          DEBUG(1, ("no uid provided for [%s] in domain [%s].\n",

                    state->name, dom->name));

          ret = EINVAL;

          goto fail;

      }

-     errno = 0;

-     l = strtol((const char *)el->values[0].data, NULL, 0);

-     if (errno) {

-         ret = EINVAL;

-         goto fail;

-     }

-     uid = l;

  

      /* check that the uid is valid for this domain */

      if (OUT_OF_ID_RANGE(uid, dom->id_min, dom->id_max)) {
@@ -136,22 +128,15 @@

          goto fail;

      }

  

-     ret = sysdb_attrs_get_el(state->attrs,

-                              opts->user_map[SDAP_AT_USER_GID].sys_name, &el);

-     if (ret) goto fail;

-     if (el->num_values == 0) {

+     ret = sysdb_attrs_get_uint32_t(attrs,

+                                    opts->user_map[SDAP_AT_USER_GID].sys_name,

+                                    &gid);

+     if (ret != EOK) {

          DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",

                    state->name, dom->name));

          ret = EINVAL;

          goto fail;

      }

-     errno = 0;

-     l = strtol((const char *)el->values[0].data, NULL, 0);

-     if (errno) {

-         ret = EINVAL;

-         goto fail;

-     }

-     gid = l;

  

      /* check that the gid is valid for this domain */

      if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
@@ -231,7 +216,7 @@

          goto fail;

      }

      if (el->num_values == 0) {

-         DEBUG(7, ("User principle is not available for [%s].\n", state->name));

+         DEBUG(7, ("User principal is not available for [%s].\n", state->name));

      } else {

          upn = talloc_strdup(user_attrs, (const char*) el->values[0].data);

          if (!upn) {
@@ -241,7 +226,7 @@

          if (dp_opt_get_bool(opts->basic, SDAP_FORCE_UPPER_CASE_REALM)) {

              make_realm_upper_case(upn);

          }

-         DEBUG(7, ("Adding user principle [%s] to attributes of [%s].\n",

+         DEBUG(7, ("Adding user principal [%s] to attributes of [%s].\n",

                    upn, state->name));

          ret = sysdb_attrs_add_string(user_attrs, SYSDB_UPN, upn);

          if (ret) {
@@ -381,6 +366,15 @@

      state->handle = NULL;

      state->higher_timestamp = NULL;

  

+     if (num_users == 0) {

+         /* Nothing to do if there are no

+          * users

+          */

+         tevent_req_done(req);

+         tevent_req_post(req, ev);

+         return req;

+     }

+ 

      subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

      if (!subreq) {

          tevent_req_error(req, ENOMEM);
@@ -814,13 +808,13 @@

                                                 struct sdap_options *opts,

                                                 struct sss_domain_info *dom,

                                                 struct sysdb_attrs *attrs,

-                                                bool store_members)

+                                                bool store_members,

+                                                bool populate_members)

  {

      struct tevent_req *req, *subreq;

      struct sdap_save_group_state *state;

      struct ldb_message_element *el;

      struct sysdb_attrs *group_attrs;

-     long int l;

      gid_t gid;

      int ret;

  
@@ -842,22 +836,15 @@

      }

      state->name = (const char *)el->values[0].data;

  

-     ret = sysdb_attrs_get_el(attrs,

-                           opts->group_map[SDAP_AT_GROUP_GID].sys_name, &el);

-     if (ret) goto fail;

-     if (el->num_values == 0) {

+     ret = sysdb_attrs_get_uint32_t(attrs,

+                                    opts->group_map[SDAP_AT_GROUP_GID].sys_name,

+                                    &gid);

+     if (ret != EOK) {

          DEBUG(1, ("no gid provided for [%s] in domain [%s].\n",

                    state->name, dom->name));

          ret = EINVAL;

          goto fail;

      }

-     errno = 0;

-     l = strtol((const char *)el->values[0].data, NULL, 0);

-     if (errno) {

-         ret = EINVAL;

-         goto fail;

-     }

-     gid = l;

  

      /* check that the gid is valid for this domain */

      if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
@@ -912,7 +899,23 @@

          }

      }

  

-     if (store_members) {

+     if (populate_members) {

+         struct ldb_message_element *el1;

+         ret = sysdb_attrs_get_el(attrs,

+                                  opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,

+                                  &el1);

+         if (ret != EOK) {

+             goto fail;

+         }

+ 

+         ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);

+         if (ret != EOK) {

+             goto fail;

+         }

+ 

+         el->values = el1->values;

+         el->num_values = el1->num_values;

+     } else if (store_members) {

          ret = sysdb_attrs_get_el(attrs,

                          opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);

          if (ret != EOK) {
@@ -1120,6 +1123,7 @@

      int count;

      int cur;

      bool twopass;

+     bool populate_members;

  

      struct sysdb_handle *handle;

  
@@ -1137,6 +1141,7 @@

                                           struct sysdb_ctx *sysdb,

                                           struct sdap_options *opts,

                                           struct sysdb_attrs **groups,

+                                          bool populate_members,

                                           int num_groups)

  {

      struct tevent_req *req, *subreq;
@@ -1154,6 +1159,7 @@

      state->cur = 0;

      state->handle = NULL;

      state->higher_timestamp = NULL;

+     state->populate_members = populate_members;

  

      switch (opts->schema_type) {

      case SDAP_SCHEMA_RFC2307:
@@ -1213,7 +1219,7 @@

      subreq = sdap_save_group_send(state, state->ev, state->handle,

                                    state->opts, state->dom,

                                    state->groups[state->cur],

-                                   (!state->twopass));

+                                   (!state->twopass), state->populate_members);

      if (!subreq) {

          tevent_req_error(req, ENOMEM);

          return;
@@ -1260,7 +1266,7 @@

  

          sdap_save_groups_save(req);

  

-     } else if (state->twopass) {

+     } else if (state->twopass && !state->populate_members) {

  

          state->cur = 0;

          sdap_save_groups_mem_save(req);
@@ -1346,720 +1352,3613 @@

      return EOK;

  }

  

+ /* ==Process-Groups======================================================= */

  

- /* ==Search-Groups-with-filter============================================ */

+ struct tevent_req *

+ sdap_process_group_members_2307_send(TALLOC_CTX *memctx,

+                                      struct tevent_context *ev,

+                                      struct sss_domain_info *dom,

+                                      struct sysdb_ctx *sysdb,

+                                      struct ldb_message_element *memberel,

+                                      struct ldb_message_element *sysdb_dns);

+ static int sdap_process_group_members_2307_recv(struct tevent_req *req);

  

- struct sdap_get_groups_state {

+ struct sdap_process_group_state {

      struct tevent_context *ev;

-     struct sdap_options *opts;

-     struct sdap_handle *sh;

      struct sss_domain_info *dom;

      struct sysdb_ctx *sysdb;

-     const char **attrs;

-     const char *filter;

+     struct sysdb_attrs *group;

  

-     char *higher_timestamp;

-     struct sysdb_attrs **groups;

-     size_t count;

+     struct ldb_message_element *sysdb_dns;

+     struct ldb_message_element *memberel;

  };

  

- static void sdap_get_groups_process(struct tevent_req *subreq);

- static void sdap_get_groups_done(struct tevent_req *subreq);

  

- struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,

-                                        struct tevent_context *ev,

-                                        struct sss_domain_info *dom,

-                                        struct sysdb_ctx *sysdb,

-                                        struct sdap_options *opts,

-                                        struct sdap_handle *sh,

-                                        const char **attrs,

-                                        const char *filter)

+ static void sdap_process_group_2307_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,

+                                            struct tevent_context *ev,

+                                            struct sss_domain_info *dom,

+                                            struct sysdb_ctx *sysdb,

+                                            struct sdap_options *opts,

+                                            struct sysdb_attrs *group)

  {

-     struct tevent_req *req, *subreq;

-     struct sdap_get_groups_state *state;

+     struct sdap_process_group_state *grp_state;

+     struct tevent_req *req = NULL;

+     struct tevent_req *subreq;

+     const char **attrs;

+     char* filter;

+     int ret;

  

-     req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);

+     req = tevent_req_create(memctx, &grp_state,

+                             struct sdap_process_group_state);

      if (!req) return NULL;

  

-     state->ev = ev;

-     state->opts = opts;

-     state->dom = dom;

-     state->sh = sh;

-     state->sysdb = sysdb;

-     state->filter = filter;

-     state->attrs = attrs;

-     state->higher_timestamp = NULL;

-     state->groups =  NULL;

-     state->count = 0;

+     ret = build_attrs_from_map(grp_state, opts->user_map,

+                                SDAP_OPTS_USER, &attrs);

+     if (ret) {

+         goto fail;

+     }

  

-     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,

-                                    dp_opt_get_string(state->opts->basic,

-                                                      SDAP_GROUP_SEARCH_BASE),

-                                    LDAP_SCOPE_SUBTREE,

-                                    state->filter, state->attrs,

-                                    state->opts->group_map, SDAP_OPTS_GROUP);

-     if (!subreq) {

+     /* FIXME: we ignore nested rfc2307bis groups for now */

+     filter = talloc_asprintf(grp_state, "(objectclass=%s)",

+                              opts->user_map[SDAP_OC_USER].name);

+     if (!filter) {

          talloc_zfree(req);

          return NULL;

      }

-     tevent_req_set_callback(subreq, sdap_get_groups_process, req);

- 

-     return req;

- }

  

- static void sdap_get_groups_process(struct tevent_req *subreq)

- {

-     struct tevent_req *req = tevent_req_callback_data(subreq,

-                                                       struct tevent_req);

-     struct sdap_get_groups_state *state = tevent_req_data(req,

-                                             struct sdap_get_groups_state);

-     int ret;

+     grp_state->ev = ev;

+     grp_state->dom = dom;

+     grp_state->sysdb = sysdb;

+     grp_state->group = group;

  

-     ret = sdap_get_generic_recv(subreq, state,

-                                 &state->count, &state->groups);

-     talloc_zfree(subreq);

+     ret = sysdb_attrs_get_el(group,

+                              opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,

+                              &grp_state->memberel);

      if (ret) {

-         tevent_req_error(req, ret);

-         return;

+         goto fail;

      }

  

-     DEBUG(6, ("Search for groups, returned %d results.\n", state->count));

+     /* Group without members */

+     if (grp_state->memberel->num_values == 0) {

+         DEBUG(2, ("No Members. Done!\n"));

+         tevent_req_done(req);

+         tevent_req_post(req, ev);

+         return req;

+     }

  

-     if (state->count == 0) {

-         tevent_req_error(req, ENOENT);

-         return;

+     grp_state->sysdb_dns = talloc(grp_state,

+                                   struct ldb_message_element);

+     if (!grp_state->sysdb_dns) {

+         ret = ENOMEM;

+         goto fail;

      }

+     grp_state->sysdb_dns->values = talloc_array(grp_state, struct ldb_val,

+                                             grp_state->memberel->num_values);

+     if (!grp_state->sysdb_dns->values) {

+         ret = ENOMEM;

+         goto fail;

+     }

+     grp_state->sysdb_dns->num_values = 0;

  

-     subreq = sdap_save_groups_send(state, state->ev, state->dom,

-                                    state->sysdb, state->opts,

-                                    state->groups, state->count);

-     if (!subreq) {

-         tevent_req_error(req, ENOMEM);

-         return;

+     switch (opts->schema_type) {

+         case SDAP_SCHEMA_RFC2307:

+             subreq = sdap_process_group_members_2307_send(grp_state,

+                                                           grp_state->ev,

+                                                           grp_state->dom,

+                                                           grp_state->sysdb,

+                                                           grp_state->memberel,

+                                                           grp_state->sysdb_dns);

+             if (!subreq) {

+                 ret = ENOMEM;

+                 goto fail;

+             }

+             tevent_req_set_callback(subreq, sdap_process_group_2307_done,

+                                     req);

+             break;

+ 

+         case SDAP_SCHEMA_IPA_V1:

+         case SDAP_SCHEMA_AD:

+         case SDAP_SCHEMA_RFC2307BIS:

+             DEBUG(2, ("Processing users for RFC2307BIS not yet implemeted\n"));

+             tevent_req_done(req);

+             tevent_req_post(req, ev);

+             break;

+ 

+         default:

+             DEBUG(1, ("Unknown schema type %d\n", opts->schema_type));

+             ret = EINVAL;

+             goto fail;

      }

-     tevent_req_set_callback(subreq, sdap_get_groups_done, req);

+ 

+     return req;

+ fail:

+     tevent_req_error(req, ret);

+     tevent_req_post(req, ev);

+     return req;

  }

  

- static void sdap_get_groups_done(struct tevent_req *subreq)

+ static void sdap_process_group_2307_done(struct tevent_req *subreq)

  {

      struct tevent_req *req = tevent_req_callback_data(subreq,

                                                        struct tevent_req);

-     struct sdap_get_groups_state *state = tevent_req_data(req,

-                                             struct sdap_get_groups_state);

-     int ret;

+     struct sdap_process_group_state *state =

+         tevent_req_data(req, struct sdap_process_group_state);

  

-     DEBUG(9, ("Saving %d Groups - Done\n", state->count));

+     int ret;

  

-     ret = sdap_save_groups_recv(subreq, state, &state->higher_timestamp);

+     ret = sdap_process_group_members_2307_recv(subreq);

      talloc_zfree(subreq);

      if (ret) {

-         DEBUG(2, ("Failed to store groups.\n"));

          tevent_req_error(req, ret);

          return;

      }

  

+     state->memberel->values = talloc_steal(state->group,

+                                            state->sysdb_dns->values);

+     state->memberel->num_values = state->sysdb_dns->num_values;

      tevent_req_done(req);

  }

  

- int sdap_get_groups_recv(struct tevent_req *req,

-                          TALLOC_CTX *mem_ctx, char **timestamp)

+ static int sdap_process_group_recv(struct tevent_req *req)

  {

-     struct sdap_get_groups_state *state = tevent_req_data(req,

-                                             struct sdap_get_groups_state);

- 

      TEVENT_REQ_RETURN_ON_ERROR(req);

- 

-     if (timestamp) {

-         *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);

-     }

- 

      return EOK;

  }

  

+ /*===Process-group-members-of-RFC2307-group============================*/

  

- /* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */

+ struct tevent_req *

+ sdap_process_missing_member_2307_send(TALLOC_CTX *memctx,

+                                       struct tevent_context *ev,

+                                       struct sss_domain_info *dom,

+                                       struct sysdb_ctx *sysdb,

+                                       struct sysdb_handle *handle,

+                                       const char *username,

+                                       struct ldb_message_element* sysdb_dns);

+ static int sdap_process_missing_member_2307_recv(struct tevent_req *req);

  

- struct sdap_initgr_rfc2307_state {

+ struct sdap_process_group_members_2307_state {

      struct tevent_context *ev;

-     struct sysdb_ctx *sysdb;

-     struct sdap_options *opts;

      struct sss_domain_info *dom;

-     struct sdap_handle *sh;

+     struct sysdb_ctx *sysdb;

+     struct sysdb_handle *handle;

  

-     struct sdap_op *op;

+     struct ldb_message_element *sysdb_dns;

+     struct ldb_message_element *memberel;

+     int cur;

+ 

+     const char **missing;

+     int mi;

+     int ai;

  };

  

- static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);

- static void sdap_initgr_rfc2307_done(struct tevent_req *subreq);

- struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,

-                                             struct tevent_context *ev,

-                                             struct sdap_options *opts,

-                                             struct sysdb_ctx *sysdb,

-                                             struct sss_domain_info *dom,

-                                             struct sdap_handle *sh,

-                                             const char *base_dn,

-                                             const char *name,

-                                             const char **grp_attrs)

+ static void sdap_process_group_members_2307_added(struct tevent_req *subreq);

+ void sdap_process_group_members_2307_step(struct tevent_req *req);

+ static void sdap_process_group_members_2307_check_add(struct tevent_req *req);

+ static void

+ sdap_process_group_members_2307_trans(struct tevent_req *subreq);

+ static void sdap_process_group_members_2307_add(struct tevent_req *req);

+ static void sdap_process_group_members_2307_added(struct tevent_req *subreq);

+ static void sdap_process_group_members_2307_post(struct tevent_req *req);

+ static void sdap_process_group_members_2307_trans_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *

+ sdap_process_group_members_2307_send(TALLOC_CTX *memctx,

+                                      struct tevent_context *ev,

+                                      struct sss_domain_info *dom,

+                                      struct sysdb_ctx *sysdb,

+                                      struct ldb_message_element *memberel,

+                                      struct ldb_message_element *sysdb_dns)

  {

-     struct tevent_req *req, *subreq;

-     struct sdap_initgr_rfc2307_state *state;

-     const char *filter;

+     struct tevent_req *req = NULL;

+     struct sdap_process_group_members_2307_state *state;

+     struct tevent_req *subreq = NULL;

  

-     req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);

+     req = tevent_req_create(memctx, &state,

+                             struct sdap_process_group_members_2307_state);

      if (!req) return NULL;

  

      state->ev = ev;

-     state->opts = opts;

-     state->sysdb = sysdb;

      state->dom = dom;

-     state->sh = sh;

-     state->op = NULL;

+     state->sysdb = sysdb;

+     state->sysdb_dns = sysdb_dns;

+     state->memberel = memberel;

+     state->cur = 0;

  

-     filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",

-                              opts->group_map[SDAP_AT_GROUP_MEMBER].name,

-                              name, opts->group_map[SDAP_OC_GROUP].name);

-     if (!filter) {

+     if (state->memberel->num_values == 0) {

+         /* No members. Done. */

+         tevent_req_done(req);

+         tevent_req_post(req, ev);

+         return req;

+     }

+ 

+     state->missing = talloc_array(state, const char *,

+                                   state->memberel->num_values+1);

+     if (!state->missing) {

          talloc_zfree(req);

          return NULL;

      }

- 

-     subreq = sdap_get_generic_send(state, state->ev, state->opts,

-                                    state->sh, base_dn, LDAP_SCOPE_SUBTREE,

-                                    filter, grp_attrs,

-                                    state->opts->group_map, SDAP_OPTS_GROUP);

+     state->mi = 0;

+     state->missing[state->mi] = NULL;

+ 

+     subreq = sysdb_search_user_by_name_send(state, state->ev,

+                         state->sysdb, NULL,

+                         state->dom,

+                         (const char *) state->memberel->values[state->cur].data,

+                         NULL);

      if (!subreq) {

          talloc_zfree(req);

          return NULL;

      }

-     tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);

+     tevent_req_set_callback(subreq, sdap_process_group_members_2307_step, req);

  

      return req;

  }

  

- static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)

+ void sdap_process_group_members_2307_step(struct tevent_req *subreq)

  {

-     struct tevent_req *req;

-     struct sdap_initgr_rfc2307_state *state;

-     struct sysdb_attrs **groups;

-     size_t count;

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_process_group_members_2307_state *state =

+         tevent_req_data(req, struct sdap_process_group_members_2307_state);

+     struct ldb_message *msg;

+     char *strdn;

      int ret;

  

-     req = tevent_req_callback_data(subreq, struct tevent_req);

-     state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);

- 

-     ret = sdap_get_generic_recv(subreq, state, &count, &groups);

+     ret = sysdb_search_user_recv(subreq, state, &msg);

      talloc_zfree(subreq);

-     if (ret) {

+     if (ret == EOK) {

+         /*

+          * User already cached in sysdb. Remember the sysdb DN for later

+          * use by sdap_save_groups()

+          */

+         strdn = sysdb_user_strdn(state->sysdb_dns->values,

+                     state->dom->name,

+                     (const char *) state->memberel->values[state->cur].data);

+         if (!strdn) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+ 

+         DEBUG(7,("Member already cached in sysdb: %s\n", strdn));

+         state->sysdb_dns->values[state->sysdb_dns->num_values].data =

+             (uint8_t *) strdn;

+         state->sysdb_dns->values[state->sysdb_dns->num_values].length =

+             strlen(strdn);

+         state->sysdb_dns->num_values++;

+     } else if (ret == ENOENT) {

+         /* The user is not in sysdb, need to add it */

+         DEBUG(7, ("member #%d (%s): not found in sysdb\n",

+                    state->cur,

+                    (char *) state->memberel->values[state->cur].data));

+ 

+         /* Just remember the name and store all the fake

+          * entries later in one transaction */

+         state->missing[state->mi] =

+             (const char *) state->memberel->values[state->cur].data;

+         state->mi++;

+         state->missing[state->mi] = NULL;

+     } else {

+         DEBUG(1, ("Error checking cache for member #%d (%s):\n",

+                    state->cur,

+                    (char *) state->memberel->values[state->cur].data));

          tevent_req_error(req, ret);

          return;

      }

  

-     if (count == 0) {

+ 

+     state->cur++;

+     if (state->cur == state->memberel->num_values) {

+         /* All members processed. Add fake entries if needed. */

+         state->ai = 0;

+         sdap_process_group_members_2307_check_add(req);

+         return;

+     }

+ 

+     /* Go to the next member */

+     subreq = sysdb_search_user_by_name_send(state, state->ev,

+                         state->sysdb, NULL,

+                         state->dom,

+                         (char *) state->memberel->values[state->cur].data,

+                         NULL);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_process_group_members_2307_step,

+                             req);

+     return;

+ }

+ 

+ static void

+ sdap_process_group_members_2307_check_add(struct tevent_req *req)

+ {

+     struct sdap_process_group_members_2307_state *state =

+         tevent_req_data(req, struct sdap_process_group_members_2307_state);

+     struct tevent_req *subreq;

+ 

+     if (state->mi == 0) {

+         /* Do not need to add any members. We are done. */

          tevent_req_done(req);

          return;

      }

  

-     subreq = sdap_save_groups_send(state, state->ev, state->dom,

-                                    state->sysdb, state->opts,

-                                    groups, count);

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

      if (!subreq) {

          tevent_req_error(req, ENOMEM);

          return;

      }

-     tevent_req_set_callback(subreq, sdap_initgr_rfc2307_done, req);

+ 

+     tevent_req_set_callback(subreq, sdap_process_group_members_2307_trans,

+                             req);

  }

  

- static void sdap_initgr_rfc2307_done(struct tevent_req *subreq)

+ static void

+ sdap_process_group_members_2307_trans(struct tevent_req *subreq)

  {

-     struct tevent_req *req;

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_process_group_members_2307_state *state =

+         tevent_req_data(req, struct sdap_process_group_members_2307_state);

      int ret;

  

-     req = tevent_req_callback_data(subreq, struct tevent_req);

- 

-     ret = sdap_save_groups_recv(subreq, NULL, NULL);

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

      talloc_zfree(subreq);

      if (ret) {

          tevent_req_error(req, ret);

          return;

      }

  

-     tevent_req_done(req);

+     sdap_process_group_members_2307_add(req);

  }

  

- static int sdap_initgr_rfc2307_recv(struct tevent_req *req)

+ static void

+ sdap_process_group_members_2307_add(struct tevent_req *req)

  {

-     TEVENT_REQ_RETURN_ON_ERROR(req);

+     struct sdap_process_group_members_2307_state *state =

+         tevent_req_data(req, struct sdap_process_group_members_2307_state);

+     struct tevent_req *subreq;

  

-     return EOK;

- }

+     if (state->ai == state->mi) {

+         sdap_process_group_members_2307_post(req);

+         return;

+     }

  

+     subreq = sdap_process_missing_member_2307_send(state, state->ev,

+                                                    state->dom,

+                                                    state->sysdb,

+                                                    state->handle,

+                                                    state->missing[state->ai],

+                                                    state->sysdb_dns);

+     if (!subreq) {

+         DEBUG(1, ("Error adding missing member #%d (%s):\n",

+                     state->ai, state->missing[state->ai]));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_process_group_members_2307_added, req);

+     return;

+ }

  

- /* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */

+ static void

+ sdap_process_group_members_2307_added(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_process_group_members_2307_state *state =

+         tevent_req_data(req, struct sdap_process_group_members_2307_state);

+     int ret;

  

- struct sdap_initgr_nested_state {

-     struct tevent_context *ev;

-     struct sysdb_ctx *sysdb;

-     struct sdap_options *opts;

+     ret = sdap_process_missing_member_2307_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->ai++;

+     sdap_process_group_members_2307_add(req);

+ }

+ 

+ static void

+ sdap_process_group_members_2307_post(struct tevent_req *req)

+ {

+     struct sdap_process_group_members_2307_state *state =

+         tevent_req_data(req, struct sdap_process_group_members_2307_state);

+     struct tevent_req *subreq;

+ 

+     /* Commit the transaction */

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_process_group_members_2307_trans_done,

+                             req);

+ }

+ 

+ static void

+ sdap_process_group_members_2307_trans_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = sysdb_transaction_commit_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* Processing completed. */

+     tevent_req_done(req);

+ }

+ 

+ int sdap_process_group_members_2307_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+     return EOK;

+ }

+ 

+ /*===Process-missing-group-member-of-RFC2307-group============================*/

+ 

+ struct sdap_process_missing_member_2307_state {

+     struct tevent_context *ev;

      struct sss_domain_info *dom;

-     struct sdap_handle *sh;

+     struct sysdb_ctx *sysdb;

+     struct sysdb_handle *handle;

  

-     const char **grp_attrs;

+     const char *username;

+     struct ldb_message_element* sysdb_dns;

  

-     char *filter;

-     char **group_dns;

-     int count;

-     int cur;

+ };

  

-     struct sdap_op *op;

+ static void sdap_process_missing_member_2307_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *

+ sdap_process_missing_member_2307_send(TALLOC_CTX *memctx,

+                                       struct tevent_context *ev,

+                                       struct sss_domain_info *dom,

+                                       struct sysdb_ctx *sysdb,

+                                       struct sysdb_handle *handle,

+                                       const char *username,

+                                       struct ldb_message_element *sysdb_dns)

+ {

+     struct sdap_process_missing_member_2307_state *state;

+     struct tevent_req *req = NULL;

+     struct tevent_req *subreq;

+ 

+     req = tevent_req_create(memctx, &state,

+                             struct sdap_process_missing_member_2307_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->dom = dom;

+     state->handle = handle;

+     state->sysdb = sysdb;

+     state->sysdb_dns = sysdb_dns;

+     state->username = username;

+ 

+     DEBUG(7, ("Adding a dummy entry\n"));

+     subreq = sysdb_add_fake_user_send(state, state->ev, state->handle,

+                                       state->dom, state->username);

+     if (!subreq) {

+         DEBUG(2, ("Cannot store fake user entry\n"));

+         talloc_zfree(req);

+         return NULL;

+     }

+     tevent_req_set_callback(subreq,

+                             sdap_process_missing_member_2307_done,

+                             req);

+     return req;

+ }

+ 

+ static void sdap_process_missing_member_2307_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_process_missing_member_2307_state *state =

+                 tevent_req_data(req,

+                                 struct sdap_process_missing_member_2307_state);

+     int ret;

+     struct ldb_dn *dn;

+     char* dn_string;

+ 

+     ret = sysdb_add_fake_user_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /*

+      * Convert the just received DN into the corresponding sysdb DN

+      * for saving into member attribute of the group

+      */

+     dn = sysdb_user_dn(state->sysdb, state, state->dom->name,

+                        state->username);

+     if (!dn) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     dn_string = ldb_dn_alloc_linearized(state->sysdb_dns->values, dn);

+     if (!dn_string) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     state->sysdb_dns->values[state->sysdb_dns->num_values].data =

+         (uint8_t *) dn_string;

+     state->sysdb_dns->values[state->sysdb_dns->num_values].length =

+         strlen(dn_string);

+     state->sysdb_dns->num_values++;

+ 

+     tevent_req_done(req);

+ }

+ 

+ static int sdap_process_missing_member_2307_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+     return EOK;

+ }

+ 

+ /* ==Search-Groups-with-filter============================================ */

  

+ struct sdap_get_groups_state {

+     struct tevent_context *ev;

+     struct sdap_options *opts;

+     struct sdap_handle *sh;

+     struct sss_domain_info *dom;

+     struct sysdb_ctx *sysdb;

+     const char **attrs;

+     const char *filter;

+ 

+     char *higher_timestamp;

      struct sysdb_attrs **groups;

-     int groups_cur;

+     size_t count;

+ 

+     size_t check_count;

+ 

+     hash_table_t *user_hash;

+     hash_table_t *group_hash;

  };

  

- static void sdap_initgr_nested_search(struct tevent_req *subreq);

- static void sdap_initgr_nested_store(struct tevent_req *req);

- static void sdap_initgr_nested_done(struct tevent_req *subreq);

- static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,

-                                                   struct tevent_context *ev,

-                                                   struct sdap_options *opts,

-                                                   struct sysdb_ctx *sysdb,

-                                                   struct sss_domain_info *dom,

-                                                   struct sdap_handle *sh,

-                                                   struct sysdb_attrs *user,

-                                                   const char **grp_attrs)

+ static void sdap_get_groups_process(struct tevent_req *subreq);

+ static void sdap_get_groups_processed(struct tevent_req *subreq);

+ static void sdap_get_groups_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,

+                                        struct tevent_context *ev,

+                                        struct sss_domain_info *dom,

+                                        struct sysdb_ctx *sysdb,

+                                        struct sdap_options *opts,

+                                        struct sdap_handle *sh,

+                                        const char **attrs,

+                                        const char *filter)

  {

      struct tevent_req *req, *subreq;

-     struct sdap_initgr_nested_state *state;

-     struct ldb_message_element *el;

-     int i, ret;

+     struct sdap_get_groups_state *state;

  

-     req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);

+     req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);

      if (!req) return NULL;

  

      state->ev = ev;

      state->opts = opts;

-     state->sysdb = sysdb;

      state->dom = dom;

      state->sh = sh;

-     state->grp_attrs = grp_attrs;

-     state->op = NULL;

+     state->sysdb = sysdb;

+     state->filter = filter;

+     state->attrs = attrs;

+     state->higher_timestamp = NULL;

+     state->groups =  NULL;

+     state->count = 0;

  

-     state->filter = talloc_asprintf(state, "(objectclass=%s)",

-                                     opts->group_map[SDAP_OC_GROUP].name);

-     if (!state->filter) {

+     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,

+                                    dp_opt_get_string(state->opts->basic,

+                                                      SDAP_GROUP_SEARCH_BASE),

+                                    LDAP_SCOPE_SUBTREE,

+                                    state->filter, state->attrs,

+                                    state->opts->group_map, SDAP_OPTS_GROUP);

+     if (!subreq) {

          talloc_zfree(req);

          return NULL;

      }

+     tevent_req_set_callback(subreq, sdap_get_groups_process, req);

  

-     /* TODO: test rootDSE for deref support and use it if available */

-     /* TODO: or test rootDSE for ASQ support and use it if available */

+     return req;

+ }

  

-     ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el);

-     if (ret || !el || el->num_values == 0) {

-         DEBUG(4, ("User entry lacks original memberof ?\n"));

-         /* user with no groups ? */

+ static struct tevent_req *sdap_nested_group_process_send(

+         TALLOC_CTX *mem_ctx, struct tevent_context *ev,

+         struct sss_domain_info *domain,

+         struct sysdb_ctx *sysdb, struct sysdb_attrs *group,

+         hash_table_t *users, hash_table_t *groups,

+         struct sdap_options *opts, struct sdap_handle *sh,

+         uint32_t nesting);

+ static void sdap_nested_done(struct tevent_req *req);

+ static errno_t sdap_nested_group_process_recv(struct tevent_req *req);

+ static void sdap_get_groups_process(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_groups_state *state = tevent_req_data(req,

+                                             struct sdap_get_groups_state);

+     int ret;

+     int i;

+ 

+     ret = sdap_get_generic_recv(subreq, state,

+                                 &state->count, &state->groups);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     DEBUG(6, ("Search for groups, returned %d results.\n", state->count));

+ 

+     switch (state->count) {

+     case 0:

          tevent_req_error(req, ENOENT);

-         tevent_req_post(req, ev);

+         return;

+     case 1:

+         /* Single group search */

+ 

+         if (state->opts->schema_type == SDAP_SCHEMA_RFC2307) {

+             state->check_count = state->count;

+             for (i=0; i < state->count; i++) {

+                 subreq = sdap_process_group_send(state, state->ev, state->dom,

+                                                  state->sysdb, state->opts,

+                                                  state->groups[i]);

+                 if (!subreq) {

+                     tevent_req_error(req, ENOMEM);

+                     return;

+                 }

+                 tevent_req_set_callback(subreq, sdap_get_groups_processed, req);

+             }

+             return;

+         } else {

+ 

+             /* Prepare hashes for nested user procesing */

+             ret = sss_hash_create(state, 32, &state->user_hash);

+             if (ret != EOK) {

+                 tevent_req_error(req, ret);

+                 return;

+             }

+ 

+             ret = sss_hash_create(state, 32, &state->group_hash);

+             if (ret != EOK) {

+                 tevent_req_error(req, ret);

+                 return;

+             }

+ 

+             subreq = sdap_nested_group_process_send(state,

+                                                     state->ev,

+                                                     state->dom,

+                                                     state->sysdb,

+                                                     state->groups[0],

+                                                     state->user_hash,

+                                                     state->group_hash,

+                                                     state->opts,

+                                                     state->sh,

+                                                     0);

+             if (!subreq) {

+                 tevent_req_error(req, EIO);

+                 return;

+             }

+ 

+             tevent_req_set_callback(subreq, sdap_nested_done, req);

+             return;

+         }

+         break;

+ 

+     default:

+         /* Enumeration */

+         break;

      }

-     state->count = el->num_values;

  

-     state->groups = talloc_zero_array(state, struct sysdb_attrs *,

-                                       state->count + 1);;

-     if (!state->groups) {

-         talloc_zfree(req);

-         return NULL;

+     subreq = sdap_save_groups_send(state, state->ev, state->dom,

+                                    state->sysdb, state->opts,

+                                    state->groups, false, state->count);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

      }

-     state->groups_cur = 0;

+     tevent_req_set_callback(subreq, sdap_get_groups_done, req);

+ }

  

-     state->group_dns = talloc_array(state, char *, state->count + 1);

-     if (!state->group_dns) {

+ static void sdap_get_groups_processed(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_groups_state *state = tevent_req_data(req,

+                                             struct sdap_get_groups_state);

+     int ret;

+ 

+     ret = sdap_process_group_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret) {

+         DEBUG(2, ("Failed to process group.\n"));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->check_count--;

+     DEBUG(9, ("Groups remaining: %d\n", state->check_count));

+ 

+     if (state->check_count == 0) {

+         subreq = sdap_save_groups_send(state, state->ev, state->dom,

+                                        state->sysdb, state->opts,

+                                        state->groups, true, state->count);

+         if (!subreq) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+         tevent_req_set_callback(subreq, sdap_get_groups_done, req);

+     }

+ }

+ 

+ static void sdap_nested_users_done(struct tevent_req *subreq);

+ static void sdap_nested_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     int hret;

+     unsigned long i;

+     unsigned long count;

+     hash_value_t *values;

+     struct sysdb_attrs **users = NULL;

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_groups_state *state = tevent_req_data(req,

+                                             struct sdap_get_groups_state);

+ 

+     ret = sdap_nested_group_process_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(1, ("Nested group processing failed: [%d][%s]\n",

+                   ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     hret = hash_values(state->user_hash, &count, &values);

+     if (hret != HASH_SUCCESS) {

+         tevent_req_error(req, EIO);

+     }

+ 

+     if (count) {

+         users = talloc_array(state, struct sysdb_attrs *, count);

+         if (!users) {

+             talloc_free(values);

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+ 

+         for (i = 0; i < count; i++) {

+             users[i] = talloc_get_type(values[i].ptr, struct sysdb_attrs);

+         }

+         talloc_zfree(values);

+     }

+ 

+     /* Save all of the users first so that they are in

+      * place for the groups to add them.

+      */

+     subreq = sdap_save_users_send(state, state->ev, state->dom,

+                                   state->sysdb, state->opts,

+                                   users, count);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_nested_users_done, req);

+ }

+ 

+ static void sdap_nested_users_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     int hret;

+     unsigned long i;

+     unsigned long count;

+     hash_value_t *values;

+     struct sysdb_attrs **groups;

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_groups_state *state = tevent_req_data(req,

+                                             struct sdap_get_groups_state);

+ 

+     ret = sdap_save_users_recv(subreq, NULL, NULL);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* Users are all saved. Now save groups */

+     hret = hash_values(state->group_hash, &count, &values);

+     if (hret != HASH_SUCCESS) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     groups = talloc_array(state, struct sysdb_attrs *, count);

+     if (!groups) {

+         talloc_free(values);

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     for (i = 0; i < count; i++) {

+         groups[i] = talloc_get_type(values[i].ptr, struct sysdb_attrs);

+     }

+     talloc_zfree(values);

+ 

+     subreq = sdap_save_groups_send(state, state->ev, state->dom,

+                                    state->sysdb, state->opts,

+                                    groups, false, count);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_get_groups_done, req);

+ }

+ 

+ static void sdap_get_groups_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_groups_state *state = tevent_req_data(req,

+                                             struct sdap_get_groups_state);

+     int ret;

+ 

+     DEBUG(9, ("Saving %d Groups - Done\n", state->count));

+ 

+     ret = sdap_save_groups_recv(subreq, state, &state->higher_timestamp);

+     talloc_zfree(subreq);

+     if (ret) {

+         DEBUG(2, ("Failed to store groups.\n"));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ int sdap_get_groups_recv(struct tevent_req *req,

+                          TALLOC_CTX *mem_ctx, char **timestamp)

+ {

+     struct sdap_get_groups_state *state = tevent_req_data(req,

+                                             struct sdap_get_groups_state);

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     if (timestamp) {

+         *timestamp = talloc_steal(mem_ctx, state->higher_timestamp);

+     }

+ 

+     return EOK;

+ }

+ 

+ /* ==Add-Incomplete-Groups====================================================== */

+ struct sdap_add_incomplete_groups_state {

+     struct tevent_context *ev;

+     struct sysdb_ctx *sysdb;

+     struct sysdb_handle *handle;

+     struct sss_domain_info *dom;

+ 

+     char **groupnames;

+     int cur;

+ 

+     struct sysdb_attrs **ldap_groups;

+     int ldap_groups_count;

+ };

+ 

+ static void sdap_add_incomplete_groups_next(struct tevent_req *subreq);

+ static void sdap_add_incomplete_groups_added(struct tevent_req *subreq);

+ 

+ static

+ struct tevent_req *sdap_add_incomplete_groups_send(TALLOC_CTX *memctx,

+                                              struct tevent_context *ev,

+                                              struct sysdb_ctx *sysdb,

+                                              struct sysdb_handle *handle,

+                                              struct sss_domain_info *dom,

+                                              char **groupnames,

+                                              struct sysdb_attrs **ldap_groups,

+                                              int ldap_groups_count)

+ {

+     struct tevent_req *req, *subreq;

+     struct sdap_add_incomplete_groups_state *state;

+ 

+     req = tevent_req_create(memctx, &state, struct sdap_add_incomplete_groups_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->sysdb = sysdb;

+     state->handle = handle;

+     state->dom = dom;

+     state->groupnames = groupnames;

+     state->ldap_groups = ldap_groups;

+     state->ldap_groups_count = ldap_groups_count;

+     state->cur = 0;

+ 

+     subreq = sysdb_search_group_by_name_send(state, ev, sysdb, handle, dom,

+                                              state->groupnames[state->cur],

+                                              NULL);

+     if (!subreq) {

+         talloc_zfree(req);

+         return NULL;

+     }

+     tevent_req_set_callback(subreq, sdap_add_incomplete_groups_next, req);

+ 

+     return req;

+ }

+ 

+ static void sdap_add_incomplete_groups_next(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_add_incomplete_groups_state *state = tevent_req_data(req,

+                                            struct sdap_add_incomplete_groups_state);

+     errno_t ret;

+     int ai;

+     const char *name;

+     gid_t gid;

+     struct ldb_message *msg = NULL;

+     struct ldb_message_element *el;

+     struct tevent_req *add_req = NULL;

+     struct tevent_req *next_req = NULL;

+ 

+     ret = sysdb_search_group_recv(subreq, state, &msg);

+     talloc_zfree(subreq);

+     if (ret == EOK) {

+         state->cur++;

+         if (state->groupnames[state->cur]) {

+             next_req = sysdb_search_group_by_name_send(state, state->ev,

+                                                     state->sysdb,

+                                                     state->handle,

+                                                     state->dom,

+                                                     state->groupnames[state->cur],

+                                                     NULL);

+             if (!next_req) {

+                 tevent_req_error(req, EIO);

+                 return;

+             }

+             tevent_req_set_callback(next_req, sdap_add_incomplete_groups_next, req);

+             return;

+         }

+ 

+         tevent_req_done(req);

+         return;

+     } else if (ret == ENOENT) {

+         DEBUG(7, ("Group #%d [%s] is not cached, need to add a incomplete entry\n",

+                     state->cur, state->groupnames[state->cur]));

+ 

+         /* The group is not in sysdb, need to add an incomplete entry */

+         for (ai=0; ai < state->ldap_groups_count; ai++) {

+             ret = sysdb_attrs_get_el(state->ldap_groups[ai],

+                                     SYSDB_NAME,

+                                     &el);

+             if (ret) {

+                 tevent_req_error(req, ret);

+                 return;

+             }

+             if (el->num_values == 0) {

+                 tevent_req_error(req, EINVAL);

+                 return;

+             }

+             name = (const char *)el->values[0].data;

+ 

+             if (strcmp(name, state->groupnames[state->cur]) == 0) {

+                 ret = sysdb_attrs_get_uint32_t(state->ldap_groups[ai],

+                                                SYSDB_GIDNUM,

+                                                &gid);

+                 if (ret) {

+                     DEBUG(1, ("no gid provided for [%s]\n", name));

+                     tevent_req_error(req, ret);

+                     return;

+                 }

+ 

+                 add_req = sysdb_add_incomplete_group_send(state,

+                                                     state->ev,

+                                                     state->handle,

+                                                     state->dom,

+                                                     state->groupnames[state->cur],

+                                                     gid);

+                 if (add_req == NULL) {

+                     tevent_req_error(req, EIO);

+                     return;

+                 }

+ 

+                 tevent_req_set_callback(add_req,

+                                         sdap_add_incomplete_groups_added,

+                                         req);

+                 return;

+             }

+         }

+ 

+         if (ai == state->ldap_groups_count) {

+             tevent_req_error(req, EINVAL);

+             return;

+         }

+     }

+ 

+     DEBUG(2, ("Search failed: %s (%d)\n", strerror(ret), ret));

+     tevent_req_error(req, ret);

+ }

+ 

+ static void sdap_add_incomplete_groups_added(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_add_incomplete_groups_state *state = tevent_req_data(req,

+                                            struct sdap_add_incomplete_groups_state);

+     errno_t ret;

+     struct tevent_req *next_req = NULL;

+ 

+     ret = sysdb_add_incomplete_group_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     state->cur++;

+     if (state->groupnames[state->cur]) {

+         next_req = sysdb_search_group_by_name_send(state, state->ev,

+                                                    state->sysdb, state->handle,

+                                                    state->dom,

+                                                    state->groupnames[state->cur],

+                                                    NULL);

+         if (!next_req) {

+             tevent_req_error(req, EIO);

+             return;

+         }

+         tevent_req_set_callback(next_req, sdap_add_incomplete_groups_next, req);

+         return;

+     }

+ 

+     tevent_req_done(req);

+     return;

+ }

+ 

+ int sdap_add_incomplete_groups_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ /* ==Initgr-call-(groups-a-user-is-member-of)-RFC2307-Classic/BIS========= */

+ 

+ struct sdap_initgr_rfc2307_state {

+     struct tevent_context *ev;

+     struct sysdb_ctx *sysdb;

+     struct sdap_options *opts;

+     struct sss_domain_info *dom;

+     struct sdap_handle *sh;

+     const char *name;

+ 

+     struct sysdb_handle *handle;

+     char **ldap_grouplist;

+ 

+     struct sysdb_attrs **ldap_groups;

+     size_t ldap_groups_count;

+ 

+     char **add_groups;

+     char **del_groups;

+ 

+     struct sdap_op *op;

+ };

+ 

+ static void sdap_initgr_rfc2307_process(struct tevent_req *subreq);

+ 

+ static

+ struct tevent_req *sdap_initgr_rfc2307_send(TALLOC_CTX *memctx,

+                                             struct tevent_context *ev,

+                                             struct sdap_options *opts,

+                                             struct sysdb_ctx *sysdb,

+                                             struct sss_domain_info *dom,

+                                             struct sdap_handle *sh,

+                                             const char *base_dn,

+                                             const char *name)

+ {

+     struct tevent_req *req, *subreq;

+     struct sdap_initgr_rfc2307_state *state;

+     const char *filter;

+     const char **attrs;

+     errno_t ret;

+ 

+     req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->opts = opts;

+     state->sysdb = sysdb;

+     state->dom = dom;

+     state->sh = sh;

+     state->op = NULL;

+     state->name = talloc_strdup(state, name);

+     if (!state->name) {

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     ret = build_attrs_from_map(state, opts->group_map,

+                                SDAP_OPTS_GROUP, &attrs);

+     if (ret != EOK) {

+         talloc_free(req);

+         return NULL;

+     }

+ 

+     filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",

+                              opts->group_map[SDAP_AT_GROUP_MEMBER].name,

+                              name, opts->group_map[SDAP_OC_GROUP].name);

+     if (!filter) {

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev, state->opts,

+                                    state->sh, base_dn, LDAP_SCOPE_SUBTREE,

+                                    filter, attrs,

+                                    state->opts->group_map, SDAP_OPTS_GROUP);

+     if (!subreq) {

+         talloc_zfree(req);

+         return NULL;

+     }

+     tevent_req_set_callback(subreq, sdap_initgr_rfc2307_process, req);

+ 

+     return req;

+ }

+ 

+ static void sdap_initgr_rfc2307_get_sysdb_groups(struct tevent_req *subreq);

+ static void sdap_initgr_rfc2307_process(struct tevent_req *subreq)

+ {

+     struct tevent_req *req;

+     struct sdap_initgr_rfc2307_state *state;

+     int ret;

+ 

+     req = tevent_req_callback_data(subreq, struct tevent_req);

+     state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+ 

+     ret = sdap_get_generic_recv(subreq, state,

+                                 &state->ldap_groups_count,

+                                 &state->ldap_groups);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (state->ldap_groups_count == 0) {

+         /* No groups for this user in LDAP

+          * We need to ensure that there are no groups

+          * in the sysdb either.

+          */

+ 

+         state->ldap_grouplist = NULL;

+     }

+     else {

+         ret = sysdb_attrs_to_list(state,

+                                   state->ldap_groups, state->ldap_groups_count,

+                                   SYSDB_NAME,

+                                   &state->ldap_grouplist);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+             return;

+         }

+     }

+     /* Start a transaction to look up the groups in the sysdb

+      * and update them with LDAP data

+      */

+ 

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307_get_sysdb_groups,

+                             req);

+ }

+ 

+ static void sdap_initgr_rfc2307_update_sysdb_groups(struct tevent_req *subreq);

+ static void sdap_initgr_rfc2307_get_sysdb_groups(struct tevent_req *subreq)

+ {

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+     int ret;

+     const char **attrs;

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     attrs = talloc_array(state, const char *, 2);

+     if (!attrs) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     attrs[0] = SYSDB_MEMBEROF;

+     attrs[1] = NULL;

+ 

+     /* Search for all groups for which this user is a member */

+     subreq = sysdb_search_user_by_name_send(state, state->ev, state->sysdb,

+                                             state->handle, state->dom,

+                                             state->name, attrs);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307_update_sysdb_groups,

+                             req);

+ }

+ 

+ static void

+ sdap_initgr_rfc2307_update_sysdb_groups_done(struct tevent_req *subreq);

+ static void

+ sdap_initgr_rfc2307_update_sysdb_groups_step(struct tevent_req *subreq);

+ 

+ static void sdap_initgr_rfc2307_update_sysdb_groups(struct tevent_req *subreq)

+ {

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+     int ret, i;

+     struct ldb_message *reply;

+     struct ldb_message_element *groups;

+     char **sysdb_grouplist;

+ 

+     ret = sysdb_search_user_recv(subreq, state, &reply);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     groups = ldb_msg_find_element(reply, SYSDB_MEMBEROF);

+     if (!groups || groups->num_values == 0) {

+         DEBUG(6, ("User is not a member of any groups\n"));

+         sysdb_grouplist = NULL;

+     } else {

+         sysdb_grouplist = talloc_array(state, char *,

+                                        groups->num_values+1);

+         if (!sysdb_grouplist) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+ 

+         /* Get a list of the groups by groupname only */

+         for (i=0; i < groups->num_values; i++) {

+             ret = sysdb_group_dn_name(state->sysdb,

+                     sysdb_grouplist,

+                     (const char *)groups->values[i].data,

+                     &sysdb_grouplist[i]);

+             if (ret != EOK) {

+                 tevent_req_error(req, ENOMEM);

+                 return;

+             }

+         }

+ 

+         sysdb_grouplist[groups->num_values] = NULL;

+     }

+ 

+     /* Find the differences between the sysdb and ldap lists

+      * Groups in ldap only must be added to the sysdb;

+      * groups in the sysdb only must be removed.

+      */

+     ret = diff_string_lists(state,

+                             state->ldap_grouplist, sysdb_grouplist,

+                             &state->add_groups, &state->del_groups, NULL);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (state->add_groups && state->add_groups[0]) {

+         subreq = sdap_add_incomplete_groups_send(state, state->ev, state->sysdb,

+                                                  state->handle, state->dom,

+                                                  state->add_groups,

+                                                  state->ldap_groups,

+                                                  state->ldap_groups_count);

+         if (!subreq) {

+             tevent_req_error(req, EIO);

+             return;

+         }

+ 

+         tevent_req_set_callback(subreq,

+                                 sdap_initgr_rfc2307_update_sysdb_groups_step,

+                                 req);

+         return;

+     }

+ 

+ 

+ 

+     subreq = sysdb_update_members_send(state, state->ev, state->handle,

+                                        state->dom, state->name,

+                                        SYSDB_MEMBER_USER,

+                                        state->add_groups, state->del_groups);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307_update_sysdb_groups_done,

+                             req);

+ }

+ 

+ static void

+ sdap_initgr_rfc2307_update_sysdb_groups_step(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+     struct tevent_req *updatereq;

+ 

+     ret = sdap_add_incomplete_groups_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     updatereq = sysdb_update_members_send(state, state->ev, state->handle,

+                                        state->dom, state->name,

+                                        SYSDB_MEMBER_USER,

+                                        state->add_groups, state->del_groups);

+     if (!updatereq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(updatereq,

+                             sdap_initgr_rfc2307_update_sysdb_groups_done,

+                             req);

+ }

+ 

+ static void

+ sdap_initgr_rfc2307_transaction_done(struct tevent_req *subreq);

+ static void

+ sdap_initgr_rfc2307_update_sysdb_groups_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+ 

+     ret = sysdb_update_members_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* Commit the transaction */

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307_transaction_done,

+                             req);

+ }

+ 

+ static void

+ sdap_initgr_rfc2307_transaction_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = sysdb_transaction_commit_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* Processing completed. Return control to sdap_get_initgr_done() */

+     tevent_req_done(req);

+ }

+ 

+ static int sdap_initgr_rfc2307_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ 

+ /* ==Initgr-call-(groups-a-user-is-member-of)-nested-groups=============== */

+ 

+ struct sdap_initgr_nested_state {

+     struct tevent_context *ev;

+     struct sysdb_ctx *sysdb;

+     struct sdap_options *opts;

+     struct sss_domain_info *dom;

+     struct sdap_handle *sh;

+ 

+     const char **grp_attrs;

+ 

+     char *filter;

+     char **group_dns;

+     int count;

+     int cur;

+ 

+     struct sdap_op *op;

+ 

+     struct sysdb_attrs **groups;

+     int groups_cur;

+ };

+ 

+ static void sdap_initgr_nested_search(struct tevent_req *subreq);

+ static void sdap_initgr_nested_store(struct tevent_req *req);

+ static void sdap_initgr_nested_done(struct tevent_req *subreq);

+ static struct tevent_req *sdap_initgr_nested_send(TALLOC_CTX *memctx,

+                                                   struct tevent_context *ev,

+                                                   struct sdap_options *opts,

+                                                   struct sysdb_ctx *sysdb,

+                                                   struct sss_domain_info *dom,

+                                                   struct sdap_handle *sh,

+                                                   struct sysdb_attrs *user,

+                                                   const char **grp_attrs)

+ {

+     struct tevent_req *req, *subreq;

+     struct sdap_initgr_nested_state *state;

+     struct ldb_message_element *el;

+     int i, ret;

+ 

+     req = tevent_req_create(memctx, &state, struct sdap_initgr_nested_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->opts = opts;

+     state->sysdb = sysdb;

+     state->dom = dom;

+     state->sh = sh;

+     state->grp_attrs = grp_attrs;

+     state->op = NULL;

+ 

+     state->filter = talloc_asprintf(state, "(objectclass=%s)",

+                                     opts->group_map[SDAP_OC_GROUP].name);

+     if (!state->filter) {

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     /* TODO: test rootDSE for deref support and use it if available */

+     /* TODO: or test rootDSE for ASQ support and use it if available */

+ 

+     ret = sysdb_attrs_get_el(user, SYSDB_MEMBEROF, &el);

+     if (ret || !el || el->num_values == 0) {

+         DEBUG(4, ("User entry lacks original memberof ?\n"));

+         /* user with no groups ? */

+         tevent_req_error(req, ENOENT);

+         tevent_req_post(req, ev);

+         return req;

+     }

+     state->count = el->num_values;

+ 

+     state->groups = talloc_zero_array(state, struct sysdb_attrs *,

+                                       state->count + 1);;

+     if (!state->groups) {

+         talloc_zfree(req);

+         return NULL;

+     }

+     state->groups_cur = 0;

+ 

+     state->group_dns = talloc_array(state, char *, state->count + 1);

+     if (!state->group_dns) {

+         talloc_zfree(req);

+         return NULL;

+     }

+     for (i = 0; i < state->count; i++) {

+         state->group_dns[i] = talloc_strdup(state->group_dns,

+                                             (char *)el->values[i].data);

+         if (!state->group_dns[i]) {

+             talloc_zfree(req);

+             return NULL;

+         }

+     }

+     state->group_dns[i] = NULL; /* terminate */

+     state->cur = 0;

+ 

+     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,

+                                    state->group_dns[state->cur],

+                                    LDAP_SCOPE_BASE,

+                                    state->filter, state->grp_attrs,

+                                    state->opts->group_map, SDAP_OPTS_GROUP);

+     if (!subreq) {

+         talloc_zfree(req);

+         return NULL;

+     }

+     tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);

+ 

+     return req;

+ }

+ 

+ static void sdap_initgr_nested_search(struct tevent_req *subreq)

+ {

+     struct tevent_req *req;

+     struct sdap_initgr_nested_state *state;

+     struct sysdb_attrs **groups;

+     size_t count;

+     int ret;

+ 

+     req = tevent_req_callback_data(subreq, struct tevent_req);

+     state = tevent_req_data(req, struct sdap_initgr_nested_state);

+ 

+     ret = sdap_get_generic_recv(subreq, state, &count, &groups);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (count == 1) {

+         state->groups[state->groups_cur] = groups[0];

+         state->groups_cur++;

+     } else {

+         DEBUG(2, ("Search for group %s, returned %d results. Skipping\n",

+                   state->group_dns[state->cur], count));

+     }

+ 

+     state->cur++;

+     if (state->cur < state->count) {

+         subreq = sdap_get_generic_send(state, state->ev,

+                                        state->opts, state->sh,

+                                        state->group_dns[state->cur],

+                                        LDAP_SCOPE_BASE,

+                                        state->filter, state->grp_attrs,

+                                        state->opts->group_map,

+                                        SDAP_OPTS_GROUP);

+         if (!subreq) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+         tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);

+     } else {

+         sdap_initgr_nested_store(req);

+     }

+ }

+ 

+ static void sdap_initgr_nested_store(struct tevent_req *req)

+ {

+     struct tevent_req *subreq;

+     struct sdap_initgr_nested_state *state;

+ 

+     state = tevent_req_data(req, struct sdap_initgr_nested_state);

+ 

+     subreq = sdap_save_groups_send(state, state->ev, state->dom,

+                                    state->sysdb, state->opts,

+                                    state->groups, false, state->groups_cur);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_initgr_nested_done, req);

+ }

+ 

+ static void sdap_initgr_nested_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req;

+     int ret;

+ 

+     req = tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = sdap_save_groups_recv(subreq, NULL, NULL);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ static int sdap_initgr_nested_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ 

+ /* ==Initgr-call-(groups-a-user-is-member-of)============================= */

+ 

+ struct sdap_get_initgr_state {

+     struct tevent_context *ev;

+     struct sysdb_ctx *sysdb;

+     struct sdap_options *opts;

+     struct sss_domain_info *dom;

+     struct sdap_handle *sh;

+     const char *name;

+     const char **grp_attrs;

+ 

+     struct sysdb_attrs *orig_user;

+ 

+     struct sysdb_handle *handle;

+ };

+ 

+ static void sdap_get_initgr_user(struct tevent_req *subreq);

+ static void sdap_get_initgr_store(struct tevent_req *subreq);

+ static void sdap_get_initgr_commit(struct tevent_req *subreq);

+ static void sdap_get_initgr_process(struct tevent_req *subreq);

+ static void sdap_get_initgr_done(struct tevent_req *subreq);

+ 

+ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,

+                                         struct tevent_context *ev,

+                                         struct sss_domain_info *dom,

+                                         struct sysdb_ctx *sysdb,

+                                         struct sdap_options *opts,

+                                         struct sdap_handle *sh,

+                                         const char *name,

+                                         const char **grp_attrs)

+ {

+     struct tevent_req *req, *subreq;

+     struct sdap_get_initgr_state *state;

+     const char *base_dn;

+     char *filter;

+     const char **attrs;

+     int ret;

+ 

+     DEBUG(9, ("Retrieving info for initgroups call\n"));

+ 

+     req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->opts = opts;

+     state->sysdb = sysdb;

+     state->dom = dom;

+     state->sh = sh;

+     state->name = name;

+     state->grp_attrs = grp_attrs;

+     state->orig_user = NULL;

+ 

+     filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",

+                         state->opts->user_map[SDAP_AT_USER_NAME].name,

+                         state->name,

+                         state->opts->user_map[SDAP_OC_USER].name);

+     if (!filter) {

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     base_dn = dp_opt_get_string(state->opts->basic,

+                                 SDAP_USER_SEARCH_BASE);

+     if (!base_dn) {

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     ret = build_attrs_from_map(state, state->opts->user_map,

+                                SDAP_OPTS_USER, &attrs);

+     if (ret) {

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev,

+                                    state->opts, state->sh,

+                                    base_dn, LDAP_SCOPE_SUBTREE,

+                                    filter, attrs,

+                                    state->opts->user_map, SDAP_OPTS_USER);

+     if (!subreq) {

+         talloc_zfree(req);

+         return NULL;

+     }

+     tevent_req_set_callback(subreq, sdap_get_initgr_user, req);

+ 

+     return req;

+ }

+ 

+ static void sdap_get_initgr_user(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_initgr_state *state = tevent_req_data(req,

+                                                struct sdap_get_initgr_state);

+     struct sysdb_attrs **usr_attrs;

+     size_t count;

+     int ret;

+ 

+     DEBUG(9, ("Receiving info for the user\n"));

+ 

+     ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     if (count != 1) {

+         DEBUG(2, ("Expected one user entry and got %d\n", count));

+         tevent_req_error(req, ENOENT);

+         return;

+     }

+ 

+     state->orig_user = usr_attrs[0];

+ 

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_get_initgr_store, req);

+ }

+ 

+ static void sdap_get_initgr_store(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_initgr_state *state = tevent_req_data(req,

+                                                struct sdap_get_initgr_state);

+     int ret;

+ 

+     DEBUG(9, ("Storing the user\n"));

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     subreq = sdap_save_user_send(state, state->ev, state->handle,

+                                  state->opts, state->dom,

+                                  state->orig_user, true);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_get_initgr_commit, req);

+ }

+ 

+ static void sdap_get_initgr_commit(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_initgr_state *state = tevent_req_data(req,

+                                                struct sdap_get_initgr_state);

+     int ret;

+ 

+     DEBUG(9, ("Commit change\n"));

+ 

+     ret = sdap_save_user_recv(subreq, NULL, NULL);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (!subreq) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_get_initgr_process, req);

+ }

+ 

+ static struct tevent_req *sdap_initgr_rfc2307bis_send(

+         TALLOC_CTX *memctx,

+         struct tevent_context *ev,

+         struct sdap_options *opts,

+         struct sysdb_ctx *sysdb,

+         struct sss_domain_info *dom,

+         struct sdap_handle *sh,

+         const char *base_dn,

+         const char *name,

+         const char *orig_dn);

+ static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req);

+ static void sdap_get_initgr_process(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_initgr_state *state = tevent_req_data(req,

+                                                struct sdap_get_initgr_state);

+     int ret;

+     const char *orig_dn;

+ 

+     DEBUG(9, ("Process user's groups\n"));

+ 

+     ret = sysdb_transaction_commit_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     switch (state->opts->schema_type) {

+     case SDAP_SCHEMA_RFC2307:

+         subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,

+                                     state->sysdb, state->dom, state->sh,

+                                     dp_opt_get_string(state->opts->basic,

+                                                   SDAP_GROUP_SEARCH_BASE),

+                                     state->name);

+         if (!subreq) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+         tevent_req_set_callback(subreq, sdap_get_initgr_done, req);

+         break;

+ 

+     case SDAP_SCHEMA_RFC2307BIS:

+         ret = sysdb_attrs_get_string(state->orig_user,

+                                      SYSDB_ORIG_DN,

+                                      &orig_dn);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+             return;

+         }

+ 

+         subreq = sdap_initgr_rfc2307bis_send(

+                 state, state->ev, state->opts, state->sysdb, state->dom,

+                 state->sh, dp_opt_get_string(state->opts->basic,

+                                              SDAP_GROUP_SEARCH_BASE),

+                 state->name, orig_dn);

+         if (!subreq) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+         talloc_steal(subreq, orig_dn);

+         tevent_req_set_callback(subreq, sdap_get_initgr_done, req);

+         break;

+     case SDAP_SCHEMA_IPA_V1:

+     case SDAP_SCHEMA_AD:

+         /* TODO: AD uses a different member/memberof schema

+          *       We need an AD specific call that is able to unroll

+          *       nested groups by doing extensive recursive searches */

+ 

+         subreq = sdap_initgr_nested_send(state, state->ev, state->opts,

+                                          state->sysdb, state->dom, state->sh,

+                                          state->orig_user, state->grp_attrs);

+         if (!subreq) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+         tevent_req_set_callback(subreq, sdap_get_initgr_done, req);

+         return;

+ 

+     default:

+         tevent_req_error(req, EINVAL);

+         return;

+     }

+ }

+ 

+ static void sdap_get_initgr_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req = tevent_req_callback_data(subreq,

+                                                       struct tevent_req);

+     struct sdap_get_initgr_state *state = tevent_req_data(req,

+                                                struct sdap_get_initgr_state);

+     int ret;

+ 

+     DEBUG(9, ("Initgroups done\n"));

+ 

+     switch (state->opts->schema_type) {

+     case SDAP_SCHEMA_RFC2307:

+ 

+         ret = sdap_initgr_rfc2307_recv(subreq);

+         break;

+ 

+     case SDAP_SCHEMA_RFC2307BIS:

+ 

+         ret = sdap_initgr_rfc2307bis_recv(subreq);

+         break;

+ 

+     case SDAP_SCHEMA_IPA_V1:

+     case SDAP_SCHEMA_AD:

+ 

+         ret = sdap_initgr_nested_recv(subreq);

+         break;

+ 

+     default:

+ 

+         ret = EINVAL;

+         break;

+     }

+ 

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ int sdap_get_initgr_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ struct sdap_nested_group_ctx {

+     struct tevent_context *ev;

+     struct sysdb_ctx *sysdb;

+     struct sss_domain_info *domain;

+ 

+     hash_table_t *users;

+     hash_table_t *groups;

+ 

+     struct sdap_options *opts;

+     struct sdap_handle *sh;

+ 

+     uint32_t nesting_level;

+ 

+     struct ldb_message_element *members;

+     uint32_t member_index;

+     char *member_dn;

+ };

+ 

+ static errno_t sdap_nested_group_process_step(struct tevent_req *req);

+ static struct tevent_req *sdap_nested_group_process_send(

+         TALLOC_CTX *mem_ctx, struct tevent_context *ev,

+         struct sss_domain_info *domain,

+         struct sysdb_ctx *sysdb, struct sysdb_attrs *group,

+         hash_table_t *users, hash_table_t *groups,

+         struct sdap_options *opts, struct sdap_handle *sh,

+         uint32_t nesting)

+ {

+     errno_t ret;

+     int hret;

+     struct tevent_req *req;

+     struct sdap_nested_group_ctx *state;

+     const char *groupname;

+     hash_key_t key;

+     hash_value_t value;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct sdap_nested_group_ctx);

+     if (!req) {

+         return NULL;

+     }

+ 

+     state->ev = ev;

+     state->sysdb = sysdb;

+     state->domain = domain;

+     state->users = users;

+     state->groups = groups;

+     state->opts = opts;

+     state->sh = sh;

+     state->nesting_level = nesting;

+ 

+     /* If this is too many levels deep, just return success */

+     if (nesting > dp_opt_get_int(opts->basic, SDAP_NESTING_LEVEL)) {

+         ret = EOK;

+         goto immediate;

+     }

+ 

+     /* Add the current group to the groups hash so we don't

+      * look it up more than once

+      */

+     key.type = HASH_KEY_STRING;

+ 

+     ret = sysdb_attrs_get_string(

+             group,

+             opts->group_map[SDAP_AT_GROUP_NAME].sys_name,

+             &groupname);

+     if (ret != EOK) goto immediate;

+ 

+     key.str = talloc_strdup(state, groupname);

+     if (!key.str) {

+         ret = ENOMEM;

+         goto immediate;

+     }

+ 

+     if (hash_has_key(groups, &key)) {

+         /* This group has already been processed

+          * (or is in progress)

+          * Skip it and just return success

+          */

+         ret = EOK;

+         goto immediate;

+     }

+ 

+     value.type = HASH_VALUE_PTR;

+     value.ptr = talloc_steal(groups, group);

+ 

+     hret = hash_enter(groups, &key, &value);

+     if (hret != HASH_SUCCESS) {

+         ret = EIO;

+         goto immediate;

+     }

+     talloc_free(key.str);

+ 

+     /* Process group memberships */

+ 

+     /* TODO: future enhancement, check for memberuid as well

+      * See https://fedorahosted.org/sssd/ticket/445

+      */

+ 

+     ret = sysdb_attrs_get_el(

+             group,

+             opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,

+             &state->members);

+     if (ret != EOK) {

+         if (ret == ENOENT) {

+             /* No members to process */

+             ret = EOK;

+         }

+         goto immediate;

+     }

+ 

+     state->member_index = 0;

+ 

+     ret = sdap_nested_group_process_step(req);

+     if (ret != EAGAIN) goto immediate;

+ 

+     return req;

+ 

+ immediate:

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else {

+         tevent_req_error(req, ret);

+     }

+     tevent_req_post(req, ev);

+     return req;

+ }

+ 

+ static void sdap_nested_group_process_sysdb_users(struct tevent_req *subreq);

+ static errno_t sdap_nested_group_process_step(struct tevent_req *req)

+ {

+     errno_t ret;

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+     struct tevent_req *subreq;

+     char *filter;

+     static const char *attrs[] = SYSDB_PW_ATTRS;

+     bool has_key = false;

+     hash_key_t key;

+     uint8_t *data;

+ 

+     do {

+         if (state->member_index >= state->members->num_values) {

+             /* No more entries to check. Return success */

+             return EOK;

+         }

+ 

+         /* First check whether this origDN is present (and not expired)

+          * in the sysdb

+          */

+         data = state->members->values[state->member_index].data;

+         state->member_dn = talloc_strdup(state, (const char *)data);

+         if (!state->member_dn) {

+             ret = ENOMEM;

+             goto error;

+         }

+ 

+         /* Check the user hash

+          * If it's there, we can save ourselves a trip to the

+          * sysdb and possibly LDAP as well

+          */

+         key.type = HASH_KEY_STRING;

+         key.str = state->member_dn;

+         has_key = hash_has_key(state->users, &key);

+         if (has_key) {

+             talloc_zfree(state->member_dn);

+             state->member_index++;

+             continue;

+         }

+ 

+ 

+     } while (has_key);

+ 

+     /* Check for the specified origDN in the sysdb */

+     filter = talloc_asprintf(NULL, "(%s=%s)",

+                              SYSDB_ORIG_DN,

+                              state->member_dn);

+     if (!filter) {

+         ret = ENOMEM;

+         goto error;

+     }

+ 

+     /* Try users first */

+     subreq = sysdb_search_users_send(state, state->ev, state->sysdb,

+                                       NULL, state->domain, filter,

+                                       attrs);

+     if (!subreq) {

+         ret = EIO;

+         talloc_free(filter);

+         goto error;

+     }

+     talloc_steal(subreq, filter);

+     tevent_req_set_callback(subreq,

+                             sdap_nested_group_process_sysdb_users,

+                             req);

+ 

+     return EAGAIN;

+ 

+ error:

+     talloc_zfree(state->member_dn);

+     return ret;

+ }

+ 

+ static void sdap_nested_group_process_user(struct tevent_req *subreq);

+ static void sdap_nested_group_process_group(struct tevent_req *subreq);

+ static void sdap_nested_group_process_sysdb_groups(struct tevent_req *subreq);

+ static errno_t sdap_nested_group_lookup_user(struct tevent_req *req,

+                                              tevent_req_fn fn);

+ static void sdap_nested_group_process_sysdb_users(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+     size_t count;

+     struct ldb_message **msgs;

+     uint64_t expiration;

+     time_t now = time(NULL);

+     char *filter;

+ 

+     static const char *attrs[] = SYSDB_GRSRC_ATTRS;

+ 

+     ret = sysdb_search_users_recv(subreq, state, &count, &msgs);

+     talloc_zfree(subreq);

+     if (ret != EOK && ret != ENOENT) {

+         tevent_req_error(req, ret);

+         return;

+     } if (ret == ENOENT || count == 0) {

+         /* It wasn't a user. Check whether it's a group */

+         if (ret == EOK) talloc_zfree(msgs);

+ 

+         filter = talloc_asprintf(NULL, "(%s=%s)",

+                                  SYSDB_ORIG_DN,

+                                  state->member_dn);

+         if (!filter) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

+         subreq = sysdb_search_groups_send(state, state->ev, state->sysdb,

+                                           NULL, state->domain, filter,

+                                           attrs);

+         if (!subreq) {

+             talloc_free(filter);

+             tevent_req_error(req, EIO);

+             return;

+         }

+         talloc_steal(subreq, filter);

+         tevent_req_set_callback(subreq,

+                                 sdap_nested_group_process_sysdb_groups,

+                                 req);

+         return;

+     }

+ 

+     /* Check whether the entry is valid */

+     if (count != 1) {

+         DEBUG(1, ("More than one entry with this origDN? Skipping\n"));

+         goto skip;

+     }

+ 

+     expiration = ldb_msg_find_attr_as_uint64(msgs[0],

+                                              SYSDB_CACHE_EXPIRE,

+                                              0);

+     if (expiration && expiration > now) {

+         DEBUG(6, ("Cached values are still valid. Skipping\n"));

+         goto skip;

+     }

+ 

+     ret = sdap_nested_group_lookup_user(req, sdap_nested_group_process_user);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+     }

+     return;

+ 

+ skip:

+     state->member_index++;

+     talloc_zfree(state->member_dn);

+     ret = sdap_nested_group_process_step(req);

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else if (ret != EAGAIN) {

+         tevent_req_error(req, ret);

+     }

+ 

+     /* EAGAIN means that we should re-enter

+      * the mainloop

+      */

+ }

+ 

+ static errno_t sdap_nested_group_lookup_user(struct tevent_req *req,

+                                              tevent_req_fn fn)

+ {

+     errno_t ret;

+     const char **sdap_attrs;

+     char *filter;

+     struct tevent_req *subreq;

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+ 

+     ret = build_attrs_from_map(state, state->opts->user_map,

+                                SDAP_OPTS_USER, &sdap_attrs);

+     if (ret != EOK) {

+         return ret;

+     }

+ 

+     filter = talloc_asprintf(

+             sdap_attrs, "(objectclass=%s)",

+             state->opts->user_map[SDAP_OC_USER].name);

+     if (!filter) {

+         talloc_free(sdap_attrs);

+         return ENOMEM;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev, state->opts,

+                                    state->sh, state->member_dn,

+                                    LDAP_SCOPE_BASE,

+                                    filter, sdap_attrs,

+                                    state->opts->user_map,

+                                    SDAP_OPTS_USER);

+     if (!subreq) {

+         talloc_free(sdap_attrs);

+         return EIO;

+     }

+     talloc_steal(subreq, sdap_attrs);

+ 

+     tevent_req_set_callback(subreq, fn, req);

+     return EOK;

+ }

+ 

+ static errno_t sdap_nested_group_lookup_group(struct tevent_req *req);

+ static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq);

+ static void sdap_nested_group_process_sysdb_groups(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+     size_t count;

+     uint64_t expiration;

+     struct ldb_message **msgs;

+     time_t now = time(NULL);

+ 

+     ret = sysdb_search_groups_recv(subreq, state, &count, &msgs);

+     talloc_zfree(subreq);

+     if (ret != EOK && ret != ENOENT) {

+         tevent_req_error(req, ret);

+         return;

+     } if (ret == ENOENT || count == 0) {

+         /* It wasn't found in the groups either

+          * We'll have to do a blind lookup for both

+          */

+ 

+         /* Try users first */

+         ret = sdap_nested_group_lookup_user(

+                 req, sdap_nested_group_process_ldap_user);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+         }

+         return;

+     }

+ 

+     /* Check whether the entry is valid */

+     if (count != 1) {

+         DEBUG(1, ("More than one entry with this origDN? Skipping\n"));

+         goto skip;

+     }

+ 

+     expiration = ldb_msg_find_attr_as_uint64(msgs[0],

+                                              SYSDB_CACHE_EXPIRE,

+                                              0);

+     if (expiration && expiration > now) {

+         DEBUG(6, ("Cached values are still valid. Skipping\n"));

+         goto skip;

+     }

+ 

+     /* Look up the group in LDAP */

+     ret = sdap_nested_group_lookup_group(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+     }

+     return;

+ 

+ skip:

+     state->member_index++;

+     talloc_zfree(state->member_dn);

+     ret = sdap_nested_group_process_step(req);

+     if (ret == EOK) {

+         tevent_req_done(req);

+     } else if (ret != EAGAIN) {

+         tevent_req_error(req, ret);

+     }

+ }

+ 

+ static errno_t sdap_nested_group_lookup_group(struct tevent_req *req)

+ {

+     errno_t ret;

+     const char **sdap_attrs;

+     char *filter;

+     struct tevent_req *subreq;

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+ 

+     ret = build_attrs_from_map(state, state->opts->group_map,

+                                SDAP_OPTS_GROUP, &sdap_attrs);

+     if (ret != EOK) {

+         return ret;

+     }

+ 

+     filter = talloc_asprintf(

+             sdap_attrs, "(objectclass=%s)",

+             state->opts->group_map[SDAP_OC_GROUP].name);

+     if (!filter) {

+         talloc_free(sdap_attrs);

+         return ENOMEM;

+     }

+ 

+     subreq = sdap_get_generic_send(state, state->ev, state->opts,

+                                    state->sh, state->member_dn,

+                                    LDAP_SCOPE_BASE,

+                                    filter, sdap_attrs,

+                                    state->opts->group_map,

+                                    SDAP_OPTS_GROUP);

+     if (!subreq) {

+         talloc_free(sdap_attrs);

+         return EIO;

+     }

+     talloc_steal(subreq, sdap_attrs);

+ 

+     tevent_req_set_callback(subreq, sdap_nested_group_process_group, req);

+     return EOK;

+ }

+ 

+ static void sdap_nested_group_process_user(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+     TALLOC_CTX *tmp_ctx;

+     size_t count;

+     struct sysdb_attrs **replies;

+     int hret;

+     hash_key_t key;

+     hash_value_t value;

+ 

+     tmp_ctx = talloc_new(NULL);

+     if (!tmp_ctx) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies);

+     talloc_zfree(subreq);

+     if (ret != EOK && ret != ENOENT) {

+         tevent_req_error(req, ret);

+         goto done;

+     } else if (ret == ENOENT || count == 0) {

+         /* Nothing to do if the user doesn't exist */

+         goto skip;

+     }

+ 

+     if (count != 1) {

+         /* There should only ever be one reply for a

+          * BASE search. If otherwise, it's a serious

+          * error.

+          */

+         DEBUG(1,("Received multiple replies for a BASE search!\n"));

+         tevent_req_error(req, EIO);

+         goto done;

+     }

+ 

+     /* Save the user attributes to the user hash so we can store

+      * them all at once later.

+      */

+ 

+     key.type = HASH_KEY_STRING;

+     key.str = state->member_dn;

+ 

+     value.type = HASH_VALUE_PTR;

+     value.ptr = replies[0];

+ 

+     hret = hash_enter(state->users, &key, &value);

+     if (hret != HASH_SUCCESS) {

+         tevent_req_error(req, EIO);

+         goto done;

+     }

+     talloc_steal(state->users, replies[0]);

+ 

+ skip:

+     state->member_index++;

+     talloc_zfree(state->member_dn);

+     ret = sdap_nested_group_process_step(req);

+     if (ret == EOK) {

+         /* EOK means it's complete */

+         tevent_req_done(req);

+     } else if (ret != EAGAIN) {

+         tevent_req_error(req, ret);

+     }

+ 

+     /* EAGAIN means that we should re-enter

+      * the mainloop

+      */

+ 

+ done:

+     talloc_free(tmp_ctx);

+ }

+ 

+ static void sdap_group_internal_nesting_done(struct tevent_req *subreq);

+ static void sdap_nested_group_process_group(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+     TALLOC_CTX *tmp_ctx;

+     size_t count;

+     struct sysdb_attrs **replies;

+ 

+     tmp_ctx = talloc_new(NULL);

+     if (!tmp_ctx) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies);

+     talloc_zfree(subreq);

+     if (ret != EOK && ret != ENOENT) {

+         tevent_req_error(req, ret);

+         goto done;

+     } else if (ret == ENOENT || count == 0) {

+         /* Nothing to do if the group doesn't exist */

+         goto skip;

+     }

+ 

+     if (count != 1) {

+         /* There should only ever be one reply for a

+          * BASE search. If otherwise, it's a serious

+          * error.

+          */

+         DEBUG(1,("Received multiple replies for a BASE search!\n"));

+         tevent_req_error(req, EIO);

+         goto done;

+     }

+ 

+     /* Recurse down into the member group */

+     subreq = sdap_nested_group_process_send(state, state->ev, state->domain,

+                                             state->sysdb, replies[0],

+                                             state->users, state->groups,

+                                             state->opts, state->sh,

+                                             state->nesting_level + 1);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         goto done;

+     }

+     tevent_req_set_callback(subreq, sdap_group_internal_nesting_done, req);

+ 

+     talloc_free(tmp_ctx);

+     return;

+ 

+ skip:

+     state->member_index++;

+     talloc_zfree(state->member_dn);

+     ret = sdap_nested_group_process_step(req);

+     if (ret == EOK) {

+         /* EOK means it's complete */

+         tevent_req_done(req);

+     } else if (ret != EAGAIN) {

+         tevent_req_error(req, ret);

+     }

+ 

+     /* EAGAIN means that we should re-enter

+      * the mainloop

+      */

+ 

+ done:

+     talloc_free(tmp_ctx);

+ }

+ 

+ static void sdap_group_internal_nesting_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+ 

+     ret = sdap_nested_group_process_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+     }

+ 

+     state->member_index++;

+     talloc_zfree(state->member_dn);

+     ret = sdap_nested_group_process_step(req);

+     if (ret == EOK) {

+         /* EOK means it's complete */

+         tevent_req_done(req);

+     } else if (ret != EAGAIN) {

+         tevent_req_error(req, ret);

+     }

+ 

+     /* EAGAIN means that we should re-enter

+      * the mainloop

+      */

+ }

+ 

+ static void sdap_nested_group_process_ldap_user(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_nested_group_ctx *state =

+             tevent_req_data(req, struct sdap_nested_group_ctx);

+     TALLOC_CTX *tmp_ctx;

+     size_t count;

+     struct sysdb_attrs **replies;

+     int hret;

+     hash_key_t key;

+     hash_value_t value;

+ 

+     tmp_ctx = talloc_new(NULL);

+     if (!tmp_ctx) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     ret = sdap_get_generic_recv(subreq, tmp_ctx, &count, &replies);

+     talloc_zfree(subreq);

+     if (ret != EOK && ret != ENOENT) {

+         tevent_req_error(req, ret);

+         goto done;

+     } else if (ret == ENOENT || count == 0) {

+         /* No user found. Assume it's a group */

+         ret = sdap_nested_group_lookup_group(req);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+         }

+         goto done;

+     }

+ 

+     if (count != 1) {

+         /* There should only ever be one reply for a

+          * BASE search. If otherwise, it's a serious

+          * error.

+          */

+         DEBUG(1,("Received multiple replies for a BASE search!\n"));

+         tevent_req_error(req, EIO);

+         goto done;

+     }

+ 

+     /* Save the user attributes to the user hash so we can store

+      * them all at once later.

+      */

+     key.type = HASH_KEY_STRING;

+     key.str = state->member_dn;

+ 

+     value.type = HASH_VALUE_PTR;

+     value.ptr = replies[0];

+ 

+     hret = hash_enter(state->users, &key, &value);

+     if (hret != HASH_SUCCESS) {

+         tevent_req_error(req, EIO);

+         goto done;

+     }

+     talloc_steal(state->users, replies[0]);

+ 

+     /* Move on to the next member */

+     state->member_index++;

+     talloc_zfree(state->member_dn);

+     ret = sdap_nested_group_process_step(req);

+     if (ret == EOK) {

+         /* EOK means it's complete */

+         tevent_req_done(req);

+     } else if (ret != EAGAIN) {

+         tevent_req_error(req, ret);

+     }

+ 

+     /* EAGAIN means that we should re-enter

+      * the mainloop

+      */

+ 

+ done:

+     talloc_free(tmp_ctx);

+ }

+ 

+ static errno_t sdap_nested_group_process_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq);

+ static struct tevent_req *sdap_initgr_rfc2307bis_send(

+         TALLOC_CTX *memctx,

+         struct tevent_context *ev,

+         struct sdap_options *opts,

+         struct sysdb_ctx *sysdb,

+         struct sss_domain_info *dom,

+         struct sdap_handle *sh,

+         const char *base_dn,

+         const char *name,

+         const char *orig_dn)

+ {

+     errno_t ret;

+     struct tevent_req *req;

+     struct tevent_req *subreq;

+     struct sdap_initgr_rfc2307_state *state;

+     const char *filter;

+     const char **attrs;

+ 

+     req = tevent_req_create(memctx, &state, struct sdap_initgr_rfc2307_state);

+     if (!req) return NULL;

+ 

+     state->ev = ev;

+     state->opts = opts;

+     state->sysdb = sysdb;

+     state->dom = dom;

+     state->sh = sh;

+     state->op = NULL;

+     state->name = name;

+ 

+     ret = build_attrs_from_map(state, opts->group_map,

+                                SDAP_OPTS_GROUP, &attrs);

+     if (ret != EOK) {

+         talloc_free(req);

+         return NULL;

+     }

+ 

+     filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",

+                              opts->group_map[SDAP_AT_GROUP_MEMBER].name,

+                              orig_dn, opts->group_map[SDAP_OC_GROUP].name);

+     if (!filter) {

          talloc_zfree(req);

          return NULL;

      }

-     for (i = 0; i < state->count; i++) {

-         state->group_dns[i] = talloc_strdup(state->group_dns,

-                                             (char *)el->values[i].data);

-         if (!state->group_dns[i]) {

-             talloc_zfree(req);

-             return NULL;

-         }

-     }

-     state->group_dns[i] = NULL; /* terminate */

-     state->cur = 0;

  

-     subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,

-                                    state->group_dns[state->cur],

-                                    LDAP_SCOPE_BASE,

-                                    state->filter, state->grp_attrs,

+     DEBUG(6, ("Looking up parent groups for user [%s]\n", orig_dn));

+     subreq = sdap_get_generic_send(state, state->ev, state->opts,

+                                    state->sh, base_dn, LDAP_SCOPE_SUBTREE,

+                                    filter, attrs,

                                     state->opts->group_map, SDAP_OPTS_GROUP);

      if (!subreq) {

          talloc_zfree(req);

          return NULL;

      }

-     tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);

+     tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_process, req);

  

      return req;

+ 

  }

  

- static void sdap_initgr_nested_search(struct tevent_req *subreq)

+ errno_t save_rfc2307bis_user_memberships(struct tevent_req *req);

+ struct tevent_req *rfc2307bis_nested_groups_send(

+         TALLOC_CTX *mem_ctx, struct tevent_context *ev,

+         struct sdap_options *opts, struct sysdb_ctx *sysdb,

+         struct sss_domain_info *dom, struct sdap_handle *sh,

+         struct sysdb_attrs **groups, size_t num_groups);

+ static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq);

+ static void sdap_initgr_rfc2307bis_process(struct tevent_req *subreq)

  {

      struct tevent_req *req;

-     struct sdap_initgr_nested_state *state;

-     struct sysdb_attrs **groups;

-     size_t count;

+     struct sdap_initgr_rfc2307_state *state;

      int ret;

  

      req = tevent_req_callback_data(subreq, struct tevent_req);

-     state = tevent_req_data(req, struct sdap_initgr_nested_state);

+     state = tevent_req_data(req, struct sdap_initgr_rfc2307_state);

  

-     ret = sdap_get_generic_recv(subreq, state, &count, &groups);

+     ret = sdap_get_generic_recv(subreq, state,

+                                 &state->ldap_groups_count,

+                                 &state->ldap_groups);

      talloc_zfree(subreq);

      if (ret) {

          tevent_req_error(req, ret);

          return;

      }

  

-     if (count == 1) {

-         state->groups[state->groups_cur] = groups[0];

-         state->groups_cur++;

+     if (state->ldap_groups_count == 0) {

+         /* Start a transaction to look up the groups in the sysdb

+          * and update them with LDAP data

+          */

+         ret = save_rfc2307bis_user_memberships(req);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+         }

+         return;

+     }

+ 

+     subreq = rfc2307bis_nested_groups_send(state, state->ev, state->opts,

+                                            state->sysdb, state->dom,

+                                            state->sh, state->ldap_groups,

+                                            state->ldap_groups_count);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq, sdap_initgr_rfc2307bis_done, req);

+ }

+ 

+ static void sdap_initgr_rfc2307bis_get_sysdb_groups(struct tevent_req *subreq);

+ errno_t save_rfc2307bis_user_memberships(struct tevent_req *req)

+ {

+     struct tevent_req *subreq;

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+ 

+     DEBUG(7, ("Save parent groups to sysdb\n"));

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     if (!subreq) {

+         return EIO;

+     }

+     /* Save this user and their memberships */

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307bis_get_sysdb_groups,

+                             req);

+     return EOK;

+ }

+ 

+ static errno_t rfc2307bis_sysdb_member_lookup(TALLOC_CTX *mem_ctx,

+                                               struct tevent_context *ev,

+                                               struct sysdb_ctx *sysdb,

+                                               struct sysdb_handle *handle,

+                                               struct sss_domain_info *dom,

+                                               enum sysdb_member_type type,

+                                               const char *domainname,

+                                               const char *name,

+                                               tevent_req_fn fn,

+                                               struct tevent_req *req);

+ static void sdap_initgr_rfc2307bis_update_sysdb_groups(

+         struct tevent_req *subreq);

+ static void sdap_initgr_rfc2307bis_get_sysdb_groups(struct tevent_req *subreq)

+ {

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+     int ret;

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     talloc_zfree(subreq);

+     if (ret) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     ret = rfc2307bis_sysdb_member_lookup(

+             state, state->ev, state->sysdb, state->handle, state->dom,

+             SYSDB_MEMBER_USER, state->dom->name, state->name,

+             sdap_initgr_rfc2307bis_update_sysdb_groups, req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+     }

+ }

+ static errno_t rfc2307bis_sysdb_member_lookup(TALLOC_CTX *mem_ctx,

+                                               struct tevent_context *ev,

+                                               struct sysdb_ctx *sysdb,

+                                               struct sysdb_handle *handle,

+                                               struct sss_domain_info *dom,

+                                               enum sysdb_member_type type,

+                                               const char *domainname,

+                                               const char *name,

+                                               tevent_req_fn fn,

+                                               struct tevent_req *req)

+ {

+     errno_t ret;

+     TALLOC_CTX *tmp_ctx;

+     char *member_dn;

+     char *filter;

+     const char **attrs;

+     struct tevent_req *subreq;

+ 

+     tmp_ctx = talloc_new(mem_ctx);

+     if (!tmp_ctx) {

+         return ENOMEM;

+     }

+ 

+     attrs = talloc_array(tmp_ctx, const char *, 2);

+     if (!attrs) {

+         ret = ENOMEM;

+         goto error;

+     }

+     attrs[0] = SYSDB_NAME;

+     attrs[1] = NULL;

+ 

+     if (type == SYSDB_MEMBER_USER) {

+         member_dn = sysdb_user_strdn(tmp_ctx, domainname, name);

+     } else if (type == SYSDB_MEMBER_GROUP) {

+         member_dn = sysdb_group_strdn(tmp_ctx, domainname, name);

      } else {

-         DEBUG(2, ("Search for group %s, returned %d results. Skipping\n",

-                   state->group_dns[state->cur], count));

+         ret = EINVAL;

+         goto error;

      }

  

-     state->cur++;

-     if (state->cur < state->count) {

-         subreq = sdap_get_generic_send(state, state->ev,

-                                        state->opts, state->sh,

-                                        state->group_dns[state->cur],

-                                        LDAP_SCOPE_BASE,

-                                        state->filter, state->grp_attrs,

-                                        state->opts->group_map,

-                                        SDAP_OPTS_GROUP);

-         if (!subreq) {

+     if (!member_dn) {

+         ret = ENOMEM;

+         goto error;

+     }

+ 

+     filter = talloc_asprintf(tmp_ctx, "(member=%s)", member_dn);

+     if (!filter) {

+         ret = ENOMEM;

+         goto error;

+     }

+     talloc_free(member_dn);

+ 

+     /* Search for all groups for which this user is a direct member */

+     subreq = sysdb_search_groups_send(mem_ctx, ev, sysdb,

+                                       handle, dom,

+                                       filter, attrs);

+     if (!subreq) {

+         ret = EIO;

+         goto error;

+     }

+     talloc_steal(subreq, tmp_ctx);

+ 

+     tevent_req_set_callback(subreq, fn, req);

+     return EOK;

+ 

+ error:

+     talloc_free(tmp_ctx);

+     return ret;

+ }

+ 

+ static void sdap_initgr_rfc2307bis_update_sysdb_groups_done(

+         struct tevent_req *subreq);

+ static void sdap_initgr_rfc2307bis_update_sysdb_groups(

+         struct tevent_req *subreq)

+ {

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

+     int ret, i;

+     size_t reply_count;

+     struct ldb_message **replies;

+     char **sysdb_grouplist;

+     const char *tmp_str;

+ 

+     ret = sysdb_search_groups_recv(subreq, state, &reply_count, &replies);

+     talloc_zfree(subreq);

+     if (ret != EOK && ret != ENOENT) {

+         tevent_req_error(req, ret);

+         return;

+     } else if (ret == ENOENT) {

+         reply_count = 0;

+     }

+ 

+     if (reply_count == 0) {

+         DEBUG(6, ("User [%s] is not a direct member of any groups\n",

+                   state->name));

+         sysdb_grouplist = NULL;

+     } else {

+         sysdb_grouplist = talloc_array(state, char *, reply_count+1);

+         if (!sysdb_grouplist) {

              tevent_req_error(req, ENOMEM);

              return;

          }

-         tevent_req_set_callback(subreq, sdap_initgr_nested_search, req);

-     } else {

-         sdap_initgr_nested_store(req);

+ 

+         for (i = 0; i < reply_count; i++) {

+             tmp_str = ldb_msg_find_attr_as_string(replies[i],

+                                                   SYSDB_NAME,

+                                                   NULL);

+             if (!tmp_str) {

+                 /* This should never happen, but if it

+                  * does, just skip it.

+                  */

+                 continue;

+             }

+ 

+             sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);

+             if (!sysdb_grouplist[i]) {

+                 talloc_free(sysdb_grouplist);

+                 tevent_req_error(req, ENOMEM);

+                 return;

+             }

+         }

+         sysdb_grouplist[reply_count] = NULL;

+     }

+ 

+     if (state->ldap_groups_count == 0) {

+         state->ldap_grouplist = NULL;

+     }

+     else {

+         ret = sysdb_attrs_to_list(state,

+                                   state->ldap_groups, state->ldap_groups_count,

+                                   SYSDB_NAME,

+                                   &state->ldap_grouplist);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+             return;

+         }

+     }

+ 

+     /* Find the differences between the sysdb and ldap lists

+      * Groups in ldap only must be added to the sysdb;

+      * groups in the sysdb only must be removed.

+      */

+     ret = diff_string_lists(state,

+                             state->ldap_grouplist, sysdb_grouplist,

+                             &state->add_groups, &state->del_groups, NULL);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     subreq = sysdb_update_members_send(state, state->ev, state->handle,

+                                        state->dom, state->name,

+                                        SYSDB_MEMBER_USER,

+                                        state->add_groups, state->del_groups);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

      }

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307bis_update_sysdb_groups_done,

+                             req);

  }

  

- static void sdap_initgr_nested_store(struct tevent_req *req)

+ static void sdap_initgr_rfc2307bis_transaction_done(struct tevent_req *subreq);

+ static void sdap_initgr_rfc2307bis_update_sysdb_groups_done(

+         struct tevent_req *subreq)

  {

-     struct tevent_req *subreq;

-     struct sdap_initgr_nested_state *state;

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_initgr_rfc2307_state *state =

+             tevent_req_data(req, struct sdap_initgr_rfc2307_state);

  

-     state = tevent_req_data(req, struct sdap_initgr_nested_state);

+     ret = sysdb_update_members_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

  

-     subreq = sdap_save_groups_send(state, state->ev, state->dom,

-                                    state->sysdb, state->opts,

-                                    state->groups, state->groups_cur);

+     /* Commit the transaction */

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

      if (!subreq) {

-         tevent_req_error(req, ENOMEM);

+         tevent_req_error(req, EIO);

          return;

      }

-     tevent_req_set_callback(subreq, sdap_initgr_nested_done, req);

+ 

+     tevent_req_set_callback(subreq,

+                             sdap_initgr_rfc2307bis_transaction_done,

+                             req);

  }

  

- static void sdap_initgr_nested_done(struct tevent_req *subreq)

+ static void sdap_initgr_rfc2307bis_transaction_done(struct tevent_req *subreq)

  {

-     struct tevent_req *req;

-     int ret;

- 

-     req = tevent_req_callback_data(subreq, struct tevent_req);

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

  

-     ret = sdap_save_groups_recv(subreq, NULL, NULL);

+     ret = sysdb_transaction_commit_recv(subreq);

      talloc_zfree(subreq);

-     if (ret) {

+     if (ret != EOK) {

          tevent_req_error(req, ret);

          return;

      }

  

+     /* Processing completed. Return control to sdap_get_initgr_done() */

      tevent_req_done(req);

  }

  

- static int sdap_initgr_nested_recv(struct tevent_req *req)

+ static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req);

+ static void sdap_initgr_rfc2307bis_done(struct tevent_req *subreq)

  {

-     TEVENT_REQ_RETURN_ON_ERROR(req);

- 

-     return EOK;

- }

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

  

+     ret = rfc2307bis_nested_groups_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

+     }

  

- /* ==Initgr-call-(groups-a-user-is-member-of)============================= */

+     /* save the user memberships */

+     ret = save_rfc2307bis_user_memberships(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+     }

+     return;

+ }

  

- struct sdap_get_initgr_state {

+ struct sdap_rfc2307bis_nested_ctx {

      struct tevent_context *ev;

-     struct sysdb_ctx *sysdb;

      struct sdap_options *opts;

+     struct sysdb_ctx *sysdb;

      struct sss_domain_info *dom;

      struct sdap_handle *sh;

-     const char *name;

-     const char **grp_attrs;

+     struct sysdb_attrs **groups;

+     size_t num_groups;

  

-     struct sysdb_attrs *orig_user;

+     size_t group_iter;

+     struct sysdb_attrs **ldap_groups;

+     size_t ldap_groups_count;

  

      struct sysdb_handle *handle;

  };

  

- static void sdap_get_initgr_user(struct tevent_req *subreq);

- static void sdap_get_initgr_store(struct tevent_req *subreq);

- static void sdap_get_initgr_commit(struct tevent_req *subreq);

- static void sdap_get_initgr_process(struct tevent_req *subreq);

- static void sdap_get_initgr_done(struct tevent_req *subreq);

+ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req);

+ struct tevent_req *rfc2307bis_nested_groups_send(

+         TALLOC_CTX *mem_ctx, struct tevent_context *ev,

+         struct sdap_options *opts, struct sysdb_ctx *sysdb,

+         struct sss_domain_info *dom, struct sdap_handle *sh,

+         struct sysdb_attrs **groups, size_t num_groups)

+ {

+     errno_t ret;

+     struct tevent_req *req;

+     struct sdap_rfc2307bis_nested_ctx *state;

+ 

+     req = tevent_req_create(mem_ctx, &state,

+                             struct sdap_rfc2307bis_nested_ctx);

+     if (!req) return NULL;

+ 

+     if (num_groups == 0) {

+         /* No parent groups to process */

+         tevent_req_done(req);

+         tevent_req_post(req, ev);

+         return req;

+     }

+ 

+     state->ev = ev;

+     state->opts = opts;

+     state->sysdb = sysdb;

+     state->dom = dom;

+     state->sh = sh;

+     state->groups = groups;

+     state->num_groups = num_groups;

+     state->group_iter = 0;

+ 

+     ret = rfc2307bis_nested_groups_step(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         tevent_req_post(req, ev);

+     }

+     return req;

+ }

+ 

+ static void rfc2307bis_nested_groups_incomplete_groups_save(

+         struct tevent_req *subreq);

+ static errno_t rfc2307bis_nested_groups_step(struct tevent_req *req)

+ {

+     errno_t ret;

+     struct tevent_req *subreq;

+     const char *name;

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

+ 

+     if (debug_level >= 6) {

+         ret = sysdb_attrs_get_string(state->groups[state->group_iter],

+                                      SYSDB_NAME, &name);

+         if (ret != EOK) {

+             return ret;

+         }

+ 

+         DEBUG(6, ("Processing group [%s]\n", name));

+     }

+ 

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     if (!subreq) {

+         return EIO;

+     }

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_nested_groups_incomplete_groups_save,

+                             req);

+     return EOK;

+ }

+ 

+ static void rfc2307bis_nested_groups_incomplete_groups_done(

+         struct tevent_req *subreq);

+ static void rfc2307bis_nested_groups_incomplete_groups_save(

+         struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

+     const char *name;

+     struct sysdb_attrs **grouplist;

+     char **groupnamelist;

+     TALLOC_CTX *tmp_ctx = NULL;

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     if (ret != EOK) goto error;

+ 

+     tmp_ctx = talloc_new(state);

+     if (!tmp_ctx) {

+         ret = ENOMEM;

+         goto error;

+     }

+ 

+     /* First, save the group we're processing to the sysdb

+      * sdap_add_incomplete_groups_send will add them if needed

+      */

+     ret = sysdb_attrs_get_string(state->groups[state->group_iter],

+                                  SYSDB_NAME, &name);

+ 

+     /* sdap_add_incomplete_groups_send expects a list of groups */

+     grouplist = talloc_array(tmp_ctx, struct sysdb_attrs *, 1);

+     if (!grouplist) {

+         ret = ENOMEM;

+         goto error;

+     }

+     grouplist[0] = state->groups[state->group_iter];

+ 

+     groupnamelist = talloc_array(tmp_ctx, char *, 2);

+     if (!groupnamelist) {

+         ret = ENOMEM;

+         goto error;

+     }

+     groupnamelist[0] = talloc_strdup(groupnamelist, name);

+     if (!groupnamelist[0]) {

+         ret = ENOMEM;

+         goto error;

+     }

+     groupnamelist[1] = NULL;

+ 

+     DEBUG(6, ("Saving incomplete group [%s] to the sysdb\n",

+               groupnamelist[0]));

+     subreq = sdap_add_incomplete_groups_send(state, state->ev, state->sysdb,

+                                              state->handle, state->dom,

+                                              groupnamelist,

+                                              grouplist,

+                                              1);

+     if (!subreq) {

+         ret = EIO;

+         goto error;

+     }

+ 

+     talloc_steal(subreq, tmp_ctx);

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_nested_groups_incomplete_groups_done,

+                             req);

+     return;

+ 

+ error:

+     talloc_free(tmp_ctx);

+     tevent_req_error(req, ret);

+ }

+ 

+ static void rfc2307bis_nested_groups_get_parents(struct tevent_req *subreq);

+ static void rfc2307bis_nested_groups_incomplete_groups_done(

+         struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

+ 

+     ret = sdap_add_incomplete_groups_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(7, ("sdap_add_incomplete_groups failed [%d][%s]\n",

+                   ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_nested_groups_get_parents,

+                             req);

+ }

  

- struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx,

-                                         struct tevent_context *ev,

-                                         struct sss_domain_info *dom,

-                                         struct sysdb_ctx *sysdb,

-                                         struct sdap_options *opts,

-                                         struct sdap_handle *sh,

-                                         const char *name,

-                                         const char **grp_attrs)

+ static void rfc2307bis_nested_groups_process(struct tevent_req *subreq);

+ static void rfc2307bis_nested_groups_get_parents(struct tevent_req *subreq)

  {

-     struct tevent_req *req, *subreq;

-     struct sdap_get_initgr_state *state;

-     const char *base_dn;

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

      char *filter;

+     const char *orig_dn;

      const char **attrs;

-     int ret;

+     TALLOC_CTX *tmp_ctx;

  

-     DEBUG(9, ("Retrieving info for initgroups call\n"));

+     ret = sysdb_transaction_commit_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(7, ("sysdb transaction failed [%d][%s]\n",

+                   ret, strerror(ret)));

+         tevent_req_error(req, ret);

+         return;

+     }

  

-     req = tevent_req_create(memctx, &state, struct sdap_get_initgr_state);

-     if (!req) return NULL;

+     /* Get any parent groups for this group */

  

-     state->ev = ev;

-     state->opts = opts;

-     state->sysdb = sysdb;

-     state->dom = dom;

-     state->sh = sh;

-     state->name = name;

-     state->grp_attrs = grp_attrs;

-     state->orig_user = NULL;

+     tmp_ctx = talloc_new(state);

+     if (!tmp_ctx) {

+         ret = ENOMEM;

+         goto error;

+     }

  

-     filter = talloc_asprintf(state, "(&(%s=%s)(objectclass=%s))",

-                         state->opts->user_map[SDAP_AT_USER_NAME].name,

-                         state->name,

-                         state->opts->user_map[SDAP_OC_USER].name);

-     if (!filter) {

-         talloc_zfree(req);

-         return NULL;

+     ret = sysdb_attrs_get_string(state->groups[state->group_iter],

+                                  SYSDB_ORIG_DN,

+                                  &orig_dn);

+     if (ret != EOK) {

+         goto error;

      }

  

-     base_dn = dp_opt_get_string(state->opts->basic,

-                                 SDAP_USER_SEARCH_BASE);

-     if (!base_dn) {

-         talloc_zfree(req);

-         return NULL;

+     ret = build_attrs_from_map(tmp_ctx, state->opts->group_map,

+                                SDAP_OPTS_GROUP, &attrs);

+     if (ret != EOK) {

+         goto error;

      }

  

-     ret = build_attrs_from_map(state, state->opts->user_map,

-                                SDAP_OPTS_USER, &attrs);

-     if (ret) {

-         talloc_zfree(req);

-         return NULL;

+     filter = talloc_asprintf(

+             tmp_ctx, "(&(%s=%s)(objectclass=%s))",

+             state->opts->group_map[SDAP_AT_GROUP_MEMBER].name,

+             orig_dn,

+             state->opts->group_map[SDAP_OC_GROUP].name);

+     if (!filter) {

+         ret = ENOMEM;

+         goto error;

      }

  

-     subreq = sdap_get_generic_send(state, state->ev,

-                                    state->opts, state->sh,

-                                    base_dn, LDAP_SCOPE_SUBTREE,

+     DEBUG(6, ("Looking up parent groups for group [%s]\n", orig_dn));

+     subreq = sdap_get_generic_send(state, state->ev, state->opts,

+                                    state->sh,

+                                    dp_opt_get_string(state->opts->basic,

+                                                      SDAP_GROUP_SEARCH_BASE),

+                                    LDAP_SCOPE_SUBTREE,

                                     filter, attrs,

-                                    state->opts->user_map, SDAP_OPTS_USER);

+                                    state->opts->group_map, SDAP_OPTS_GROUP);

      if (!subreq) {

-         talloc_zfree(req);

-         return NULL;

+         ret = EIO;

+         goto error;

      }

-     tevent_req_set_callback(subreq, sdap_get_initgr_user, req);

+     talloc_steal(subreq, tmp_ctx);

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_nested_groups_process,

+                             req);

  

-     return req;

+     return;

+ 

+ error:

+     talloc_free(tmp_ctx);

+     tevent_req_error(req, ret);

  }

  

- static void sdap_get_initgr_user(struct tevent_req *subreq)

+ static errno_t rfc2307bis_nested_groups_update_sysdb(struct tevent_req *req);

+ static void rfc2307bis_nested_groups_done(struct tevent_req *subreq);

+ static void rfc2307bis_nested_groups_process(struct tevent_req *subreq)

  {

-     struct tevent_req *req = tevent_req_callback_data(subreq,

-                                                       struct tevent_req);

-     struct sdap_get_initgr_state *state = tevent_req_data(req,

-                                                struct sdap_get_initgr_state);

-     struct sysdb_attrs **usr_attrs;

-     size_t count;

-     int ret;

- 

-     DEBUG(9, ("Receiving info for the user\n"));

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

  

-     ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);

+     ret = sdap_get_generic_recv(subreq, state,

+                                 &state->ldap_groups_count,

+                                 &state->ldap_groups);

      talloc_zfree(subreq);

      if (ret) {

          tevent_req_error(req, ret);

          return;

      }

  

-     if (count != 1) {

-         DEBUG(2, ("Expected one user entry and got %d\n", count));

-         tevent_req_error(req, ENOENT);

+     if (state->ldap_groups_count == 0) {

+         /* No groups for this user in LDAP

+          * We need to ensure that there are no groups

+          * in the sysdb either.

+          */

+ 

+         ret = rfc2307bis_nested_groups_update_sysdb(req);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+         }

          return;

      }

  

-     state->orig_user = usr_attrs[0];

- 

-     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     /* Otherwise, recurse into the groups */

+     subreq = rfc2307bis_nested_groups_send(

+             state, state->ev, state->opts, state->sysdb,

+             state->dom, state->sh,

+             state->ldap_groups, state->ldap_groups_count);

      if (!subreq) {

-         tevent_req_error(req, ENOMEM);

+         tevent_req_error(req, EIO);

          return;

      }

-     tevent_req_set_callback(subreq, sdap_get_initgr_store, req);

+     tevent_req_set_callback(subreq, rfc2307bis_nested_groups_done, req);

  }

  

- static void sdap_get_initgr_store(struct tevent_req *subreq)

+ static errno_t rfc2307bis_nested_groups_recv(struct tevent_req *req)

  {

-     struct tevent_req *req = tevent_req_callback_data(subreq,

-                                                       struct tevent_req);

-     struct sdap_get_initgr_state *state = tevent_req_data(req,

-                                                struct sdap_get_initgr_state);

-     int ret;

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+     return EOK;

+ }

  

-     DEBUG(9, ("Storing the user\n"));

+ static void rfc2307bis_nested_groups_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

  

-     ret = sysdb_transaction_recv(subreq, state, &state->handle);

+     ret = rfc2307bis_nested_groups_recv(subreq);

      talloc_zfree(subreq);

-     if (ret) {

+     if (ret != EOK) {

+         DEBUG(6, ("rfc2307bis_nested failed [%d][%s]\n",

+                   ret, strerror(ret)));

          tevent_req_error(req, ret);

          return;

      }

  

-     subreq = sdap_save_user_send(state, state->ev, state->handle,

-                                  state->opts, state->dom,

-                                  state->orig_user, true);

-     if (!subreq) {

-         tevent_req_error(req, ENOMEM);

-         return;

+     /* All of the parent groups have been added

+      * Now add the memberships

+      */

+ 

+     ret = rfc2307bis_nested_groups_update_sysdb(req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

      }

-     tevent_req_set_callback(subreq, sdap_get_initgr_commit, req);

+     return;

  }

  

- static void sdap_get_initgr_commit(struct tevent_req *subreq)

+ static void rfc2307bis_get_sysdb_groups(struct tevent_req *subreq);

+ static errno_t rfc2307bis_nested_groups_update_sysdb(struct tevent_req *req)

  {

-     struct tevent_req *req = tevent_req_callback_data(subreq,

-                                                       struct tevent_req);

-     struct sdap_get_initgr_state *state = tevent_req_data(req,

-                                                struct sdap_get_initgr_state);

-     int ret;

+     struct tevent_req *subreq;

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

  

-     DEBUG(9, ("Commit change\n"));

+     /* Start a transaction to look up the groups in the sysdb

+      * and update them with LDAP data

+      */

  

-     ret = sdap_save_user_recv(subreq, NULL, NULL);

+     subreq = sysdb_transaction_send(state, state->ev, state->sysdb);

+     if (!subreq) {

+         return EIO;

+     }

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_get_sysdb_groups,

+                             req);

+     return EOK;

+ }

+ 

+ static void rfc2307bis_update_sysdb_groups(struct tevent_req *subreq);

+ static void rfc2307bis_get_sysdb_groups(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     const char *name;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

+ 

+     ret = sysdb_transaction_recv(subreq, state, &state->handle);

      talloc_zfree(subreq);

-     if (ret) {

+     if (ret != EOK) {

          tevent_req_error(req, ret);

          return;

      }

  

-     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

-     if (!subreq) {

-         tevent_req_error(req, ENOMEM);

-         return;

+     ret = sysdb_attrs_get_string(state->groups[state->group_iter],

+                                  SYSDB_NAME, &name);

+ 

+     ret = rfc2307bis_sysdb_member_lookup(

+             state, state->ev, state->sysdb, state->handle, state->dom,

+             SYSDB_MEMBER_GROUP, state->dom->name, name,

+             rfc2307bis_update_sysdb_groups, req);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

      }

-     tevent_req_set_callback(subreq, sdap_get_initgr_process, req);

  }

  

- static void sdap_get_initgr_process(struct tevent_req *subreq)

+ static void rfc2307bis_update_sysdb_groups_process(struct tevent_req *req);

+ static void rfc2307bis_update_sysdb_groups(struct tevent_req *subreq)

  {

-     struct tevent_req *req = tevent_req_callback_data(subreq,

-                                                       struct tevent_req);

-     struct sdap_get_initgr_state *state = tevent_req_data(req,

-                                                struct sdap_get_initgr_state);

-     int ret;

- 

-     DEBUG(9, ("Process user's groups\n"));

- 

-     ret = sysdb_transaction_commit_recv(subreq);

+     errno_t ret;

+     unsigned int i;

+     size_t reply_count;

+     struct ldb_message **replies;

+     const char *name;

+     TALLOC_CTX *tmp_ctx;

+     const char *tmp_str;

+     char **sysdb_grouplist;

+     char **ldap_grouplist;

+     char **add_groups;

+     char **del_groups;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

+ 

+     ret = sysdb_search_groups_recv(subreq, state, &reply_count, &replies);

      talloc_zfree(subreq);

-     if (ret) {

+     if (ret != EOK && ret != ENOENT) {

          tevent_req_error(req, ret);

          return;

+     } else if (ret == ENOENT) {

+         reply_count = 0;

      }

  

-     switch (state->opts->schema_type) {

-     case SDAP_SCHEMA_RFC2307:

-         subreq = sdap_initgr_rfc2307_send(state, state->ev, state->opts,

-                                     state->sysdb, state->dom, state->sh,

-                                     dp_opt_get_string(state->opts->basic,

-                                                   SDAP_GROUP_SEARCH_BASE),

-                                     state->name, state->grp_attrs);

-         if (!subreq) {

-             tevent_req_error(req, ENOMEM);

-             return;

-         }

-         tevent_req_set_callback(subreq, sdap_get_initgr_done, req);

-         break;

+     tmp_ctx = talloc_new(state);

+     if (!tmp_ctx) {

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

  

-     case SDAP_SCHEMA_RFC2307BIS:

-     case SDAP_SCHEMA_IPA_V1:

-     case SDAP_SCHEMA_AD:

-         /* TODO: AD uses a different member/memberof schema

-          *       We need an AD specific call that is able to unroll

-          *       nested groups by doing extensive recursive searches */

+     ret = sysdb_attrs_get_string(state->groups[state->group_iter],

+                                  SYSDB_NAME, &name);

+     if (ret != EOK) goto error;

  

-         subreq = sdap_initgr_nested_send(state, state->ev, state->opts,

-                                          state->sysdb, state->dom, state->sh,

-                                          state->orig_user, state->grp_attrs);

-         if (!subreq) {

+     /* Create a list of the groups in the sysdb */

+     if (reply_count == 0) {

+         DEBUG(6, ("Group [%s] is not a direct member of any groups\n",

+                   name));

+         sysdb_grouplist = NULL;

+     } else {

+         sysdb_grouplist = talloc_array(state, char *, reply_count+1);

+         if (!sysdb_grouplist) {

              tevent_req_error(req, ENOMEM);

              return;

          }

-         tevent_req_set_callback(subreq, sdap_get_initgr_done, req);

-         return;

  

-     default:

-         tevent_req_error(req, EINVAL);

-         return;

+         for (i = 0; i < reply_count; i++) {

+             tmp_str = ldb_msg_find_attr_as_string(replies[i],

+                                                   SYSDB_NAME,

+                                                   NULL);

+             if (!tmp_str) {

+                 /* This should never happen, but if it

+                  * does, just skip it.

+                  */

+                 continue;

+             }

+ 

+             sysdb_grouplist[i] = talloc_strdup(sysdb_grouplist, tmp_str);

+             if (!sysdb_grouplist[i]) {

+                 talloc_free(sysdb_grouplist);

+                 tevent_req_error(req, ENOMEM);

+                 return;

+             }

+         }

+         sysdb_grouplist[reply_count] = NULL;

      }

- }

  

- static void sdap_get_initgr_done(struct tevent_req *subreq)

- {

-     struct tevent_req *req = tevent_req_callback_data(subreq,

-                                                       struct tevent_req);

-     struct sdap_get_initgr_state *state = tevent_req_data(req,

-                                                struct sdap_get_initgr_state);

-     int ret;

+     /* Create a list of the groups in LDAP */

+     if (state->ldap_groups_count == 0) {

+         /* No groups for this user in LDAP

+          * We need to ensure that there are no groups

+          * in the sysdb either.

+          */

  

-     DEBUG(9, ("Initgroups done\n"));

+         ldap_grouplist = NULL;

+     }

+     else {

+         ret = sysdb_attrs_to_list(tmp_ctx,

+                                   state->ldap_groups,

+                                   state->ldap_groups_count,

+                                   SYSDB_NAME,

+                                   &ldap_grouplist);

+         if (ret != EOK) {

+             goto error;

+         }

+     }

  

-     switch (state->opts->schema_type) {

-     case SDAP_SCHEMA_RFC2307:

+     /* Find the differences between the sysdb and ldap lists

+      * Groups in ldap only must be added to the sysdb;

+      * groups in the sysdb only must be removed.

+      */

+     ret = diff_string_lists(tmp_ctx,

+                             ldap_grouplist, sysdb_grouplist,

+                             &add_groups, &del_groups, NULL);

+     if (ret != EOK) {

+         goto error;

+     }

  

-         ret = sdap_initgr_rfc2307_recv(subreq);

-         break;

+     /* Since all of the groups were created by nested calls,

+      * we don't need to step through sdap_add_incomplete_groups_send

+      * here like we do in sdap_initgr_rfc2307_update_sysdb_groups

+      *

+      * We can just update the memberships and move on

+      */

+     subreq = sysdb_update_members_send(state, state->ev, state->handle,

+                                        state->dom, name,

+                                        SYSDB_MEMBER_GROUP,

+                                        add_groups, del_groups);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     talloc_steal(subreq, tmp_ctx);

  

-     case SDAP_SCHEMA_RFC2307BIS:

-     case SDAP_SCHEMA_IPA_V1:

-     case SDAP_SCHEMA_AD:

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_update_sysdb_groups_process,

+                             req);

  

-         ret = sdap_initgr_nested_recv(subreq);

-         break;

+     return;

  

-     default:

+ error:

+     talloc_free(tmp_ctx);

+     tevent_req_error(req, ret);

+ }

+ static void rfc2307bis_update_sysdb_groups_done(struct tevent_req *req);

+ static void rfc2307bis_update_sysdb_groups_process(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

  

-         ret = EINVAL;

-         break;

+     ret = sysdb_update_members_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         tevent_req_error(req, ret);

+         return;

      }

  

-     talloc_zfree(subreq);

-     if (ret) {

+     /* Processing of this group is finished */

+     subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);

+     if (!subreq) {

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq,

+                             rfc2307bis_update_sysdb_groups_done,

+                             req);

+ }

+ 

+ static void rfc2307bis_update_sysdb_groups_done(struct tevent_req *subreq)

+ {

+     errno_t ret;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct sdap_rfc2307bis_nested_ctx *state =

+             tevent_req_data(req, struct sdap_rfc2307bis_nested_ctx);

+ 

+     ret = sysdb_transaction_commit_recv(subreq);

+     if (ret != EOK) {

          tevent_req_error(req, ret);

          return;

      }

  

+     /* Continue processing groups at this level */

+     state->group_iter++;

+     if (state->group_iter < state->num_groups) {

+         ret = rfc2307bis_nested_groups_step(req);

+         if (ret != EOK) {

+             tevent_req_error(req, ret);

+         }

+         return;

+     }

+ 

+     /* All done in this nesting level */

      tevent_req_done(req);

  }

  

- int sdap_get_initgr_recv(struct tevent_req *req)

+ static int sdap_initgr_rfc2307bis_recv(struct tevent_req *req)

  {

      TEVENT_REQ_RETURN_ON_ERROR(req);

- 

      return EOK;

  }

  

@@ -24,6 +24,7 @@

  #include "util/util.h"

  #include "util/sss_krb5.h"

  #include "providers/ldap/sdap_async_private.h"

+ #include "providers/ldap/ldap_common.h"

  

  #define LDAP_X_SSSD_PASSWORD_EXPIRED 0x555D

  
@@ -55,8 +56,10 @@

      struct timeval tv;

      int ver;

      int lret;

+     int optret;

      int ret = EOK;

      int msgid;

+     char *errmsg = NULL;

      bool ldap_referrals;

  

      req = tevent_req_create(memctx, &state, struct sdap_connect_state);
@@ -90,6 +93,13 @@

          goto fail;

      }

  

+     /* TODO: maybe this can be remove when we go async, currently we need it

+      * to handle EINTR during poll(). */

+     ret = ldap_set_option(state->sh->ldap, LDAP_OPT_RESTART, LDAP_OPT_ON);

+     if (ret != LDAP_OPT_SUCCESS) {

+         DEBUG(1, ("Failed to set restart option.\n"));

+     }

+ 

      /* Set Network Timeout */

      tv.tv_sec = dp_opt_get_int(opts->basic, SDAP_NETWORK_TIMEOUT);

      tv.tv_usec = 0;
@@ -120,37 +130,11 @@

          goto fail;

      }

  

- #ifdef HAVE_LDAP_CONNCB

-     struct ldap_cb_data *cb_data;

- 

-     /* add connection callback */

-     state->sh->conncb = talloc_zero(state->sh, struct ldap_conncb);

-     if (state->sh->conncb == NULL) {

-         DEBUG(1, ("talloc_zero failed.\n"));

-         ret = ENOMEM;

-         goto fail;

-     }

- 

-     cb_data = talloc_zero(state->sh->conncb, struct ldap_cb_data);

-     if (cb_data == NULL) {

-         DEBUG(1, ("talloc_zero failed.\n"));

-         ret = ENOMEM;

-         goto fail;

-     }

-     cb_data->sh = state->sh;

-     cb_data->ev = state->ev;

- 

-     state->sh->conncb->lc_add = sdap_ldap_connect_callback_add;

-     state->sh->conncb->lc_del = sdap_ldap_connect_callback_del;

-     state->sh->conncb->lc_arg = cb_data;

- 

-     lret = ldap_set_option(state->sh->ldap, LDAP_OPT_CONNECT_CB,

-                            state->sh->conncb);

-     if (lret != LDAP_OPT_SUCCESS) {

-         DEBUG(1, ("Failed to set connection callback\n"));

+     ret = setup_ldap_connection_callbacks(state->sh, state->ev);

+     if (ret != EOK) {

+         DEBUG(1, ("setup_ldap_connection_callbacks failed.\n"));

          goto fail;

      }

- #endif

  

      /* if we do not use start_tls the connection is not really connected yet

       * just fake an async procedure and leave connection to the bind call */
@@ -163,15 +147,27 @@

  

      lret = ldap_start_tls(state->sh->ldap, NULL, NULL, &msgid);

      if (lret != LDAP_SUCCESS) {

-         DEBUG(3, ("ldap_start_tls failed: [%s]\n", ldap_err2string(lret)));

+         optret = ldap_get_option(state->sh->ldap,

+                                  SDAP_DIAGNOSTIC_MESSAGE,

+                                  (void*)&errmsg);

+         if (optret == LDAP_SUCCESS) {

+             DEBUG(3, ("ldap_start_tls failed: [%s] [%s]\n",

+                       ldap_err2string(lret),

+                       errmsg));

+             sss_log(SSS_LOG_ERR, "Could not start TLS. %s", errmsg);

+             ldap_memfree(errmsg);

+         }

+         else {

+             DEBUG(3, ("ldap_start_tls failed: [%s]\n",

+                       ldap_err2string(lret)));

+             sss_log(SSS_LOG_ERR, "Could not start TLS. "

+                                  "Check for certificate issues.");

+         }

          goto fail;

      }

  

-     state->sh->connected = true;

- #ifndef HAVE_LDAP_CONNCB

-     ret = sdap_install_ldap_callbacks(state->sh, state->ev);

+     ret = sdap_set_connected(state->sh, state->ev);

      if (ret) goto fail;

- #endif

  

      /* FIXME: get timeouts from configuration, for now 5 secs. */

      ret = sdap_op_add(state, ev, state->sh, msgid,
@@ -205,7 +201,9 @@

      struct sdap_connect_state *state = tevent_req_data(req,

                                            struct sdap_connect_state);

      char *errmsg;

+     char *tlserr;

      int ret;

+     int optret;

  

      if (error) {

          tevent_req_error(req, error);
@@ -234,8 +232,24 @@

  /* FIXME: take care that ldap_install_tls might block */

      ret = ldap_install_tls(state->sh->ldap);

      if (ret != LDAP_SUCCESS) {

-         DEBUG(1, ("ldap_install_tls failed: [%d][%s]\n", ret,

-                   ldap_err2string(ret)));

+ 

+         optret = ldap_get_option(state->sh->ldap,

+                                  SDAP_DIAGNOSTIC_MESSAGE,

+                                  (void*)&tlserr);

+         if (optret == LDAP_SUCCESS) {

+             DEBUG(3, ("ldap_install_tls failed: [%s] [%s]\n",

+                       ldap_err2string(ret),

+                       tlserr));

+             sss_log(SSS_LOG_ERR, "Could not start TLS encryption. %s", tlserr);

+             ldap_memfree(tlserr);

+         }

+         else {

+             DEBUG(3, ("ldap_install_tls failed: [%s]\n",

+                       ldap_err2string(ret)));

+             sss_log(SSS_LOG_ERR, "Could not start TLS encryption. "

+                                  "Check for certificate issues.");

+         }

+ 

          state->result = ret;

          tevent_req_error(req, EIO);

          return;
@@ -343,11 +357,8 @@

      DEBUG(8, ("ldap simple bind sent, msgid = %d\n", msgid));

  

      if (!sh->connected) {

-         sh->connected = true;

- #ifndef HAVE_LDAP_CONNCB

-         ret = sdap_install_ldap_callbacks(sh, ev);

+         ret = sdap_set_connected(sh, ev);

          if (ret) goto fail;

- #endif

      }

  

      /* FIXME: get timeouts from configuration, for now 5 secs. */
@@ -522,13 +533,6 @@

      DEBUG(4, ("Executing sasl bind mech: %s, user: %s\n",

                sasl_mech, sasl_user));

  

-     /* Until ldap_sasl_interactive_bind_s() is async we may want to set

-      * LDAP_OPT_RESTART to handle EINTR during poll(). */

-     ret = ldap_set_option(state->sh->ldap, LDAP_OPT_RESTART, LDAP_OPT_ON);

-     if (ret != LDAP_OPT_SUCCESS) {

-         DEBUG(1, ("Failed to set restart option.\n"));

-     }

- 

      /* FIXME: Warning, this is a sync call!

       * No async variant exist in openldap libraries yet */

  
@@ -544,11 +548,8 @@

      }

  

      if (!sh->connected) {

-         sh->connected = true;

- #ifndef HAVE_LDAP_CONNCB

-         ret = sdap_install_ldap_callbacks(sh, ev);

+         ret = sdap_set_connected(sh, ev);

          if (ret) goto fail;

- #endif

      }

  

      tevent_req_post(req, ev);
@@ -577,7 +578,7 @@

  

          switch (in->id) {

          case SASL_CB_GETREALM:

-         case SASL_CB_AUTHNAME:

+         case SASL_CB_USER:

          case SASL_CB_PASS:

              if (in->defresult) {

                  in->result = in->defresult;
@@ -586,7 +587,7 @@

              }

              in->len = strlen(in->result);

              break;

-         case SASL_CB_USER:

+         case SASL_CB_AUTHNAME:

              if (state->sasl_user) {

                  in->result = state->sasl_user;

              } else if (in->defresult) {
@@ -642,14 +643,21 @@

                                     int    timeout,

                                     const char *keytab,

                                     const char *principal,

-                                    const char *realm)

+                                    const char *realm,

+                                    int lifetime)

  {

      struct tevent_req *req;

      struct tevent_req *subreq;

      struct sdap_kinit_state *state;

      int ret;

  

-     DEBUG(6, ("Attempting kinit (%s, %s, %s)\n", keytab, principal, realm));

+     DEBUG(6, ("Attempting kinit (%s, %s, %s, %d)\n", keytab, principal, realm,

+                                                      lifetime));

+ 

+     if (lifetime < 0 || lifetime > INT32_MAX) {

+         DEBUG(1, ("Ticket lifetime out of range.\n"));

+         return NULL;

+     }

  

      req = tevent_req_create(memctx, &state, struct sdap_kinit_state);

      if (!req) return NULL;
@@ -664,7 +672,8 @@

          }

      }

  

-     subreq = sdap_get_tgt_send(state, ev, realm, principal, keytab, timeout);

+     subreq = sdap_get_tgt_send(state, ev, realm, principal, keytab, lifetime,

+                                timeout);

      if (!subreq) {

          talloc_zfree(req);

          return NULL;
@@ -848,6 +857,7 @@

      struct tevent_context *ev;

      struct sdap_options *opts;

      struct sdap_service *service;

+     struct be_ctx *be;

  

      bool use_rootdse;

      struct sysdb_attrs *rootdse;
@@ -857,6 +867,7 @@

      struct fo_server *srv;

  };

  

+ static int sdap_cli_resolve_next(struct tevent_req *req);

  static void sdap_cli_resolve_done(struct tevent_req *subreq);

  static void sdap_cli_connect_done(struct tevent_req *subreq);

  static void sdap_cli_rootdse_step(struct tevent_req *req);
@@ -873,8 +884,9 @@

                                           struct sdap_service *service,

                                           struct sysdb_attrs **rootdse)

  {

-     struct tevent_req *req, *subreq;

      struct sdap_cli_connect_state *state;

+     struct tevent_req *req;

+     int ret;

  

      req = tevent_req_create(memctx, &state, struct sdap_cli_connect_state);

      if (!req) return NULL;
@@ -882,7 +894,9 @@

      state->ev = ev;

      state->opts = opts;

      state->service = service;

+     state->be = be;

      state->srv = NULL;

+     state->be = be;

  

      if (rootdse) {

          state->use_rootdse = true;
@@ -892,16 +906,30 @@

          state->rootdse = NULL;

      }

  

+     ret = sdap_cli_resolve_next(req);

+     if (ret) {

+         tevent_req_error(req, ret);

+         tevent_req_post(req, ev);

+     }

+     return req;

+ }

+ 

+ static int sdap_cli_resolve_next(struct tevent_req *req)

+ {

+     struct sdap_cli_connect_state *state = tevent_req_data(req,

+                                              struct sdap_cli_connect_state);

+     struct tevent_req *subreq;

+ 

      /* NOTE: this call may cause service->uri to be refreshed

       * with a new valid server. Do not use service->uri before */

-     subreq = be_resolve_server_send(state, ev, be, service->name);

+     subreq = be_resolve_server_send(state, state->ev,

+                                     state->be, state->service->name);

      if (!subreq) {

-         talloc_zfree(req);

-         return NULL;

+         return ENOMEM;

      }

-     tevent_req_set_callback(subreq, sdap_cli_resolve_done, req);

  

-     return req;

+     tevent_req_set_callback(subreq, sdap_cli_resolve_done, req);

+     return EOK;

  }

  

  static void sdap_cli_resolve_done(struct tevent_req *subreq)
@@ -911,6 +939,8 @@

      struct sdap_cli_connect_state *state = tevent_req_data(req,

                                               struct sdap_cli_connect_state);

      int ret;

+     bool use_tls = dp_opt_get_bool(state->opts->basic,

+                                    SDAP_ID_TLS);

  

      ret = be_resolve_server_recv(subreq, &state->srv);

      talloc_zfree(subreq);
@@ -921,10 +951,15 @@

          return;

      }

  

+     if (use_tls && sdap_is_secure_uri(state->service->uri)) {

+         DEBUG(8, ("[%s] is a secure channel. No need to run START_TLS\n",

+                   state->service->uri));

+         use_tls = false;

+     }

+ 

      subreq = sdap_connect_send(state, state->ev, state->opts,

                                 state->service->uri,

-                                dp_opt_get_bool(state->opts->basic,

-                                                             SDAP_ID_TLS));

+                                use_tls);

      if (!subreq) {

          tevent_req_error(req, ENOMEM);

          return;
@@ -944,6 +979,15 @@

      ret = sdap_connect_recv(subreq, state, &state->sh);

      talloc_zfree(subreq);

      if (ret) {

+         if (ret == ETIMEDOUT) { /* retry another server */

+             fo_set_port_status(state->srv, PORT_NOT_WORKING);

+             ret = sdap_cli_resolve_next(req);

+             if (ret != EOK) {

+                 tevent_req_error(req, ret);

+             }

+             return;

+         }

+ 

          tevent_req_error(req, ret);

          return;

      }
@@ -980,6 +1024,7 @@

      struct sdap_cli_connect_state *state = tevent_req_data(req,

                                               struct sdap_cli_connect_state);

      struct tevent_req *subreq;

+     int ret;

  

      subreq = sdap_get_rootdse_send(state, state->ev, state->opts, state->sh);

      if (!subreq) {
@@ -992,15 +1037,11 @@

      /* this rootdse search is performed before we actually do a bind,

       * so we need to set up the callbacks or we will never get notified

       * of a reply */

-         state->sh->connected = true;

- #ifndef HAVE_LDAP_CONNCB

-         int ret;

  

-         ret = sdap_install_ldap_callbacks(state->sh, state->ev);

+         ret = sdap_set_connected(state->sh, state->ev);

          if (ret) {

              tevent_req_error(req, ret);

          }

- #endif

      }

  }

  
@@ -1016,8 +1057,29 @@

      ret = sdap_get_rootdse_recv(subreq, state, &state->rootdse);

      talloc_zfree(subreq);

      if (ret) {

-         tevent_req_error(req, ret);

-         return;

+         if (ret == ETIMEDOUT) { /* retry another server */

+             fo_set_port_status(state->srv, PORT_NOT_WORKING);

+             ret = sdap_cli_resolve_next(req);

+             if (ret != EOK) {

+                 tevent_req_error(req, ret);

+             }

+             return;

+         }

+ 

+         else if (ret == ENOENT) {

+             /* RootDSE was not available on

+              * the server.

+              * Continue, and just assume that the

+              * features requested by the config

+              * work properly.

+              */

+             state->use_rootdse = false;

+         }

+ 

+         else {

+             tevent_req_error(req, ret);

+             return;

+         }

      }

  

      sasl_mech = dp_opt_get_string(state->opts->basic, SDAP_SASL_MECH);
@@ -1056,7 +1118,9 @@

                          dp_opt_get_string(state->opts->basic,

                                                     SDAP_SASL_AUTHID),

                          dp_opt_get_string(state->opts->basic,

-                                                    SDAP_KRB5_REALM));

+                                                    SDAP_KRB5_REALM),

+                         dp_opt_get_int(state->opts->basic,

+                                                    SDAP_KRB5_TICKET_LIFETIME));

      if (!subreq) {

          tevent_req_error(req, ENOMEM);

          return;
@@ -1068,12 +1132,23 @@

  {

      struct tevent_req *req = tevent_req_callback_data(subreq,

                                                        struct tevent_req);

+     struct sdap_cli_connect_state *state = tevent_req_data(req,

+                                              struct sdap_cli_connect_state);

      enum sdap_result result;

      int ret;

  

      ret = sdap_kinit_recv(subreq, &result);

      talloc_zfree(subreq);

      if (ret) {

+         if (ret == ETIMEDOUT) { /* child timed out, retry another server */

+             fo_set_port_status(state->srv, PORT_NOT_WORKING);

+             ret = sdap_cli_resolve_next(req);

+             if (ret != EOK) {

+                 tevent_req_error(req, ret);

+             }

+             return;

+         }

+ 

          tevent_req_error(req, ret);

          return;

      }
@@ -1115,6 +1190,8 @@

  {

      struct tevent_req *req = tevent_req_callback_data(subreq,

                                                        struct tevent_req);

+     struct sdap_cli_connect_state *state = tevent_req_data(req,

+                                              struct sdap_cli_connect_state);

      enum sdap_result result;

      int ret;

  
@@ -1129,6 +1206,11 @@

          return;

      }

  

+     /* Reconnection succeeded

+      * Run any post-connection routines

+      */

+     be_run_online_cb(state->be);

+ 

      tevent_req_done(req);

  }

  
@@ -1157,6 +1239,9 @@

      }

  

      if (gsh) {

+         if (*gsh) {

+             talloc_zfree(*gsh);

+         }

          *gsh = talloc_steal(memctx, state->sh);

          if (!*gsh) {

              return ENOMEM;

@@ -28,15 +28,16 @@

  void make_realm_upper_case(const char *upn);

  struct sdap_handle *sdap_handle_create(TALLOC_CTX *memctx);

  

- #ifdef HAVE_LDAP_CONNCB

- int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb, LDAPURLDesc *srv,

-                            struct sockaddr *addr, struct ldap_conncb *ctx);

- void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb,

-                                     struct ldap_conncb *ctx);

- #else

- int sdap_install_ldap_callbacks(struct sdap_handle *sh,

-                                 struct tevent_context *ev);

- #endif

+ void sdap_ldap_result(struct tevent_context *ev, struct tevent_fd *fde,

+                       uint16_t flags, void *pvt);

+ 

+ int setup_ldap_connection_callbacks(struct sdap_handle *sh,

+                                     struct tevent_context *ev);

+ int remove_ldap_connection_callbacks(struct sdap_handle *sh);

+ 

+ int get_fd_from_ldap(LDAP *ldap, int *fd);

+ 

+ errno_t sdap_set_connected(struct sdap_handle *sh, struct tevent_context *ev);

  

  int sdap_op_add(TALLOC_CTX *memctx, struct tevent_context *ev,

                  struct sdap_handle *sh, int msgid,
@@ -58,6 +59,7 @@

                                       const char *realm_str,

                                       const char *princ_str,

                                       const char *keytab_name,

+                                      int32_t lifetime,

                                       int timeout);

  

  int sdap_get_tgt_recv(struct tevent_req *req,

@@ -77,7 +77,8 @@

      return 0;

  }

  

- static errno_t sdap_fork_child(struct sdap_child *child)

+ static errno_t sdap_fork_child(struct tevent_context *ev,

+                                struct sdap_child *child)

  {

      int pipefd_to_child[2];

      int pipefd_from_child[2];
@@ -118,6 +119,11 @@

          fd_nonblocking(child->read_from_child_fd);

          fd_nonblocking(child->write_to_child_fd);

  

+         ret = child_handler_setup(ev, pid, NULL, NULL);

+         if (ret != EOK) {

+             return ret;

+         }

+ 

      } else { /* error */

          err = errno;

          DEBUG(1, ("fork failed [%d][%s].\n", err, strerror(err)));
@@ -131,6 +137,7 @@

                                            const char *realm_str,

                                            const char *princ_str,

                                            const char *keytab_name,

+                                           int32_t lifetime,

                                            struct io_buffer **io_buf)

  {

      struct io_buffer *buf;
@@ -142,7 +149,7 @@

          return ENOMEM;

      }

  

-     buf->size = 3 * sizeof(uint32_t);

+     buf->size = 4 * sizeof(uint32_t);

      if (realm_str) {

          buf->size += strlen(realm_str);

      }
@@ -183,11 +190,14 @@

      /* keytab */

      if (keytab_name) {

          SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab_name), &rp);

-         safealign_memcpy(&buf->data[rp], keytab_name, strlen(realm_str), &rp);

+         safealign_memcpy(&buf->data[rp], keytab_name, strlen(keytab_name), &rp);

      } else {

          SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);

      }

  

+     /* lifetime */

+     SAFEALIGN_SET_UINT32(&buf->data[rp], lifetime, &rp);

+ 

      *io_buf = buf;

      return EOK;

  }
@@ -242,6 +252,7 @@

                                       const char *realm_str,

                                       const char *princ_str,

                                       const char *keytab_name,

+                                      int32_t lifetime,

                                       int timeout)

  {

      struct tevent_req *req, *subreq;
@@ -268,14 +279,14 @@

  

      /* prepare the data to pass to child */

      ret = create_tgt_req_send_buffer(state,

-                                      realm_str, princ_str, keytab_name,

+                                      realm_str, princ_str, keytab_name, lifetime,

                                       &buf);

      if (ret != EOK) {

          DEBUG(1, ("create_tgt_req_send_buffer failed.\n"));

          goto fail;

      }

  

-     ret = sdap_fork_child(state->child);

+     ret = sdap_fork_child(state->ev, state->child);

      if (ret != EOK) {

          DEBUG(1, ("sdap_fork_child failed.\n"));

          goto fail;
@@ -422,7 +433,6 @@

  {

      int ret;

      const char *mech;

-     struct tevent_signal *sige;

      unsigned v;

      FILE *debug_filep;

  
@@ -432,13 +442,6 @@

          return EOK;

      }

  

-     sige = tevent_add_signal(ctx->be->ev, ctx, SIGCHLD, SA_SIGINFO,

-                              child_sig_handler, NULL);

-     if (sige == NULL) {

-         DEBUG(1, ("tevent_add_signal failed.\n"));

-         return ENOMEM;

-     }

- 

      if (debug_to_file != 0 && ldap_child_debug_fd == -1) {

          ret = open_debug_file_ex("ldap_child", &debug_filep);

          if (ret != EOK) {

@@ -0,0 +1,275 @@

+ /*

+     SSSD

+ 

+     Helper routines for file descriptor events

+ 

+     Authors:

+         Sumit Bose <sbose@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include "util/util.h"

+ #include "providers/ldap/sdap_async_private.h"

+ 

+ struct sdap_fd_events {

+ #ifdef HAVE_LDAP_CONNCB

+     struct ldap_conncb *conncb;

+ #else

+     struct tevent_fd *fde;

+ #endif

+ };

+ 

+ int get_fd_from_ldap(LDAP *ldap, int *fd)

+ {

+     int ret;

+ 

+     ret = ldap_get_option(ldap, LDAP_OPT_DESC, fd);

+     if (ret != LDAP_OPT_SUCCESS) {

+         DEBUG(1, ("Failed to get fd from ldap!!\n"));

+         *fd = -1;

+         return EIO;

+     }

+ 

+     return EOK;

+ }

+ 

+ int remove_ldap_connection_callbacks(struct sdap_handle *sh)

+ {

+     /* sdap_fd_events might be NULL here if sdap_mark_offline()

+      * was called before a connection was established.

+      */

+     if (sh->sdap_fd_events) {

+ #ifdef HAVE_LDAP_CONNCB

+         talloc_zfree(sh->sdap_fd_events->conncb);

+ #else

+         talloc_zfree(sh->sdap_fd_events->fde);

+ #endif

+     }

+     return EOK;

+ }

+ 

+ #ifdef HAVE_LDAP_CONNCB

+ 

+ static int remove_connection_callback(TALLOC_CTX *mem_ctx)

+ {

+     int lret;

+     struct ldap_conncb *conncb = talloc_get_type(mem_ctx, struct ldap_conncb);

+ 

+     struct ldap_cb_data *cb_data = talloc_get_type(conncb->lc_arg,

+                                                    struct ldap_cb_data);

+ 

+     lret = ldap_get_option(cb_data->sh->ldap, LDAP_OPT_CONNECT_CB, conncb);

+     if (lret != LDAP_OPT_SUCCESS) {

+         DEBUG(1, ("Failed to remove connection callback.\n"));

+     } else {

+         DEBUG(9, ("Successfully removed connection callback.\n"));

+     }

+     return EOK;

+ }

+ 

+ static int sdap_ldap_connect_callback_add(LDAP *ld, Sockbuf *sb,

+                                           LDAPURLDesc *srv,

+                                           struct sockaddr *addr,

+                                           struct ldap_conncb *ctx)

+ {

+     int ret;

+     ber_socket_t ber_fd;

+     struct fd_event_item *fd_event_item;

+     struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg,

+                                                    struct ldap_cb_data);

+ 

+     if (cb_data == NULL) {

+         DEBUG(1, ("sdap_ldap_connect_callback_add called without "

+                   "callback data.\n"));

+         return EINVAL;

+     }

+ 

+     ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd);

+     if (ret == -1) {

+         DEBUG(1, ("ber_sockbuf_ctrl failed.\n"));

+         return EINVAL;

+     }

+     DEBUG(9, ("New LDAP connection to [%s] with fd [%d].\n",

+               ldap_url_desc2str(srv), ber_fd));

+ 

+     fd_event_item = talloc_zero(cb_data, struct fd_event_item);

+     if (fd_event_item == NULL) {

+         DEBUG(1, ("talloc failed.\n"));

+         return ENOMEM;

+     }

+ 

+     fd_event_item->fde = tevent_add_fd(cb_data->ev, fd_event_item, ber_fd,

+                                        TEVENT_FD_READ, sdap_ldap_result,

+                                        cb_data->sh);

+     if (fd_event_item->fde == NULL) {

+         DEBUG(1, ("tevent_add_fd failed.\n"));

+         talloc_free(fd_event_item);

+         return ENOMEM;

+     }

+     fd_event_item->fd = ber_fd;

+ 

+     DLIST_ADD(cb_data->fd_list, fd_event_item);

+ 

+     return LDAP_SUCCESS;

+ }

+ 

+ static void sdap_ldap_connect_callback_del(LDAP *ld, Sockbuf *sb,

+                                            struct ldap_conncb *ctx)

+ {

+     int ret;

+     ber_socket_t ber_fd;

+     struct fd_event_item *fd_event_item;

+     struct ldap_cb_data *cb_data = talloc_get_type(ctx->lc_arg,

+                                                    struct ldap_cb_data);

+ 

+     if (sb == NULL || cb_data == NULL) {

+         return;

+     }

+ 

+     ret = ber_sockbuf_ctrl(sb, LBER_SB_OPT_GET_FD, &ber_fd);

+     if (ret == -1) {

+         DEBUG(1, ("ber_sockbuf_ctrl failed.\n"));

+         return;

+     }

+     DEBUG(9, ("Closing LDAP connection with fd [%d].\n", ber_fd));

+ 

+     DLIST_FOR_EACH(fd_event_item, cb_data->fd_list) {

+         if (fd_event_item->fd == ber_fd) {

+             break;

+         }

+     }

+     if (fd_event_item == NULL) {

+         DEBUG(1, ("No event for fd [%d] found.\n", ber_fd));

+         return;

+     }

+ 

+     DLIST_REMOVE(cb_data->fd_list, fd_event_item);

+     talloc_zfree(fd_event_item);

+ 

+     return;

+ }

+ 

+ #else

+ 

+ static int sdap_install_ldap_callbacks(struct sdap_handle *sh,

+                                        struct tevent_context *ev)

+ {

+     int fd;

+     int ret;

+ 

+     if (sh->sdap_fd_events) {

+         DEBUG(1, ("sdap_install_ldap_callbacks is called with already "

+                   "initialized sdap_fd_events.\n"));

+         return EINVAL;

+     }

+ 

+     sh->sdap_fd_events = talloc_zero(sh, struct sdap_fd_events);

+     if (!sh->sdap_fd_events) {

+         DEBUG(1, ("talloc_zero failed.\n"));

+         return ENOMEM;

+     }

+ 

+     ret = get_fd_from_ldap(sh->ldap, &fd);

+     if (ret) return ret;

+ 

+     sh->sdap_fd_events->fde = tevent_add_fd(ev, sh->sdap_fd_events, fd,

+                                             TEVENT_FD_READ, sdap_ldap_result,

+                                             sh);

+     if (!sh->sdap_fd_events->fde) {

+         talloc_zfree(sh->sdap_fd_events);

+         return ENOMEM;

+     }

+ 

+     DEBUG(8, ("Trace: sh[%p], connected[%d], ops[%p], fde[%p], ldap[%p]\n",

+               sh, (int)sh->connected, sh->ops, sh->sdap_fd_events->fde,

+               sh->ldap));

+ 

+     return EOK;

+ }

+ 

+ #endif

+ 

+ 

+ errno_t setup_ldap_connection_callbacks(struct sdap_handle *sh,

+                                         struct tevent_context *ev)

+ {

+ #ifdef HAVE_LDAP_CONNCB

+     int ret;

+     struct ldap_cb_data *cb_data;

+ 

+     sh->sdap_fd_events = talloc_zero(sh, struct sdap_fd_events);

+     if (sh->sdap_fd_events == NULL) {

+         DEBUG(1, ("talloc_zero failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     sh->sdap_fd_events->conncb = talloc_zero(sh->sdap_fd_events,

+                                              struct ldap_conncb);

+     if (sh->sdap_fd_events->conncb == NULL) {

+         DEBUG(1, ("talloc_zero failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+ 

+     cb_data = talloc_zero(sh->sdap_fd_events->conncb, struct ldap_cb_data);

+     if (cb_data == NULL) {

+         DEBUG(1, ("talloc_zero failed.\n"));

+         ret = ENOMEM;

+         goto fail;

+     }

+     cb_data->sh = sh;

+     cb_data->ev = ev;

+ 

+     sh->sdap_fd_events->conncb->lc_add = sdap_ldap_connect_callback_add;

+     sh->sdap_fd_events->conncb->lc_del = sdap_ldap_connect_callback_del;

+     sh->sdap_fd_events->conncb->lc_arg = cb_data;

+ 

+     ret = ldap_set_option(sh->ldap, LDAP_OPT_CONNECT_CB,

+                           sh->sdap_fd_events->conncb);

+     if (ret != LDAP_OPT_SUCCESS) {

+         DEBUG(1, ("Failed to set connection callback\n"));

+         ret = EFAULT;

+         goto fail;

+     }

+ 

+     talloc_set_destructor((TALLOC_CTX *) sh->sdap_fd_events->conncb,

+                           remove_connection_callback);

+ 

+     return EOK;

+ 

+ fail:

+     talloc_zfree(sh->sdap_fd_events);

+     return ret;

+ #else

+     DEBUG(9, ("LDAP connection callbacks are not supported.\n"));

+     return EOK;

+ #endif

+ }

+ 

+ errno_t sdap_set_connected(struct sdap_handle *sh, struct tevent_context *ev)

+ {

+     int ret = EOK;

+ 

+     sh->connected = true;

+ 

+ #ifndef HAVE_LDAP_CONNCB

+     ret = sdap_install_ldap_callbacks(sh, ev);

+ #endif

+ 

+     return ret;

+ }

src/providers/proxy/proxy.c src/providers/proxy.c
file renamed
+1022 -153
@@ -24,13 +24,18 @@

  #include <pwd.h>

  #include <grp.h>

  #include <dlfcn.h>

+ #include <sys/types.h>

+ #include <sys/wait.h>

  

  #include <security/pam_appl.h>

  #include <security/pam_modules.h>

  

  #include "util/util.h"

+ #include "util/strtonum.h"

  #include "providers/dp_backend.h"

  #include "db/sysdb.h"

+ #include "proxy.h"

+ #include <dhash.h>

  

  struct proxy_nss_ops {

      enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
@@ -65,69 +70,54 @@

  struct proxy_auth_ctx {

      struct be_ctx *be;

      char *pam_target;

- };

  

- struct authtok_conv {

-     uint32_t authtok_size;

-     uint8_t *authtok;

+     uint32_t max_children;

+     uint32_t running;

+     uint32_t next_id;

+     hash_table_t *request_table;

+     struct sbus_connection *sbus_srv;

+     int timeout_ms;

  };

  

- static int proxy_internal_conv(int num_msg, const struct pam_message **msgm,

-                             struct pam_response **response,

-                             void *appdata_ptr) {

-     int i;

-     struct pam_response *reply;

-     struct authtok_conv *auth_data;

- 

-     auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);

- 

-     if (num_msg <= 0) return PAM_CONV_ERR;

+ static int client_registration(DBusMessage *message,

+                                struct sbus_connection *conn);

  

-     reply = (struct pam_response *) calloc(num_msg,

-                                            sizeof(struct pam_response));

-     if (reply == NULL) return PAM_CONV_ERR;

- 

-     for (i=0; i < num_msg; i++) {

-         switch( msgm[i]->msg_style ) {

-             case PAM_PROMPT_ECHO_OFF:

-                 DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg));

-                 reply[i].resp_retcode = 0;

-                 reply[i].resp = calloc(auth_data->authtok_size + 1,

-                                        sizeof(char));

-                 if (reply[i].resp == NULL) goto failed;

-                 memcpy(reply[i].resp, auth_data->authtok, auth_data->authtok_size);

- 

-                 break;

-             default:

-                 DEBUG(1, ("Conversation style %d not supported.\n",

-                            msgm[i]->msg_style));

-                 goto failed;

-         }

-     }

+ static struct sbus_method proxy_methods[] = {

+     { DP_METHOD_REGISTER, client_registration },

+     { NULL, NULL }

+ };

  

-     *response = reply;

-     reply = NULL;

+ struct sbus_interface proxy_interface = {

+     DP_INTERFACE,

+     DP_PATH,

+     SBUS_DEFAULT_VTABLE,

+     proxy_methods,

+     NULL

+ };

  

-     return PAM_SUCCESS;

+ struct authtok_conv {

+     uint32_t authtok_size;

+     uint8_t *authtok;

+ };

  

- failed:

-     free(reply);

-     return PAM_CONV_ERR;

- }

+ struct proxy_client_ctx {

+     struct be_req *be_req;

+     struct proxy_auth_ctx *auth_ctx;

+ };

  

  static void proxy_pam_handler_cache_done(struct tevent_req *treq);

  static void proxy_reply(struct be_req *req, int dp_err,

                          int error, const char *errstr);

  

+ static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,

+                                            struct proxy_auth_ctx *ctx,

+                                            struct be_req *be_req);

+ static void proxy_child_done(struct tevent_req *child_req);

  static void proxy_pam_handler(struct be_req *req) {

-     int ret;

-     int pam_status;

-     pam_handle_t *pamh=NULL;

-     struct authtok_conv *auth_data;

-     struct pam_conv conv;

      struct pam_data *pd;

-     struct proxy_auth_ctx *ctx;;

-     bool cache_auth_data = false;

+     struct proxy_auth_ctx *ctx;

+     struct tevent_req *child_req = NULL;

+     struct proxy_client_ctx *client_ctx;

  

      pd = talloc_get_type(req->req_data, struct pam_data);

  
@@ -158,144 +148,812 @@

              return;

      }

  

-     conv.conv=proxy_internal_conv;

-     auth_data = talloc_zero(req, struct authtok_conv);

-     conv.appdata_ptr=auth_data;

- 

-     ret = pam_start(ctx->pam_target, pd->user, &conv, &pamh);

-     if (ret == PAM_SUCCESS) {

-         DEBUG(1, ("Pam transaction started.\n"));

-         ret = pam_set_item(pamh, PAM_TTY, pd->tty);

-         if (ret != PAM_SUCCESS) {

-             DEBUG(1, ("Setting PAM_TTY failed: %s.\n", pam_strerror(pamh, ret)));

-         }

-         ret = pam_set_item(pamh, PAM_RUSER, pd->ruser);

-         if (ret != PAM_SUCCESS) {

-             DEBUG(1, ("Setting PAM_RUSER failed: %s.\n", pam_strerror(pamh, ret)));

-         }

-         ret = pam_set_item(pamh, PAM_RHOST, pd->rhost);

-         if (ret != PAM_SUCCESS) {

-             DEBUG(1, ("Setting PAM_RHOST failed: %s.\n", pam_strerror(pamh, ret)));

-         }

-         switch (pd->cmd) {

-             case SSS_PAM_AUTHENTICATE:

-                 auth_data->authtok_size = pd->authtok_size;

-                 auth_data->authtok = pd->authtok;

-                 pam_status = pam_authenticate(pamh, 0);

-                 if ((pam_status == PAM_SUCCESS) &&

-                     (req->be_ctx->domain->cache_credentials)) {

-                     cache_auth_data = true;

-                 }

-                 break;

-             case SSS_PAM_SETCRED:

-                 pam_status=pam_setcred(pamh, 0);

-                 break;

-             case SSS_PAM_ACCT_MGMT:

-                 pam_status=pam_acct_mgmt(pamh, 0);

-                 break;

-             case SSS_PAM_OPEN_SESSION:

-                 pam_status=pam_open_session(pamh, 0);

-                 break;

-             case SSS_PAM_CLOSE_SESSION:

-                 pam_status=pam_close_session(pamh, 0);

-                 break;

-             case SSS_PAM_CHAUTHTOK:

-                 if (pd->priv != 1) {

-                     auth_data->authtok_size = pd->authtok_size;

-                     auth_data->authtok = pd->authtok;

-                     pam_status = pam_authenticate(pamh, 0);

-                     if (pam_status != PAM_SUCCESS) break;

-                 }

-                 auth_data->authtok_size = pd->newauthtok_size;

-                 auth_data->authtok = pd->newauthtok;

-                 pam_status = pam_chauthtok(pamh, 0);

-                 if ((pam_status == PAM_SUCCESS) &&

-                     (req->be_ctx->domain->cache_credentials)) {

-                     cache_auth_data = true;

-                 }

-                 break;

-             case SSS_PAM_CHAUTHTOK_PRELIM:

-                 if (pd->priv != 1) {

-                     auth_data->authtok_size = pd->authtok_size;

-                     auth_data->authtok = pd->authtok;

-                     pam_status = pam_authenticate(pamh, 0);

-                 } else {

-                     pam_status = PAM_SUCCESS;

-                 }

-                 break;

-             default:

-                 DEBUG(1, ("unknown PAM call\n"));

-                 pam_status=PAM_ABORT;

+     client_ctx = talloc(req, struct proxy_client_ctx);

+     if (client_ctx == NULL) {

+         proxy_reply(req, DP_ERR_FATAL, ENOMEM, NULL);

+         return;

+     }

+     client_ctx->auth_ctx = ctx;

+     client_ctx->be_req = req;

+ 

+     /* Queue the request and spawn a child if there

+      * is an available slot.

+      */

+     child_req = proxy_child_send(req, ctx, req);

+     if (child_req == NULL) {

+         /* Could not queue request

+          * Return an error

+          */

+         proxy_reply(req, DP_ERR_FATAL, EINVAL, "Could not queue request\n");

+         return;

+     }

+     tevent_req_set_callback(child_req, proxy_child_done, client_ctx);

+     return;

+ }

+ 

+ struct pc_init_ctx;

+ struct proxy_child_ctx {

+     struct proxy_auth_ctx *auth_ctx;

+     struct be_req *be_req;

+     struct pam_data *pd;

+ 

+     uint32_t id;

+     pid_t pid;

+     bool running;

+ 

+     struct sbus_connection *conn;

+     struct tevent_timer *timer;

+ 

+     struct tevent_req *init_req;

+ };

+ 

+ static int proxy_child_destructor(TALLOC_CTX *ctx)

+ {

+     struct proxy_child_ctx *child_ctx =

+             talloc_get_type(ctx, struct proxy_child_ctx);

+     hash_key_t key;

+     int hret;

+ 

+     DEBUG(8, ("Removing proxy child id [%d]\n", child_ctx->id));

+     key.type = HASH_KEY_ULONG;

+     key.ul = child_ctx->id;

+     hret = hash_delete(child_ctx->auth_ctx->request_table, &key);

+     if (!(hret == HASH_SUCCESS ||

+           hret == HASH_ERROR_KEY_NOT_FOUND)) {

+         DEBUG(1, ("Hash error [%d][%s]\n", hret, hash_error_string(hret)));

+         /* Nothing we can do about this, so just continue */

+     }

+     return 0;

+ }

+ 

+ static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,

+                                               struct proxy_child_ctx *child_ctx,

+                                               struct proxy_auth_ctx *auth_ctx);

+ static void proxy_child_init_done(struct tevent_req *subreq);

+ static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,

+                                            struct proxy_auth_ctx *auth_ctx,

+                                            struct be_req *be_req)

+ {

+     struct tevent_req *req;

+     struct tevent_req *subreq;

+     struct proxy_child_ctx *state;

+     int hret;

+     hash_key_t key;

+     hash_value_t value;

+     uint32_t first;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct proxy_child_ctx);

+     if (req == NULL) {

+         DEBUG(1, ("Could not send PAM request to child\n"));

+         return NULL;

+     }

+ 

+     state->be_req = be_req;

+     state->auth_ctx = auth_ctx;

+     state->pd = talloc_get_type(be_req->req_data, struct pam_data);

+ 

+     /* Find an available key */

+     key.type = HASH_KEY_ULONG;

+     key.ul = auth_ctx->next_id;

+ 

+     first = auth_ctx->next_id;

+     while (auth_ctx->next_id == 0 ||

+             hash_has_key(auth_ctx->request_table, &key)) {

+         /* Handle overflow, zero is a reserved value

+          * Also handle the unlikely case where the next ID

+          * is still awaiting being run

+          */

+         auth_ctx->next_id++;

+         key.ul = auth_ctx->next_id;

+ 

+         if (auth_ctx->next_id == first) {

+             /* We've looped through all possible integers! */

+             DEBUG(0, ("Serious error: queue is too long!\n"));

+             talloc_zfree(req);

+             return NULL;

          }

+     }

+ 

+     state->id = auth_ctx->next_id;

+     auth_ctx->next_id++;

+ 

+     value.type = HASH_VALUE_PTR;

+     value.ptr = req;

+     DEBUG(8, ("Queueing request [%d]\n", key.ul));

+     hret = hash_enter(auth_ctx->request_table,

+                       &key, &value);

+     if (hret != HASH_SUCCESS) {

+         DEBUG(1, ("Could not add request to the queue\n"));

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     talloc_set_destructor((TALLOC_CTX *) state,

+                           proxy_child_destructor);

+ 

+     if (auth_ctx->running < auth_ctx->max_children) {

+         /* There's an available slot; start a child

+          * to handle the request

+          */

+ 

+         auth_ctx->running++;

+         subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);

+         if (!subreq) {

+             DEBUG(1, ("Could not fork child process\n"));

+             auth_ctx->running--;

+             talloc_zfree(req);

+             return NULL;

+         }

+         tevent_req_set_callback(subreq, proxy_child_init_done, req);

+ 

+         state->running = true;

+     }

+     else {

+         /* If there was no available slot, it will be queued

+          * until a slot is available

+          */

+         DEBUG(8, ("All available child slots are full, queuing request\n"));

+     }

+     return req;

+ }

+ 

+ struct pc_init_ctx {

+     char *command;

+     pid_t pid;

+     struct tevent_timer *timeout;

+     struct tevent_signal *sige;

+     struct proxy_child_ctx *child_ctx;

+     struct sbus_connection *conn;

+ };

+ 

+ static int pc_init_destructor (TALLOC_CTX *ctx)

+ {

+     struct pc_init_ctx *init_ctx =

+             talloc_get_type(ctx, struct pc_init_ctx);

+ 

+     /* If the init request has died, forcibly kill the child */

+     kill(init_ctx->pid, SIGKILL);

+     return 0;

+ }

+ 

+ static void pc_init_sig_handler(struct tevent_context *ev,

+                            struct tevent_signal *sige, int signum,

+                            int count, void *__siginfo, void *pvt);

+ static void pc_init_timeout(struct tevent_context *ev,

+                             struct tevent_timer *te,

+                             struct timeval t, void *ptr);

+ static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,

+                                               struct proxy_child_ctx *child_ctx,

+                                               struct proxy_auth_ctx *auth_ctx)

+ {

+     struct tevent_req *req;

+     struct pc_init_ctx *state;

+     char **proxy_child_args;

+     struct timeval tv;

+     errno_t ret;

+     pid_t pid;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct pc_init_ctx);

+     if (req == NULL) {

+         DEBUG(1, ("Could not create tevent_req\n"));

+         return NULL;

+     }

+ 

+     state->child_ctx = child_ctx;

+ 

+     state->command = talloc_asprintf(req,

+             "%s/proxy_child -d %d%s%s --domain %s --id %d",

+             SSSD_LIBEXEC_PATH, debug_level,

+             (debug_timestamps ? "" : " --debug-timestamps=0"),

+             (debug_to_file ? " --debug-to-files" : ""),

+             auth_ctx->be->domain->name,

+             child_ctx->id);

+     if (state->command == NULL) {

+         DEBUG(1, ("talloc_asprintf failed.\n"));

+         return NULL;

+     }

+ 

+     DEBUG(7, ("Starting proxy child with args [%s]\n", state->command));

+ 

+     pid = fork();

+     if (pid < 0) {

+         ret = errno;

+         DEBUG(1, ("fork failed [%d][%s].\n", ret, strerror(ret)));

+         talloc_zfree(req);

+         return NULL;

+     }

  

-         DEBUG(4, ("Pam result: [%d][%s]\n", pam_status,

-                   pam_strerror(pamh, pam_status)));

+     if (pid == 0) { /* child */

+         proxy_child_args = parse_args(state->command);

+         execvp(proxy_child_args[0], proxy_child_args);

  

-         if (pam_status == PAM_AUTHINFO_UNAVAIL) {

-             be_mark_offline(req->be_ctx);

+         ret = errno;

+         DEBUG(0, ("Could not start proxy child [%s]: [%d][%s].\n",

+                   state->command, ret, strerror(ret)));

+ 

+         _exit(1);

+     }

+ 

+     else { /* parent */

+         state->pid = pid;

+         /* Make sure to kill the child process if we abort */

+         talloc_set_destructor((TALLOC_CTX *)state, pc_init_destructor);

+ 

+         state->sige = tevent_add_signal(auth_ctx->be->ev, req,

+                                         SIGCHLD, SA_SIGINFO,

+                                         pc_init_sig_handler, req);

+         if (state->sige == NULL) {

+             DEBUG(1, ("tevent_add_signal failed.\n"));

+             talloc_zfree(req);

+             return NULL;

          }

  

-         ret = pam_end(pamh, pam_status);

-         if (ret != PAM_SUCCESS) {

-             pamh=NULL;

-             DEBUG(1, ("Cannot terminate pam transaction.\n"));

+         /* Save the init request to the child context.

+          * This is technically a layering violation,

+          * but it's the only sane way to be able to

+          * identify which client is which when it

+          * connects to the backend in

+          * client_registration()

+          */

+         child_ctx->init_req = req;

+ 

+         /* Wait six seconds for the child to connect

+          * This is because the connection handler will add

+          * its own five-second timeout, and we don't want to

+          * be faster here.

+          */

+         tv = tevent_timeval_current_ofs(6, 0);

+         state->timeout = tevent_add_timer(auth_ctx->be->ev, req,

+                                           tv, pc_init_timeout, req);

+ 

+         /* processing will continue once the connection is received

+          * in proxy_client_init()

+          */

+         return req;

+     }

+ }

+ 

+ static void pc_init_sig_handler(struct tevent_context *ev,

+                                 struct tevent_signal *sige, int signum,

+                                 int count, void *__siginfo, void *pvt)

+ {

+     int ret;

+     int child_status;

+     struct tevent_req *req;

+     struct pc_init_ctx *init_ctx;

+ 

+     if (count <= 0) {

+         DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));

+         return;

+     }

+ 

+     req = talloc_get_type(pvt, struct tevent_req);

+     init_ctx = tevent_req_data(req, struct pc_init_ctx);

+ 

+     DEBUG(7, ("Waiting for child [%d].\n", init_ctx->pid));

+ 

+     errno = 0;

+     ret = waitpid(init_ctx->pid, &child_status, WNOHANG);

+ 

+     if (ret == -1) {

+         ret = errno;

+         DEBUG(1, ("waitpid failed [%d][%s].\n", ret, strerror(ret)));

+     } else if (ret == 0) {

+         DEBUG(1, ("waitpid did not find a child with changed status.\n"));

+     } else {

+         if (WIFEXITED(child_status)) {

+             DEBUG(4, ("child [%d] exited with status [%d].\n", ret,

+                       WEXITSTATUS(child_status)));

+             tevent_req_error(req, EIO);

+         } else if (WIFSIGNALED(child_status)) {

+             DEBUG(4, ("child [%d] was terminate by signal [%d].\n", ret,

+                       WTERMSIG(child_status)));

+             tevent_req_error(req, EIO);

+         } else {

+             if (WIFSTOPPED(child_status)) {

+                 DEBUG(1, ("child [%d] was stopped by signal [%d].\n", ret,

+                           WSTOPSIG(child_status)));

+             }

+             if (WIFCONTINUED(child_status)) {

+                 DEBUG(1, ("child [%d] was resumed by delivery of SIGCONT.\n",

+                           ret));

+             }

+             DEBUG(1, ("Child is still running, no new child is started.\n"));

+             return;

          }

+     }

+ }

+ 

+ static void pc_init_timeout(struct tevent_context *ev,

+                             struct tevent_timer *te,

+                             struct timeval t, void *ptr)

+ {

+     struct tevent_req *req;

+ 

+     DEBUG(2, ("Client timed out before Identification!\n"));

+     req = talloc_get_type(ptr, struct tevent_req);

+     tevent_req_error(req, ETIMEDOUT);

+ }

+ 

+ static errno_t proxy_child_init_recv(struct tevent_req *req,

+                                    pid_t *pid,

+                                    struct sbus_connection **conn)

+ {

+     struct pc_init_ctx *state;

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     state = tevent_req_data(req, struct pc_init_ctx);

+ 

+     /* Unset the destructor since we initialized successfully.

+      * We don't want to kill the child now that it's properly

+      * set up.

+      */

+     talloc_set_destructor((TALLOC_CTX *)state, NULL);

+ 

+     *pid = state->pid;

+     *conn = state->conn;

+ 

+     return EOK;

+ }

+ 

+ struct proxy_child_sig_ctx {

+     struct proxy_auth_ctx *auth_ctx;

+     pid_t pid;

+ };

+ static void proxy_child_sig_handler(struct tevent_context *ev,

+                                     struct tevent_signal *sige, int signum,

+                                     int count, void *__siginfo, void *pvt);

+ static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,

+                                               struct proxy_auth_ctx *auth_ctx,

+                                               struct sbus_connection *conn,

+                                               struct pam_data *pd,

+                                               pid_t pid);

+ static void proxy_pam_conv_done(struct tevent_req *subreq);

+ static void proxy_child_init_done(struct tevent_req *subreq) {

+     int ret;

+     struct tevent_signal *sige;

+     struct tevent_req *req =

+             tevent_req_callback_data(subreq, struct tevent_req);

+     struct proxy_child_ctx *child_ctx =

+             tevent_req_data(req, struct proxy_child_ctx);

+     struct proxy_child_sig_ctx *sig_ctx;

+ 

+     ret = proxy_child_init_recv(subreq, &child_ctx->pid, &child_ctx->conn);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(6, ("Proxy child init failed [%d]\n", ret));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     /* An initialized child is available, awaiting the PAM command */

+     subreq = proxy_pam_conv_send(req, child_ctx->auth_ctx,

+                                  child_ctx->conn, child_ctx->pd,

+                                  child_ctx->pid);

+     if (!subreq) {

+         DEBUG(1,("Could not start PAM conversation\n"));

+         tevent_req_error(req, EIO);

+         return;

+     }

+     tevent_req_set_callback(subreq, proxy_pam_conv_done, req);

+ 

+     /* Add a signal handler for the child under the auth_ctx,

+      * that way if the child exits after completion of the

+      * request, it will still be handled.

+      */

+     sig_ctx = talloc_zero(child_ctx->auth_ctx, struct proxy_child_sig_ctx);

+     if(sig_ctx == NULL) {

+         DEBUG(1, ("tevent_add_signal failed.\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+     sig_ctx->auth_ctx = child_ctx->auth_ctx;

+     sig_ctx->pid = child_ctx->pid;

+ 

+     sige = tevent_add_signal(child_ctx->auth_ctx->be->ev,

+                              child_ctx->auth_ctx,

+                              SIGCHLD, SA_SIGINFO,

+                              proxy_child_sig_handler,

+                              sig_ctx);

+     if (sige == NULL) {

+         DEBUG(1, ("tevent_add_signal failed.\n"));

+         tevent_req_error(req, ENOMEM);

+         return;

+     }

+ 

+     /* Steal the signal context onto the signal event

+      * so that when the signal is freed, the context

+      * will go with it.

+      */

+     talloc_steal(sige, sig_ctx);

+ }

  

+ static void remove_sige(struct tevent_context *ev,

+                         struct tevent_immediate *imm,

+                         void *pvt);

+ static void run_proxy_child_queue(struct tevent_context *ev,

+                                   struct tevent_immediate *imm,

+                                   void *pvt);

+ static void proxy_child_sig_handler(struct tevent_context *ev,

+                                     struct tevent_signal *sige, int signum,

+                                     int count, void *__siginfo, void *pvt)

+ {

+     int ret;

+     int child_status;

+     struct proxy_child_sig_ctx *sig_ctx;

+     struct tevent_immediate *imm;

+     struct tevent_immediate *imm2;

+ 

+     if (count <= 0) {

+         DEBUG(0, ("SIGCHLD handler called with invalid child count\n"));

+         return;

+     }

+ 

+     sig_ctx = talloc_get_type(pvt, struct proxy_child_sig_ctx);

+     DEBUG(7, ("Waiting for child [%d].\n", sig_ctx->pid));

+ 

+     errno = 0;

+     ret = waitpid(sig_ctx->pid, &child_status, WNOHANG);

+ 

+     if (ret == -1) {

+         ret = errno;

+         DEBUG(1, ("waitpid failed [%d][%s].\n", ret, strerror(ret)));

+     } else if (ret == 0) {

+         DEBUG(1, ("waitpid did not found a child with changed status.\n"));

      } else {

-         DEBUG(1, ("Failed to initialize pam transaction.\n"));

-         pam_status = PAM_SYSTEM_ERR;

+         if (WIFEXITED(child_status)) {

+             DEBUG(4, ("child [%d] exited with status [%d].\n", ret,

+                       WEXITSTATUS(child_status)));

+         } else if (WIFSIGNALED(child_status)) {

+             DEBUG(4, ("child [%d] was terminated by signal [%d].\n", ret,

+                       WTERMSIG(child_status)));

+         } else {

+             if (WIFSTOPPED(child_status)) {

+                 DEBUG(1, ("child [%d] was stopped by signal [%d].\n", ret,

+                           WSTOPSIG(child_status)));

+             }

+             if (WIFCONTINUED(child_status)) {

+                 DEBUG(1, ("child [%d] was resumed by delivery of SIGCONT.\n",

+                           ret));

+             }

+             DEBUG(1, ("Child is still running, no new child is started.\n"));

+             return;

+         }

+ 

+         imm = tevent_create_immediate(ev);

+         if (imm == NULL) {

+             DEBUG(1, ("tevent_create_immediate failed.\n"));

+             return;

+         }

+ 

+         tevent_schedule_immediate(imm, ev, run_proxy_child_queue,

+                                   sig_ctx->auth_ctx);

+ 

+         /* schedule another immediate timer to delete the sigchld handler */

+         imm2 = tevent_create_immediate(ev);

+         if (imm == NULL) {

+             DEBUG(1, ("tevent_create_immediate failed.\n"));

+             return;

+         }

+ 

+         tevent_schedule_immediate(imm2, ev, remove_sige, sige);

+     }

+ 

+     return;

+ }

+ 

+ static void remove_sige(struct tevent_context *ev,

+                         struct tevent_immediate *imm,

+                         void *pvt)

+ {

+     talloc_free(pvt);

+ }

+ 

+ struct proxy_conv_ctx {

+     struct proxy_auth_ctx *auth_ctx;

+     struct sbus_connection *conn;

+     struct pam_data *pd;

+     pid_t pid;

+ };

+ static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr);

+ static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,

+                                               struct proxy_auth_ctx *auth_ctx,

+                                               struct sbus_connection *conn,

+                                               struct pam_data *pd,

+                                               pid_t pid)

+ {

+     errno_t ret;

+     bool dp_ret;

+     DBusMessage *msg;

+     struct tevent_req *req;

+     struct proxy_conv_ctx *state;

+ 

+     req = tevent_req_create(mem_ctx, &state, struct proxy_conv_ctx);

+     if (req == NULL) {

+         return NULL;

+     }

+ 

+     state->auth_ctx = auth_ctx;

+     state->conn = conn;

+     state->pd = pd;

+     state->pid = pid;

+ 

+     msg = dbus_message_new_method_call(NULL,

+                                        DP_PATH,

+                                        DP_INTERFACE,

+                                        DP_METHOD_PAMHANDLER);

+     if (msg == NULL) {

+         DEBUG(1, ("dbus_message_new_method_call failed.\n"));

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     DEBUG(4, ("Sending request with the following data:\n"));

+     DEBUG_PAM_DATA(4, pd);

+ 

+     dp_ret = dp_pack_pam_request(msg, pd);

+     if (!dp_ret) {

+         DEBUG(1, ("Failed to build message\n"));

+         dbus_message_unref(msg);

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     ret = sbus_conn_send(state->conn, msg, state->auth_ctx->timeout_ms,

+                          proxy_pam_conv_reply, req, NULL);

+     if (ret != EOK) {

+         dbus_message_unref(msg);

+         talloc_zfree(req);

+         return NULL;

+     }

+ 

+     dbus_message_unref(msg);

+     return req;

+ }

+ 

+ static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr)

+ {

+     struct tevent_req *req;

+     struct proxy_conv_ctx *state;

+     DBusError dbus_error;

+     DBusMessage *reply;

+     int type;

+     int ret;

+ 

+     DEBUG(8, ("Handling pam conversation reply\n"));

+ 

+     req = talloc_get_type(ptr, struct tevent_req);

+     state = tevent_req_data(req, struct proxy_conv_ctx);

+ 

+     dbus_error_init(&dbus_error);

+ 

+     reply = dbus_pending_call_steal_reply(pending);

+     dbus_pending_call_unref(pending);

+     if (reply == NULL) {

+         DEBUG(0, ("Severe error. A reply callback was called but no reply was"

+                   "received and no timeout occurred\n"));

+         state->pd->pam_status = PAM_SYSTEM_ERR;

+         tevent_req_error(req, EIO);

+     }

+ 

+     type = dbus_message_get_type(reply);

+     switch (type) {

+         case DBUS_MESSAGE_TYPE_METHOD_RETURN:

+             ret = dp_unpack_pam_response(reply, state->pd, &dbus_error);

+             if (!ret) {

+                 DEBUG(0, ("Failed to parse reply.\n"));

+                 state->pd->pam_status = PAM_SYSTEM_ERR;

+                 dbus_message_unref(reply);

+                 tevent_req_error(req, EIO);

+                 return;

+             }

+             DEBUG(4, ("received: [%d][%s]\n",

+                       state->pd->pam_status,

+                       state->pd->domain));

+             break;

+         case DBUS_MESSAGE_TYPE_ERROR:

+             DEBUG(0, ("Reply error [%s].\n",

+                     dbus_message_get_error_name(reply)));

+             state->pd->pam_status = PAM_SYSTEM_ERR;

+             break;

+         default:

+             DEBUG(0, ("Default... what now?.\n"));

+             state->pd->pam_status = PAM_SYSTEM_ERR;

      }

+     dbus_message_unref(reply);

+ 

+     /* Kill the child */

+     kill(state->pid, SIGKILL);

  

-     pd->pam_status = pam_status;

+     /* Conversation is finished */

+     tevent_req_done(req);

+ }

+ 

+ static errno_t proxy_pam_conv_recv(struct tevent_req *req)

+ {

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     return EOK;

+ }

+ 

+ static void proxy_pam_conv_done(struct tevent_req *subreq)

+ {

+     struct tevent_req *req;

+     int ret;

+ 

+     req = tevent_req_callback_data(subreq, struct tevent_req);

+ 

+     ret = proxy_pam_conv_recv(subreq);

+     talloc_zfree(subreq);

+     if (ret != EOK) {

+         DEBUG(6, ("Proxy PAM conversation failed [%d]\n", ret));

+         tevent_req_error(req, ret);

+         return;

+     }

+ 

+     tevent_req_done(req);

+ }

+ 

+ static int proxy_child_recv(struct tevent_req *req,

+                           TALLOC_CTX *mem_ctx,

+                           struct pam_data **pd)

+ {

+     struct proxy_child_ctx *ctx;

+ 

+     TEVENT_REQ_RETURN_ON_ERROR(req);

+ 

+     ctx = tevent_req_data(req, struct proxy_child_ctx);

+     *pd = talloc_steal(mem_ctx, ctx->pd);

+ 

+     return EOK;

+ }

+ 

+ static void proxy_child_done(struct tevent_req *req)

+ {

+     struct proxy_client_ctx *client_ctx =

+             tevent_req_callback_data(req, struct proxy_client_ctx);

+     struct pam_data *pd;

+     char *password;

+     int ret;

+     struct tevent_immediate *imm;

+ 

+     ret = proxy_child_recv(req, client_ctx, &pd);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         /* Pam child failed */

+         client_ctx->auth_ctx->running--;

+         proxy_reply(client_ctx->be_req, DP_ERR_FATAL, ret,

+                     "PAM child failed");

+ 

+         /* Start the next auth in the queue, if any */

+         imm = tevent_create_immediate(client_ctx->be_req->be_ctx->ev);

+         if (imm == NULL) {

+             DEBUG(1, ("tevent_create_immediate failed.\n"));

+             return;

+         }

  

-     if (cache_auth_data) {

-         struct tevent_req *subreq;

-         char *password;

+         tevent_schedule_immediate(imm,

+                                   client_ctx->be_req->be_ctx->ev,

+                                   run_proxy_child_queue,

+                                   client_ctx->auth_ctx);

+         return;

+     }

  

-         password = talloc_size(req, auth_data->authtok_size + 1);

+     /* Check if we need to save the cached credentials */

+     if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) &&

+             pd->pam_status == PAM_SUCCESS &&

+             client_ctx->be_req->be_ctx->domain->cache_credentials) {

+         password = talloc_strndup(client_ctx->be_req,

+                                   (char *) pd->authtok,

+                                   pd->authtok_size);

          if (!password) {

              /* password caching failures are not fatal errors */

-             return proxy_reply(req, DP_ERR_OK, EOK, NULL);

+             DEBUG(2, ("Failed to cache password\n"));

+             goto done;

          }

-         memcpy(password, auth_data->authtok, auth_data->authtok_size);

-         password[auth_data->authtok_size] = '\0';

          talloc_set_destructor((TALLOC_CTX *)password, password_destructor);

  

-         subreq = sysdb_cache_password_send(req, req->be_ctx->ev,

-                                            req->be_ctx->sysdb, NULL,

-                                            req->be_ctx->domain,

-                                            pd->user, password);

-         if (!subreq) {

+         DEBUG(6, ("Caching the password\n"));

+         req = sysdb_cache_password_send(client_ctx,

+                                         client_ctx->be_req->be_ctx->ev,

+                                         client_ctx->be_req->be_ctx->sysdb,

+                                         NULL,

+                                         client_ctx->be_req->be_ctx->domain,

+                                         pd->user, password);

+         if (!req) {

              /* password caching failures are not fatal errors */

-             return proxy_reply(req, DP_ERR_OK, EOK, NULL);

+             DEBUG(2, ("Failed to cache password\n"));

+             goto done;

          }

-         tevent_req_set_callback(subreq, proxy_pam_handler_cache_done, req);

+         tevent_req_set_callback(req, proxy_pam_handler_cache_done,

+                                 client_ctx->be_req);

+         return;

      }

  

-     proxy_reply(req, DP_ERR_OK, EOK, NULL);

+ done:

+     proxy_reply(client_ctx->be_req, DP_ERR_OK, EOK, NULL);

+ }

+ 

+ static void run_proxy_child_queue(struct tevent_context *ev,

+                                   struct tevent_immediate *imm,

+                                   void *pvt)

+ {

+     struct proxy_auth_ctx *auth_ctx;

+     struct hash_iter_context_t *iter;

+     struct hash_entry_t *entry;

+     struct tevent_req *req;

+     struct tevent_req *subreq;

+     struct proxy_child_ctx *state;

+ 

+     auth_ctx = talloc_get_type(pvt, struct proxy_auth_ctx);

+ 

+     /* Launch next queued request */

+     iter = new_hash_iter_context(auth_ctx->request_table);

+     while ((entry = iter->next(iter)) != NULL) {

+         req = talloc_get_type(entry->value.ptr, struct tevent_req);

+         state = tevent_req_data(req, struct proxy_child_ctx);

+         if (!state->running) {

+             break;

+         }

+     }

+ 

+     if (!entry) {

+         /* Nothing pending on the queue */

+         return;

+     }

+ 

+     if (auth_ctx->running < auth_ctx->max_children) {

+         /* There's an available slot; start a child

+          * to handle the request

+          */

+         auth_ctx->running++;

+         subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);

+         if (!subreq) {

+             DEBUG(1, ("Could not fork child process\n"));

+             auth_ctx->running--;

+             talloc_zfree(req);

+             return;

+         }

+         tevent_req_set_callback(subreq, proxy_child_init_done, req);

+ 

+         state->running = true;

+     }

  }

  

  static void proxy_pam_handler_cache_done(struct tevent_req *subreq)

  {

-     struct be_req *req = tevent_req_callback_data(subreq, struct be_req);

+     struct be_req *be_req = tevent_req_callback_data(subreq, struct be_req);

      int ret;

  

      /* password caching failures are not fatal errors */

      ret = sysdb_cache_password_recv(subreq);

      talloc_zfree(subreq);

  

-     /* so we just log it any return */

+     /* so we just log it and return */

      if (ret) {

          DEBUG(2, ("Failed to cache password (%d)[%s]!?\n",

                    ret, strerror(ret)));

      }

  

-     return proxy_reply(req, DP_ERR_OK, EOK, NULL);

+     proxy_reply(be_req, DP_ERR_OK, EOK, NULL);

+ 

+     return;

  }

  

  static void proxy_reply(struct be_req *req, int dp_err,

                          int error, const char *errstr)

  {

+     if (!req->be_ctx->offstat.offline) {

+         /* This action took place online.

+          * Fire any online callbacks if necessary.

+          * Note: we're checking the offline value directly,

+          * because if the activity took a long time to

+          * complete, calling be_is_offline() might report false

+          * incorrectly.

+          */

+         be_run_online_cb(req->be_ctx);

+     }

      return req->fn(req, dp_err, error, errstr);

  }

  
@@ -2165,8 +2823,7 @@

                                     EINVAL, "Invalid attr type");

              } else {

                  char *endptr;

-                 errno = 0;

-                 uid = (uid_t)strtol(ar->filter_value, &endptr, 0);

+                 uid = (uid_t) strtouint32(ar->filter_value, &endptr, 0);

                  if (errno || *endptr || (ar->filter_value == endptr)) {

                      return proxy_reply(breq, DP_ERR_FATAL,

                                         EINVAL, "Invalid attr type");
@@ -2220,8 +2877,7 @@

                                     EINVAL, "Invalid attr type");

              } else {

                  char *endptr;

-                 errno = 0;

-                 gid = (gid_t)strtol(ar->filter_value, &endptr, 0);

+                 gid = (gid_t) strtouint32(ar->filter_value, &endptr, 0);

                  if (errno || *endptr || (ar->filter_value == endptr)) {

                      return proxy_reply(breq, DP_ERR_FATAL,

                                         EINVAL, "Invalid attr type");
@@ -2338,8 +2994,8 @@

      return funcptr;

  }

  

- int sssm_proxy_init(struct be_ctx *bectx,

-                     struct bet_ops **ops, void **pvt_data)

+ int sssm_proxy_id_init(struct be_ctx *bectx,

+                        struct bet_ops **ops, void **pvt_data)

  {

      struct proxy_ctx *ctx;

      char *libname;
@@ -2470,17 +3126,203 @@

      return ret;

  }

  

+ struct proxy_client {

+     struct proxy_auth_ctx *proxy_auth_ctx;

+     struct sbus_connection *conn;

+     struct tevent_timer *timeout;

+     bool initialized;

+ };

+ 

+ static void init_timeout(struct tevent_context *ev,

+                          struct tevent_timer *te,

+                          struct timeval t, void *ptr);

+ static int proxy_client_init(struct sbus_connection *conn, void *data)

+ {

+     struct proxy_auth_ctx *proxy_auth_ctx;

+     struct proxy_client *proxy_cli;

+     struct timeval tv;

+ 

+     proxy_auth_ctx = talloc_get_type(data, struct proxy_auth_ctx);

+ 

+     /* hang off this memory to the connection so that when the connection

+      * is freed we can potentially call a destructor */

+ 

+     proxy_cli = talloc_zero(conn, struct proxy_client);

+     if (!proxy_cli) {

+         DEBUG(0,("Out of memory?!\n"));

+         talloc_zfree(conn);

+         return ENOMEM;

+     }

+     proxy_cli->proxy_auth_ctx = proxy_auth_ctx;

+     proxy_cli->conn = conn;

+     proxy_cli->initialized = false;

+ 

+     /* 5 seconds should be plenty */

+     tv = tevent_timeval_current_ofs(5, 0);

+ 

+     proxy_cli->timeout = tevent_add_timer(proxy_auth_ctx->be->ev, proxy_cli,

+                                           tv, init_timeout, proxy_cli);

+     if (!proxy_cli->timeout) {

+         DEBUG(0,("Out of memory?!\n"));

+         talloc_zfree(conn);

+         return ENOMEM;

+     }

+     DEBUG(4, ("Set-up proxy client ID timeout [%p]\n", proxy_cli->timeout));

+ 

+     /* Attach the client context to the connection context, so that it is

+      * always available when we need to manage the connection. */

+     sbus_conn_set_private_data(conn, proxy_cli);

+ 

+     return EOK;

+ }

+ 

+ static void init_timeout(struct tevent_context *ev,

+                          struct tevent_timer *te,

+                          struct timeval t, void *ptr)

+ {

+     struct proxy_client *proxy_cli;

+ 

+     DEBUG(2, ("Client timed out before Identification [%p]!\n", te));

+ 

+     proxy_cli = talloc_get_type(ptr, struct proxy_client);

+ 

+     sbus_disconnect(proxy_cli->conn);

+     talloc_zfree(proxy_cli);

+ 

+     /* If we time out here, we will also time out to

+      * pc_init_timeout(), so we'll finish the request

+      * there.

+      */

+ }

+ 

+ static int client_registration(DBusMessage *message,

+                                struct sbus_connection *conn)

+ {

+     dbus_uint16_t version = DATA_PROVIDER_VERSION;

+     struct proxy_client *proxy_cli;

+     DBusMessage *reply;

+     DBusError dbus_error;

+     dbus_uint16_t cli_ver;

+     uint32_t cli_id;

+     dbus_bool_t dbret;

+     void *data;

+     int hret;

+     hash_key_t key;

+     hash_value_t value;

+     struct tevent_req *req;

+     struct proxy_child_ctx *child_ctx;

+     struct pc_init_ctx *init_ctx;

+ 

+     data = sbus_conn_get_private_data(conn);

+     proxy_cli = talloc_get_type(data, struct proxy_client);

+     if (!proxy_cli) {

+         DEBUG(0, ("Connection holds no valid init data\n"));

+         return EINVAL;

+     }

+ 

+     /* First thing, cancel the timeout */

+     DEBUG(4, ("Cancel proxy client ID timeout [%p]\n", proxy_cli->timeout));

+     talloc_zfree(proxy_cli->timeout);

+ 

+     dbus_error_init(&dbus_error);

+ 

+     dbret = dbus_message_get_args(message, &dbus_error,

+                                   DBUS_TYPE_UINT16, &cli_ver,

+                                   DBUS_TYPE_UINT32, &cli_id,

+                                   DBUS_TYPE_INVALID);

+     if (!dbret) {

+         DEBUG(1, ("Failed to parse message, killing connection\n"));

+         if (dbus_error_is_set(&dbus_error)) dbus_error_free(&dbus_error);

+         sbus_disconnect(conn);

+         /* FIXME: should we just talloc_zfree(conn) ? */

+         return EIO;

+     }

+ 

+     DEBUG(4, ("Proxy client [%ld] connected\n", cli_id));

+ 

+     /* Check the hash table */

+     key.type = HASH_KEY_ULONG;

+     key.ul = cli_id;

+     if (!hash_has_key(proxy_cli->proxy_auth_ctx->request_table, &key)) {

+         DEBUG(1, ("Unknown child ID. Killing the connection\n"));

+         sbus_disconnect(proxy_cli->conn);

+         return EIO;

+     }

+ 

+     /* reply that all is ok */

+     reply = dbus_message_new_method_return(message);

+     if (!reply) {

+         DEBUG(0, ("Dbus Out of memory!\n"));

+         return ENOMEM;

+     }

+ 

+     dbret = dbus_message_append_args(reply,

+                                      DBUS_TYPE_UINT16, &version,

+                                      DBUS_TYPE_INVALID);

+     if (!dbret) {

+         DEBUG(0, ("Failed to build dbus reply\n"));

+         dbus_message_unref(reply);

+         sbus_disconnect(conn);

+         return EIO;

+     }

+ 

+     /* send reply back */

+     sbus_conn_send_reply(conn, reply);

+     dbus_message_unref(reply);

+ 

+     hret = hash_lookup(proxy_cli->proxy_auth_ctx->request_table, &key, &value);

+     if (hret != HASH_SUCCESS) {

+         DEBUG(1, ("Hash error [%d][%s]\n", hret, hash_error_string(hret)));

+         sbus_disconnect(conn);

+     }

+ 

+     /* Signal that the child is up and ready to receive the request */

+     req = talloc_get_type(value.ptr, struct tevent_req);

+     child_ctx = tevent_req_data(req, struct proxy_child_ctx);

+ 

+     if (!child_ctx->running) {

+         /* This should hopefully be impossible, but protect

+          * against it anyway. If we're not marked running, then

+          * the init_req will be NULL below and things will

+          * break.

+          */

+         DEBUG(1, ("Client connection from a request "

+                   "that's not marked as running\n"));

+         return EIO;

+     }

+ 

+     init_ctx = tevent_req_data(child_ctx->init_req, struct pc_init_ctx);

+     init_ctx->conn = conn;

+     tevent_req_done(child_ctx->init_req);

+     child_ctx->init_req = NULL;

+ 

+     return EOK;

+ }

+ 

  int sssm_proxy_auth_init(struct be_ctx *bectx,

                           struct bet_ops **ops, void **pvt_data)

  {

      struct proxy_auth_ctx *ctx;

      int ret;

+     int hret;

+     char *sbus_address;

  

-     ctx = talloc(bectx, struct proxy_auth_ctx);

+     /* If we're already set up, just return that */

+     if(bectx->bet_info[BET_AUTH].mod_name &&

+        strcmp("proxy", bectx->bet_info[BET_AUTH].mod_name) == 0) {

+         DEBUG(8, ("Re-using proxy_auth_ctx for this provider\n"));

+         *ops = bectx->bet_info[BET_AUTH].bet_ops;

+         *pvt_data = bectx->bet_info[BET_AUTH].pvt_bet_data;

+         return EOK;

+     }

+ 

+     ctx = talloc_zero(bectx, struct proxy_auth_ctx);

      if (!ctx) {

          return ENOMEM;

      }

      ctx->be = bectx;

+     ctx->timeout_ms = SSS_CLI_SOCKET_TIMEOUT/4;

+     ctx->next_id = 1;

  

      ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,

                              CONFDB_PROXY_PAM_TARGET, NULL,
@@ -2492,6 +3334,33 @@

          goto done;

      }

  

+     sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s", PIPE_PATH,

+                                    PROXY_CHILD_PIPE, bectx->domain->name);

+     if (sbus_address == NULL) {

+         DEBUG(1, ("talloc_asprintf failed.\n"));

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     ret = sbus_new_server(ctx, bectx->ev, sbus_address, &proxy_interface,

+                           &ctx->sbus_srv, proxy_client_init, ctx);

+     if (ret != EOK) {

+         DEBUG(0, ("Could not set up sbus server.\n"));

+         goto done;

+     }

+ 

+     /* Set up request hash table */

+     /* FIXME: get max_children from configuration file */

+     ctx->max_children = 10;

+ 

+     hret = hash_create(ctx->max_children * 2, &ctx->request_table,

+                        NULL, NULL);

+     if (hret != HASH_SUCCESS) {

+         DEBUG(0, ("Could not initialize request table\n"));

+         ret = EIO;

+         goto done;

+     }

+ 

      *ops = &proxy_auth_ops;

      *pvt_data = ctx;

  

@@ -0,0 +1,30 @@

+ /*

+     SSSD

+ 

+     Proxy provider, private header file

+ 

+     Authors:

+         Sumit Bose <sbose@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #ifndef __PROXY_H__

+ #define __PROXY_H__

+ 

+ #define PROXY_CHILD_PIPE "private/proxy_child"

+ 

+ #endif /* __PROXY_H__ */

@@ -0,0 +1,583 @@

+ /*

+     SSSD

+ 

+     Pam Proxy Child

+ 

+     Authors:

+ 

+         Sumit Bose <sbose@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include <stdio.h>

+ #include <unistd.h>

+ #include <fcntl.h>

+ #include <sys/types.h>

+ #include <sys/stat.h>

+ #include <sys/socket.h>

+ #include <sys/un.h>

+ #include <string.h>

+ #include <sys/time.h>

+ #include <errno.h>

+ #include <dlfcn.h>

+ 

+ #include <security/pam_appl.h>

+ #include <security/pam_modules.h>

+ 

+ #include "popt.h"

+ #include "util/util.h"

+ #include "confdb/confdb.h"

+ #include "db/sysdb.h"

+ #include "dbus/dbus.h"

+ #include "sbus/sssd_dbus.h"

+ #include "providers/proxy/proxy.h"

+ 

+ #include "providers/dp_backend.h"

+ 

+ static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn);

+ 

+ struct sbus_method pc_methods[] = {

+     { DP_METHOD_PAMHANDLER, pc_pam_handler },

+     { NULL, NULL }

+ };

+ 

+ struct sbus_interface pc_interface = {

+     DP_INTERFACE,

+     DP_PATH,

+     SBUS_DEFAULT_VTABLE,

+     pc_methods,

+     NULL

+ };

+ 

+ struct pc_ctx {

+     struct tevent_context *ev;

+     struct confdb_ctx *cdb;

+     struct sysdb_ctx *sysdb;

+     struct sss_domain_info *domain;

+     const char *identity;

+     const char *conf_path;

+     struct sbus_connection *mon_conn;

+     struct sbus_connection *conn;

+     const char *pam_target;

+     uint32_t id;

+ };

+ 

+ struct authtok_conv {

+     uint32_t authtok_size;

+     uint8_t *authtok;

+ 

+     uint32_t newauthtok_size;

+     uint8_t *newauthtok;

+ 

+     bool sent_old;

+ };

+ 

+ static int proxy_internal_conv(int num_msg, const struct pam_message **msgm,

+                             struct pam_response **response,

+                             void *appdata_ptr) {

+     int i;

+     struct pam_response *reply;

+     struct authtok_conv *auth_data;

+ 

+     auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);

+ 

+     if (num_msg <= 0) return PAM_CONV_ERR;

+ 

+     reply = (struct pam_response *) calloc(num_msg,

+                                            sizeof(struct pam_response));

+     if (reply == NULL) return PAM_CONV_ERR;

+ 

+     for (i=0; i < num_msg; i++) {

+         switch( msgm[i]->msg_style ) {

+             case PAM_PROMPT_ECHO_OFF:

+                 DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg));

+                 reply[i].resp_retcode = 0;

+                 reply[i].resp = calloc(auth_data->authtok_size + 1,

+                                        sizeof(char));

+                 if (reply[i].resp == NULL) goto failed;

+                 memcpy(reply[i].resp, auth_data->authtok,

+                        auth_data->authtok_size);

+ 

+                 break;

+             default:

+                 DEBUG(1, ("Conversation style %d not supported.\n",

+                            msgm[i]->msg_style));

+                 goto failed;

+         }

+     }

+ 

+     *response = reply;

+     reply = NULL;

+ 

+     return PAM_SUCCESS;

+ 

+ failed:

+     free(reply);

+     return PAM_CONV_ERR;

+ }

+ 

+ static int proxy_chauthtok_conv(int num_msg, const struct pam_message **msgm,

+                                 struct pam_response **response,

+                                 void *appdata_ptr) {

+     int i;

+     struct pam_response *reply;

+     struct authtok_conv *auth_data;

+ 

+     auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);

+ 

+     if (num_msg <= 0) return PAM_CONV_ERR;

+ 

+     reply = (struct pam_response *) calloc(num_msg,

+                                            sizeof(struct pam_response));

+     if (reply == NULL) return PAM_CONV_ERR;

+ 

+     for (i=0; i < num_msg; i++) {

+         switch( msgm[i]->msg_style ) {

+             case PAM_PROMPT_ECHO_OFF:

+                 DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg));

+ 

+                 reply[i].resp_retcode = 0;

+                 if (!auth_data->sent_old) {

+                     /* The first prompt will be asking for the old authtok */

+                     reply[i].resp = calloc(auth_data->authtok_size + 1,

+                                            sizeof(char));

+                     if (reply[i].resp == NULL) goto failed;

+                     memcpy(reply[i].resp, auth_data->authtok,

+                            auth_data->authtok_size);

+                     auth_data->sent_old = true;

+                 }

+                 else {

+                     /* Subsequent prompts are looking for the new authtok */

+                     reply[i].resp = calloc(auth_data->newauthtok_size + 1,

+                                            sizeof(char));

+                     if (reply[i].resp == NULL) goto failed;

+                     memcpy(reply[i].resp, auth_data->newauthtok,

+                            auth_data->newauthtok_size);

+                 }

+ 

+                 break;

+             default:

+                 DEBUG(1, ("Conversation style %d not supported.\n",

+                            msgm[i]->msg_style));

+                 goto failed;

+         }

+     }

+ 

+     *response = reply;

+     reply = NULL;

+ 

+     return PAM_SUCCESS;

+ 

+ failed:

+     free(reply);

+     return PAM_CONV_ERR;

+ }

+ 

+ static errno_t call_pam_stack(const char *pam_target, struct pam_data *pd)

+ {

+     int ret;

+     int pam_status;

+     pam_handle_t *pamh=NULL;

+     struct authtok_conv *auth_data;

+     struct pam_conv conv;

+ 

+     if (pd->cmd == SSS_PAM_CHAUTHTOK) {

+         conv.conv=proxy_chauthtok_conv;

+     }

+     else {

+         conv.conv=proxy_internal_conv;

+     }

+     auth_data = talloc_zero(pd, struct authtok_conv);

+     conv.appdata_ptr=auth_data;

+ 

+     ret = pam_start(pam_target, pd->user, &conv, &pamh);

+     if (ret == PAM_SUCCESS) {

+         DEBUG(7, ("Pam transaction started with service name [%s].\n",

+                   pam_target));

+         ret = pam_set_item(pamh, PAM_TTY, pd->tty);

+         if (ret != PAM_SUCCESS) {

+             DEBUG(1, ("Setting PAM_TTY failed: %s.\n",

+                       pam_strerror(pamh, ret)));

+         }

+         ret = pam_set_item(pamh, PAM_RUSER, pd->ruser);

+         if (ret != PAM_SUCCESS) {

+             DEBUG(1, ("Setting PAM_RUSER failed: %s.\n",

+                       pam_strerror(pamh, ret)));

+         }

+         ret = pam_set_item(pamh, PAM_RHOST, pd->rhost);

+         if (ret != PAM_SUCCESS) {

+             DEBUG(1, ("Setting PAM_RHOST failed: %s.\n",

+                       pam_strerror(pamh, ret)));

+         }

+         switch (pd->cmd) {

+             case SSS_PAM_AUTHENTICATE:

+                 auth_data->authtok_size = pd->authtok_size;

+                 auth_data->authtok = pd->authtok;

+                 pam_status = pam_authenticate(pamh, 0);

+                 break;

+             case SSS_PAM_SETCRED:

+                 pam_status=pam_setcred(pamh, 0);

+                 break;

+             case SSS_PAM_ACCT_MGMT:

+                 pam_status=pam_acct_mgmt(pamh, 0);

+                 break;

+             case SSS_PAM_OPEN_SESSION:

+                 pam_status=pam_open_session(pamh, 0);

+                 break;

+             case SSS_PAM_CLOSE_SESSION:

+                 pam_status=pam_close_session(pamh, 0);

+                 break;

+             case SSS_PAM_CHAUTHTOK:

+                 auth_data->authtok_size = pd->authtok_size;

+                 auth_data->authtok = pd->authtok;

+                 if (pd->priv != 1) {

+                     pam_status = pam_authenticate(pamh, 0);

+                     auth_data->sent_old = false;

+                     if (pam_status != PAM_SUCCESS) break;

+                 }

+                 auth_data->newauthtok_size = pd->newauthtok_size;

+                 auth_data->newauthtok = pd->newauthtok;

+                 pam_status = pam_chauthtok(pamh, 0);

+                 break;

+             case SSS_PAM_CHAUTHTOK_PRELIM:

+                 if (pd->priv != 1) {

+                     auth_data->authtok_size = pd->authtok_size;

+                     auth_data->authtok = pd->authtok;

+                     pam_status = pam_authenticate(pamh, 0);

+                 } else {

+                     pam_status = PAM_SUCCESS;

+                 }

+                 break;

+             default:

+                 DEBUG(1, ("unknown PAM call\n"));

+                 pam_status=PAM_ABORT;

+         }

+ 

+         DEBUG(4, ("Pam result: [%d][%s]\n", pam_status,

+                   pam_strerror(pamh, pam_status)));

+ 

+         ret = pam_end(pamh, pam_status);

+         if (ret != PAM_SUCCESS) {

+             pamh=NULL;

+             DEBUG(1, ("Cannot terminate pam transaction.\n"));

+         }

+ 

+     } else {

+         DEBUG(1, ("Failed to initialize pam transaction.\n"));

+         pam_status = PAM_SYSTEM_ERR;

+     }

+ 

+     pd->pam_status = pam_status;

+ 

+     return EOK;

+ }

+ 

+ static int pc_pam_handler(DBusMessage *message, struct sbus_connection *conn)

+ {

+     DBusError dbus_error;

+     DBusMessage *reply;

+     struct pc_ctx *pc_ctx;

+     errno_t ret;

+     void *user_data;

+     struct pam_data *pd = NULL;

+ 

+     user_data = sbus_conn_get_private_data(conn);

+     if (!user_data) {

+         ret = EINVAL;

+         goto done;

+     }

+     pc_ctx = talloc_get_type(user_data, struct pc_ctx);

+     if (!pc_ctx) {

+         ret = EINVAL;

+         goto done;

+     }

+ 

+     reply = dbus_message_new_method_return(message);

+     if (!reply) {

+         DEBUG(1, ("dbus_message_new_method_return failed, "

+                   "cannot send reply.\n"));

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     dbus_error_init(&dbus_error);

+ 

+     ret = dp_unpack_pam_request(message, pc_ctx, &pd, &dbus_error);

+     if (!ret) {

+         DEBUG(1,("Failed, to parse message!\n"));

+         ret = EIO;

+         goto done;

+     }

+ 

+     pd->pam_status = PAM_SYSTEM_ERR;

+     pd->domain = talloc_strdup(pd, pc_ctx->domain->name);

+     if (pd->domain == NULL) {

+         talloc_free(pd);

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+     DEBUG(4, ("Got request with the following data\n"));

+     DEBUG_PAM_DATA(4, pd);

+ 

+     ret = call_pam_stack(pc_ctx->pam_target, pd);

+     if (ret != EOK) {

+         DEBUG(1, ("call_pam_stack failed.\n"));

+     }

+ 

+     DEBUG(4, ("Sending result [%d][%s]\n",

+               pd->pam_status, pd->domain));

+ 

+     ret = dp_pack_pam_response(reply, pd);

+     if (!ret) {

+         DEBUG(1, ("Failed to generate dbus reply\n"));

+         talloc_free(pd);

+         dbus_message_unref(reply);

+         ret = EIO;

+         goto done;

+     }

+ 

+     sbus_conn_send_reply(conn, reply);

+     dbus_message_unref(reply);

+     talloc_free(pd);

+ 

+     /* We'll return the message and let the

+      * parent process kill us.

+      */

+     return EOK;

+ 

+ done:

+     exit(ret);

+ }

+ 

+ int proxy_child_send_id(struct sbus_connection *conn,

+                         uint16_t version,

+                         uint32_t id);

+ static int proxy_cli_init(struct pc_ctx *ctx)

+ {

+     char *sbus_address;

+     int ret;

+ 

+     sbus_address = talloc_asprintf(ctx, "unix:path=%s/%s_%s",

+                                       PIPE_PATH, PROXY_CHILD_PIPE,

+                                       ctx->domain->name);

+     if (sbus_address == NULL) {

+         DEBUG(1, ("talloc_asprintf failed.\n"));

+         return ENOMEM;

+     }

+ 

+     ret = sbus_client_init(ctx, ctx->ev, sbus_address,

+                            &pc_interface, &ctx->conn,

+                            NULL, ctx);

+     if (ret != EOK) {

+         DEBUG(1, ("sbus_client_init failed.\n"));

+         return ret;

+     }

+ 

+     ret = proxy_child_send_id(ctx->conn, DATA_PROVIDER_VERSION, ctx->id);

+     if (ret != EOK) {

+         DEBUG(0, ("dp_common_send_id failed.\n"));

+         return ret;

+     }

+ 

+     return EOK;

+ }

+ 

+ int proxy_child_send_id(struct sbus_connection *conn,

+                         uint16_t version,

+                         uint32_t id)

+ {

+     DBusMessage *msg;

+     dbus_bool_t ret;

+     int retval;

+ 

+     /* create the message */

+     msg = dbus_message_new_method_call(NULL,

+                                        DP_PATH,

+                                        DP_INTERFACE,

+                                        DP_METHOD_REGISTER);

+     if (msg == NULL) {

+         DEBUG(0, ("Out of memory?!\n"));

+         return ENOMEM;

+     }

+ 

+     DEBUG(4, ("Sending ID to Proxy Backend: (%d,%ld)\n",

+               version, id));

+ 

+     ret = dbus_message_append_args(msg,

+                                    DBUS_TYPE_UINT16, &version,

+                                    DBUS_TYPE_UINT32, &id,

+                                    DBUS_TYPE_INVALID);

+     if (!ret) {

+         DEBUG(1, ("Failed to build message\n"));

+         return EIO;

+     }

+ 

+     retval = sbus_conn_send(conn, msg, 30000, dp_id_callback, NULL, NULL);

+ 

+     dbus_message_unref(msg);

+     return retval;

+ }

+ 

+ int proxy_child_process_init(TALLOC_CTX *mem_ctx, const char *domain,

+                              struct tevent_context *ev, struct confdb_ctx *cdb,

+                              const char *pam_target, uint32_t id)

+ {

+     struct pc_ctx *ctx;

+     int ret;

+ 

+     ctx = talloc_zero(mem_ctx, struct pc_ctx);

+     if (!ctx) {

+         DEBUG(0, ("fatal error initializing pc_ctx\n"));

+         return ENOMEM;

+     }

+     ctx->ev = ev;

+     ctx->cdb = cdb;

+     ctx->pam_target = talloc_steal(ctx, pam_target);

+     ctx->id = id;

+     ctx->conf_path = talloc_asprintf(ctx, CONFDB_DOMAIN_PATH_TMPL, domain);

+     if (!ctx->conf_path) {

+         DEBUG(0, ("Out of memory!?\n"));

+         return ENOMEM;

+     }

+ 

+     ret = confdb_get_domain(cdb, domain, &ctx->domain);

+     if (ret != EOK) {

+         DEBUG(0, ("fatal error retrieving domain configuration\n"));

+         return ret;

+     }

+ 

+     ret = sysdb_domain_init(ctx, ev, ctx->domain, DB_PATH, &ctx->sysdb);

+     if (ret != EOK) {

+         DEBUG(0, ("fatal error opening cache database\n"));

+         return ret;

+     }

+ 

+     ret = proxy_cli_init(ctx);

+     if (ret != EOK) {

+         DEBUG(0, ("fatal error setting up server bus\n"));

+         return ret;

+     }

+ 

+     return EOK;

+ }

+ 

+ int main(int argc, const char *argv[])

+ {

+     int opt;

+     poptContext pc;

+     char *domain = NULL;

+     char *srv_name = NULL;

+     char *conf_entry = NULL;

+     struct main_context *main_ctx;

+     int ret;

+     long id;

+     char *pam_target = NULL;

+ 

+     struct poptOption long_options[] = {

+         POPT_AUTOHELP

+         SSSD_MAIN_OPTS

+         {"domain", 0, POPT_ARG_STRING, &domain, 0,

+          _("Domain of the information provider (mandatory)"), NULL },

+         {"id", 0, POPT_ARG_LONG, &id, 0,

+          _("Child identifier (mandatory)"), NULL },

+         POPT_TABLEEND

+     };

+ 

+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);

+     while((opt = poptGetNextOpt(pc)) != -1) {

+         switch(opt) {

+         default:

+         fprintf(stderr, "\nInvalid option %s: %s\n\n",

+                   poptBadOption(pc, 0), poptStrerror(opt));

+             poptPrintUsage(pc, stderr, 0);

+             return 1;

+         }

+     }

+ 

+     if (domain == NULL) {

+         fprintf(stderr, "\nMissing option, "

+                         "--domain is a mandatory option.\n\n");

+             poptPrintUsage(pc, stderr, 0);

+             return 1;

+     }

+ 

+     if (id == 0) {

+         fprintf(stderr, "\nMissing option, "

+                         "--id is a mandatory option.\n\n");

+             poptPrintUsage(pc, stderr, 0);

+             return 1;

+     }

+ 

+     poptFreeContext(pc);

+ 

+ 

+     /* set up things like debug , signals, daemonization, etc... */

+     debug_log_file = talloc_asprintf(NULL, "proxy_child_%s", domain);

+     if (!debug_log_file) return 2;

+ 

+     srv_name = talloc_asprintf(NULL, "sssd[proxy_child[%s]]", domain);

+     if (!srv_name) return 2;

+ 

+     conf_entry = talloc_asprintf(NULL, CONFDB_DOMAIN_PATH_TMPL, domain);

+     if (!conf_entry) return 2;

+ 

+     ret = server_setup(srv_name, 0, conf_entry, &main_ctx);

+     if (ret != EOK) {

+         DEBUG(0, ("Could not set up mainloop [%d]\n", ret));

+         return 2;

+     }

+ 

+     ret = unsetenv("_SSS_LOOPS");

+     if (ret != EOK) {

+         DEBUG(1, ("Failed to unset _SSS_LOOPS, "

+                   "pam modules might not work as expected.\n"));

+     }

+ 

+     ret = confdb_get_string(main_ctx->confdb_ctx, main_ctx, conf_entry,

+                             CONFDB_PROXY_PAM_TARGET, NULL, &pam_target);

+     if (ret != EOK) {

+         DEBUG(0, ("Error reading from confdb (%d) [%s]\n",

+                   ret, strerror(ret)));

+         return 4;

+     }

+     if (pam_target == NULL) {

+         DEBUG(1, ("Missing option proxy_pam_target.\n"));

+         return 4;

+     }

+ 

+     ret = die_if_parent_died();

+     if (ret != EOK) {

+         /* This is not fatal, don't return */

+         DEBUG(2, ("Could not set up to exit when parent process does\n"));

+     }

+ 

+     ret = proxy_child_process_init(main_ctx, domain, main_ctx->event_ctx,

+                                    main_ctx->confdb_ctx, pam_target,

+                                    (uint32_t)id);

+     if (ret != EOK) {

+         DEBUG(0, ("Could not initialize proxy child [%d].\n", ret));

+         return 3;

+     }

+ 

+     DEBUG(1, ("Proxy child for domain [%s] started!\n", domain));

+ 

+     /* loop on main */

+     server_loop(main_ctx);

+ 

+     return 0;

+ }

file modified
+254 -7
@@ -325,7 +325,7 @@

      DEBUG(4, ("Initializing new c-ares channel\n"));

      /* FIXME: the options would contain

       * the nameservers to contact, the domains

-      * to search, timeout... => get from confdb

+      * to search... => get from confdb

       */

      options.sock_state_cb = fd_event;

      options.sock_state_cb_data = ctx;
@@ -358,6 +358,10 @@

      int ret;

      struct resolv_ctx *ctx;

  

+     if (timeout < 1) {

+         return EINVAL;

+     }

+ 

      ctx = talloc_zero(mem_ctx, struct resolv_ctx);

      if (ctx == NULL)

          return ENOMEM;
@@ -661,11 +665,6 @@

                         state->family, resolv_gethostbyname_done, req);

  }

  

- /* SRV and TXT parsing is not used anywhere in the code yet, so we disable it

-  * for now

-  */

- #ifdef BUILD_TXT_SRV

- 

  /*

   * A simple helper function that will take an array of struct ares_srv_reply that

   * was allocated by malloc() in c-ares and copies it using talloc. The old one
@@ -804,7 +803,6 @@

      state->timeouts = timeouts;

  

      if (status != ARES_SUCCESS) {

-         tevent_req_error(req, return_code(status));

          ret = return_code(status);

          goto fail;

      }
@@ -870,6 +868,11 @@

                 ns_c_in, ns_t_srv, resolv_getsrv_done, req);

  }

  

+ /* TXT parsing is not used anywhere in the code yet, so we disable it

+  * for now

+  */

+ #ifdef BUILD_TXT

+ 

  /*

   * A simple helper function that will take an array of struct txt_reply that

   * was allocated by malloc() in c-ares and copies it using talloc. The old one
@@ -1074,3 +1077,247 @@

  }

  

  #endif

+ 

+ static struct ares_srv_reply *split_reply_list(struct ares_srv_reply *list)

+ {

+     struct ares_srv_reply *single_step, *double_step, *prev;

+ 

+     if (!list) {

+         return NULL;

+     }

+ 

+     prev        = list;

+     single_step = list->next;

+     double_step = single_step->next;

+ 

+     while (double_step && double_step->next) {

+         prev = single_step;

+         single_step = single_step->next;

+         double_step = double_step->next->next;

+     }

+ 

+     prev->next = NULL;

+     return single_step;

+ }

+ 

+ static struct ares_srv_reply *merge_reply_list(struct ares_srv_reply *left,

+                                                struct ares_srv_reply *right)

+ {

+     struct ares_srv_reply *l, *r;

+     struct ares_srv_reply *res, *res_start;

+ 

+     if (!left)

+         return right;

+     if (!right)

+         return left;

+ 

+     if (left->priority < right->priority) {

+         res_start = left;

+         l = left->next;

+         r = right;

+     } else {

+         res_start = right;

+         l = left;

+         r = right->next;

+     }

+ 

+     res = res_start;

+ 

+     while(l && r) {

+         if (l->priority < r->priority) {

+             res->next = l;

+             res = l;

+             l = l->next;

+         } else {

+             res->next = r;

+             res = r;

+             r = r->next;

+         }

+     }

+ 

+     res->next = l ? l : r;

+ 

+     return res_start;

+ }

+ 

+ /**

+  * sort linked list of struct ares_srv_reply by priority using merge sort.

+  *

+  * Merge sort is ideal for sorting linked lists as there is no problem

+  * with absence of random access into the list. The complexity is O(n log n)

+  *

+  * For reference, see Robert Sedgewick's "Algorithms in C", Addison-Wesley,

+  * ISBN 0-201-51425

+  */

+ static struct ares_srv_reply *reply_priority_sort(struct ares_srv_reply *list)

+ {

+     struct ares_srv_reply *half;

+ 

+     if (!list || !list->next)

+         return list;

+ 

+     half = split_reply_list(list);

+     list = merge_reply_list(reply_priority_sort(list),

+                             reply_priority_sort(half));

+ 

+     return list;

+ }

+ 

+ static int reply_weight_rearrange(TALLOC_CTX *mem_ctx,

+                                   int len,

+                                   struct ares_srv_reply **start,

+                                   struct ares_srv_reply **end)

+ {

+     int i;

+     int total, selected;

+     int *totals;

+     struct ares_srv_reply *r, *prev, *tmp;

+     struct ares_srv_reply *new_start = NULL;

+     struct ares_srv_reply *new_end = NULL;

+ 

+     if (len <= 1) {

+         return EOK;

+     }

+ 

+     totals = talloc_array(mem_ctx, int, len);

+     if (!totals) {

+         return ENOMEM;

+     }

+ 

+     srand(time(NULL) * getpid());

+ 

+     /* promote all servers with weight==0 to the top */

+     r = *(start);

+     prev = NULL;

+     while (r != NULL) {

+         if (r->weight == 0) {

+             /* remove from the old list */

+             if (prev) {

+                 prev->next = r->next;

+             } else {

+                 *start = r->next;

+             }

+ 

+             /* add to the head of the new list */

+             tmp = r;

+             r = r->next;

+ 

+             tmp->next = *start;

+             *start = tmp;

+         } else {

+             prev = r;

+             r = r->next;

+         }

+     }

+     *end = prev ? prev : *start;

+ 

+     while (*start != NULL) {

+         /* Commpute the sum of the weights of those RRs, and with each RR

+          * associate the running sum in the selected order.

+          */

+         total = 0;

+         memset(totals, -1, sizeof(int) * len);

+         for (i = 0, r = *start; r != NULL; r=r->next, ++i) {

+             totals[i] = r->weight + total;

+             total = totals[i];

+         }

+ 

+         /* choose a  uniform random number between 0 and the sum computed

+          * (inclusive), and select the RR whose running sum value is the

+          * first in the selected order which is greater than or equal to

+          * the random number selected.

+          */

+         selected = (int)((total + 1) * (rand()/(RAND_MAX + 1.0)));

+         for (i = 0, r = *start, prev = NULL; r != NULL; r=r->next, ++i) {

+             if (totals[i] >= selected)

+                 break;

+ 

+             prev = r;

+         }

+ 

+         if (r == NULL || totals[i] == -1) {

+             DEBUG(1, ("Bug: did not select any server!\n"));

+             return EIO;

+         }

+ 

+         /* remove r from the old list */

+         if (prev) {

+             prev->next = r->next;

+         } else {

+             *start = r->next;

+         }

+ 

+         /* add r to the end of the new list */

+         if (!new_start) {

+             new_start = r;

+             new_end = r;

+         } else {

+             new_end->next = r;

+             new_end = r;

+         }

+     }

+     new_end->next = NULL;

+ 

+     /* return the rearranged list */

+     *start = new_start;

+     *end = new_end;

+     talloc_free(totals);

+     return EOK;

+ }

+ 

+ int

+ resolv_sort_srv_reply(TALLOC_CTX *mem_ctx, struct ares_srv_reply **reply)

+ {

+     int ret;

+     struct ares_srv_reply *pri_start, *pri_end, *next, *prev_end;

+     int len;

+ 

+     /* RFC 2782 says: If there is precisely one SRV RR, and its Target is "."

+      * (the root domain), abort.

+      */

+     if (*reply && !(*reply)->next && strcmp((*reply)->host, ".") == 0) {

+         DEBUG(1, ("DNS returned only the root domain, aborting\n"));

+         return EIO;

+     }

+ 

+     /* sort the list by priority */

+     *reply = reply_priority_sort(*reply);

+ 

+     pri_start = *reply;

+     prev_end  = NULL;

+ 

+     while (pri_start) {

+         pri_end = pri_start;

+ 

+         /* Find nodes with the same priority */

+         len = 1;

+         while (pri_end->next && pri_end->priority == pri_end->next->priority) {

+             pri_end = pri_end->next;

+             len++;

+         }

+ 

+         /* rearrange each priority level according to the weight field */

+         next = pri_end->next;

+         pri_end->next = NULL;

+         ret = reply_weight_rearrange(mem_ctx, len, &pri_start, &pri_end);

+         if (ret) {

+             DEBUG(1, ("Error rearranging priority level [%d]: %s\n",

+                       ret, strerror(ret)));

+             return ret;

+         }

+ 

+         /* Hook the level back into the list */

+         if (prev_end) {

+             prev_end->next = pri_start;

+         } else {

+             *reply = pri_start;

+         }

+         pri_end->next = next;

+ 

+         /* Move on to the next level */

+         prev_end  = pri_end;

+         pri_start = next;

+     }

+ 

+     return EOK;

+ }

@@ -88,6 +88,10 @@

                         int *timeouts,

                         struct ares_srv_reply **reply_list);

  

+ /* This is an implementation of section "Usage rules" of RFC 2782 */

+ int

+ resolv_sort_srv_reply(TALLOC_CTX *mem_ctx, struct ares_srv_reply **reply);

+ 

  /** Get TXT record **/

  struct tevent_req *resolv_gettxt_send(TALLOC_CTX *mem_ctx,

                                        struct tevent_context *ev,

src/responder/common/negcache.c src/responder/nss/nsssrv_nc.c
file renamed
+230 -23
@@ -20,6 +20,7 @@

  */

  

  #include "util/util.h"

+ #include "confdb/confdb.h"

  #include <fcntl.h>

  #include <time.h>

  #include "tdb.h"
@@ -30,7 +31,7 @@

  #define NC_UID_PREFIX NC_ENTRY_PREFIX"UID"

  #define NC_GID_PREFIX NC_ENTRY_PREFIX"GID"

  

- struct nss_nc_ctx {

+ struct sss_nc_ctx {

      struct tdb_context *tdb;

  };

  
@@ -44,11 +45,11 @@

      return EOK;

  }

  

- int nss_ncache_init(TALLOC_CTX *memctx, struct nss_nc_ctx **_ctx)

+ int sss_ncache_init(TALLOC_CTX *memctx, struct sss_nc_ctx **_ctx)

  {

-     struct nss_nc_ctx *ctx;

+     struct sss_nc_ctx *ctx;

  

-     ctx = talloc_zero(memctx, struct nss_nc_ctx);

+     ctx = talloc_zero(memctx, struct sss_nc_ctx);

      if (!ctx) return ENOMEM;

  

      errno = 0;
@@ -60,7 +61,7 @@

      return EOK;

  };

  

- static int nss_ncache_check_str(struct nss_nc_ctx *ctx, char *str, int ttl)

+ static int sss_ncache_check_str(struct sss_nc_ctx *ctx, char *str, int ttl)

  {

      TDB_DATA key;

      TDB_DATA data;
@@ -117,7 +118,7 @@

      return ret;

  }

  

- static int nss_ncache_set_str(struct nss_nc_ctx *ctx,

+ static int sss_ncache_set_str(struct sss_nc_ctx *ctx,

                                char *str, bool permanent)

  {

      TDB_DATA key;
@@ -151,7 +152,7 @@

      return ret;

  }

  

- int nss_ncache_check_user(struct nss_nc_ctx *ctx, int ttl,

+ int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,

                            const char *domain, const char *name)

  {

      char *str;
@@ -162,13 +163,13 @@

      str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_check_str(ctx, str, ttl);

+     ret = sss_ncache_check_str(ctx, str, ttl);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_check_group(struct nss_nc_ctx *ctx, int ttl,

+ int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,

                             const char *domain, const char *name)

  {

      char *str;
@@ -179,13 +180,13 @@

      str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_check_str(ctx, str, ttl);

+     ret = sss_ncache_check_str(ctx, str, ttl);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_check_uid(struct nss_nc_ctx *ctx, int ttl, uid_t uid)

+ int sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, uid_t uid)

  {

      char *str;

      int ret;
@@ -193,13 +194,13 @@

      str = talloc_asprintf(ctx, "%s/%u", NC_UID_PREFIX, uid);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_check_str(ctx, str, ttl);

+     ret = sss_ncache_check_str(ctx, str, ttl);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_check_gid(struct nss_nc_ctx *ctx, int ttl, gid_t gid)

+ int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid)

  {

      char *str;

      int ret;
@@ -207,13 +208,13 @@

      str = talloc_asprintf(ctx, "%s/%u", NC_GID_PREFIX, gid);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_check_str(ctx, str, ttl);

+     ret = sss_ncache_check_str(ctx, str, ttl);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_set_user(struct nss_nc_ctx *ctx, bool permanent,

+ int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,

                          const char *domain, const char *name)

  {

      char *str;
@@ -224,13 +225,13 @@

      str = talloc_asprintf(ctx, "%s/%s/%s", NC_USER_PREFIX, domain, name);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_set_str(ctx, str, permanent);

+     ret = sss_ncache_set_str(ctx, str, permanent);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_set_group(struct nss_nc_ctx *ctx, bool permanent,

+ int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,

                          const char *domain, const char *name)

  {

      char *str;
@@ -241,13 +242,13 @@

      str = talloc_asprintf(ctx, "%s/%s/%s", NC_GROUP_PREFIX, domain, name);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_set_str(ctx, str, permanent);

+     ret = sss_ncache_set_str(ctx, str, permanent);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_set_uid(struct nss_nc_ctx *ctx, bool permanent, uid_t uid)

+ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, uid_t uid)

  {

      char *str;

      int ret;
@@ -255,13 +256,13 @@

      str = talloc_asprintf(ctx, "%s/%u", NC_UID_PREFIX, uid);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_set_str(ctx, str, permanent);

+     ret = sss_ncache_set_str(ctx, str, permanent);

  

      talloc_free(str);

      return ret;

  }

  

- int nss_ncache_set_gid(struct nss_nc_ctx *ctx, bool permanent, gid_t gid)

+ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, gid_t gid)

  {

      char *str;

      int ret;
@@ -269,7 +270,7 @@

      str = talloc_asprintf(ctx, "%s/%u", NC_GID_PREFIX, gid);

      if (!str) return ENOMEM;

  

-     ret = nss_ncache_set_str(ctx, str, permanent);

+     ret = sss_ncache_set_str(ctx, str, permanent);

  

      talloc_free(str);

      return ret;
@@ -309,7 +310,7 @@

      return 0;

  }

  

- int nss_ncache_reset_permament(struct nss_nc_ctx *ctx)

+ int sss_ncache_reset_permament(struct sss_nc_ctx *ctx)

  {

      int ret;

  
@@ -319,3 +320,209 @@

  

      return EOK;

  }

+ 

+ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,

+                                struct confdb_ctx *cdb,

+                                struct sss_names_ctx *names_ctx,

+                                struct sss_domain_info *domain_list)

+ {

+     errno_t ret;

+     bool filter_set = false;

+     char **filter_list = NULL;

+     char *name = NULL;

+     struct sss_domain_info *dom = NULL;

+     char *domainname = NULL;

+     char *conf_path = NULL;

+     TALLOC_CTX *tmpctx = talloc_new(NULL);

+     int i;

+ 

+     /* Populate domain-specific negative cache entries */

+     for (dom = domain_list; dom; dom = dom->next) {

+         conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL,

+                                     dom->name);

+         if (!conf_path) {

+             ret = ENOMEM;

+             goto done;

+         }

+ 

+         talloc_zfree(filter_list);

+         ret = confdb_get_string_as_list(cdb, tmpctx, conf_path,

+                                         CONFDB_NSS_FILTER_USERS,

+                                         &filter_list);

+         if (ret == ENOENT) continue;

+         if (ret != EOK) goto done;

+         filter_set = true;

+ 

+         for (i = 0; (filter_list && filter_list[i]); i++) {

+             ret = sss_parse_name(tmpctx, names_ctx, filter_list[i],

+                                  &domainname, &name);

+             if (ret != EOK) {

+                 DEBUG(1, ("Invalid name in filterUsers list: [%s] (%d)\n",

+                          filter_list[i], ret));

+                 continue;

+             }

+ 

+             if (domainname && strcmp(domainname, dom->name)) {

+                 DEBUG(1, ("Mismatch between domain name (%s) and name "

+                           "set in FQN  (%s), skipping user %s\n",

+                           dom->name, domainname, name));

+                 continue;

+             }

+ 

+             ret = sss_ncache_set_user(ncache, true, dom->name, name);

+             if (ret != EOK) {

+                 DEBUG(1, ("Failed to store permanent user filter for [%s]"

+                           " (%d [%s])\n", filter_list[i],

+                           ret, strerror(ret)));

+                 continue;

+             }

+         }

+     }

+ 

+     ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY,

+                                     CONFDB_NSS_FILTER_USERS, &filter_list);

+     if (ret == ENOENT) {

+         if (!filter_set) {

+             filter_list = talloc_array(tmpctx, char *, 2);

+             if (!filter_list) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+             filter_list[0] = talloc_strdup(tmpctx, "root");

+             if (!filter_list[0]) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+             filter_list[1] = NULL;

+         }

+         ret = EOK;

+     }

+     else if (ret != EOK) goto done;

+ 

+     for (i = 0; (filter_list && filter_list[i]); i++) {

+         ret = sss_parse_name(tmpctx, names_ctx, filter_list[i],

+                              &domainname, &name);

+         if (ret != EOK) {

+             DEBUG(1, ("Invalid name in filterUsers list: [%s] (%d)\n",

+                      filter_list[i], ret));

+             continue;

+         }

+         if (domainname) {

+             ret = sss_ncache_set_user(ncache, true, domainname, name);

+             if (ret != EOK) {

+                 DEBUG(1, ("Failed to store permanent user filter for [%s]"

+                           " (%d [%s])\n", filter_list[i],

+                           ret, strerror(ret)));

+                 continue;

+             }

+         } else {

+             for (dom = domain_list; dom; dom = dom->next) {

+                 ret = sss_ncache_set_user(ncache, true, dom->name, name);

+                 if (ret != EOK) {

+                    DEBUG(1, ("Failed to store permanent user filter for"

+                              " [%s:%s] (%d [%s])\n",

+                              dom->name, filter_list[i],

+                              ret, strerror(ret)));

+                     continue;

+                 }

+             }

+         }

+     }

+ 

+     filter_set = false;

+     for (dom = domain_list; dom; dom = dom->next) {

+         conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name);

+         if (!conf_path) {

+             ret = ENOMEM;

+             goto done;

+         }

+ 

+         talloc_zfree(filter_list);

+         ret = confdb_get_string_as_list(cdb, tmpctx, conf_path,

+                                         CONFDB_NSS_FILTER_GROUPS, &filter_list);

+         if (ret == ENOENT) continue;

+         if (ret != EOK) goto done;

+         filter_set = true;

+ 

+         for (i = 0; (filter_list && filter_list[i]); i++) {

+             ret = sss_parse_name(tmpctx, names_ctx, filter_list[i],

+                                  &domainname, &name);

+             if (ret != EOK) {

+                 DEBUG(1, ("Invalid name in filterGroups list: [%s] (%d)\n",

+                          filter_list[i], ret));

+                 continue;

+             }

+ 

+             if (domainname && strcmp(domainname, dom->name)) {

+                 DEBUG(1, ("Mismatch betwen domain name (%s) and name "

+                           "set in FQN  (%s), skipping group %s\n",

+                           dom->name, domainname, name));

+                 continue;

+             }

+ 

+             ret = sss_ncache_set_group(ncache, true, dom->name, name);

+             if (ret != EOK) {

+                 DEBUG(1, ("Failed to store permanent group filter for [%s]"

+                           " (%d [%s])\n", filter_list[i],

+                           ret, strerror(ret)));

+                 continue;

+             }

+         }

+     }

+ 

+     ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY,

+                                     CONFDB_NSS_FILTER_GROUPS, &filter_list);

+     if (ret == ENOENT) {

+         if (!filter_set) {

+             filter_list = talloc_array(tmpctx, char *, 2);

+             if (!filter_list) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+             filter_list[0] = talloc_strdup(tmpctx, "root");

+             if (!filter_list[0]) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+             filter_list[1] = NULL;

+         }

+         ret = EOK;

+     }

+     else if (ret != EOK) goto done;

+ 

+     for (i = 0; (filter_list && filter_list[i]); i++) {

+         ret = sss_parse_name(tmpctx, names_ctx, filter_list[i],

+                              &domainname, &name);

+         if (ret != EOK) {

+             DEBUG(1, ("Invalid name in filterGroups list: [%s] (%d)\n",

+                      filter_list[i], ret));

+             continue;

+         }

+         if (domainname) {

+             ret = sss_ncache_set_group(ncache, true, domainname, name);

+             if (ret != EOK) {

+                 DEBUG(1, ("Failed to store permanent group filter for"

+                           " [%s] (%d [%s])\n", filter_list[i],

+                           ret, strerror(ret)));

+                 continue;

+             }

+         } else {

+             for (dom = domain_list; dom; dom = dom->next) {

+                 ret = sss_ncache_set_group(ncache, true, dom->name, name);

+                 if (ret != EOK) {

+                    DEBUG(1, ("Failed to store permanent group filter for"

+                              " [%s:%s] (%d [%s])\n",

+                              dom->name, filter_list[i],

+                              ret, strerror(ret)));

+                     continue;

+                 }

+             }

+         }

+     }

+ 

+     ret = EOK;

+ 

+ done:

+     talloc_free(tmpctx);

+     return ret;

+ }

src/responder/common/negcache.h src/responder/nss/nsssrv_nc.h
file renamed
+20 -12
@@ -22,30 +22,38 @@

  #ifndef _NSS_NEG_CACHE_H_

  #define _NSS_NEG_CACHE_H_

  

- struct nss_nc_ctx;

+ struct sss_nc_ctx;

  

  /* init the in memory negative cache */

- int nss_ncache_init(TALLOC_CTX *memctx, struct nss_nc_ctx **_ctx);

+ int sss_ncache_init(TALLOC_CTX *memctx, struct sss_nc_ctx **_ctx);

  

  /* check if the user is expired according to the passed in time to live */

- int nss_ncache_check_user(struct nss_nc_ctx *ctx, int ttl,

+ int sss_ncache_check_user(struct sss_nc_ctx *ctx, int ttl,

                            const char *domain, const char *name);

- int nss_ncache_check_group(struct nss_nc_ctx *ctx, int ttl,

+ int sss_ncache_check_group(struct sss_nc_ctx *ctx, int ttl,

                            const char *domain, const char *name);

- int nss_ncache_check_uid(struct nss_nc_ctx *ctx, int ttl, uid_t uid);

- int nss_ncache_check_gid(struct nss_nc_ctx *ctx, int ttl, gid_t gid);

+ int sss_ncache_check_uid(struct sss_nc_ctx *ctx, int ttl, uid_t uid);

+ int sss_ncache_check_gid(struct sss_nc_ctx *ctx, int ttl, gid_t gid);

  

  /* add a new neg-cache entry setting the timestamp to "now" unless

   * "permanent" is set to true, in which case the timestamps is set to 0

   * and the negative cache never expires (used to permanently filter out

   * users and groups) */

- int nss_ncache_set_user(struct nss_nc_ctx *ctx, bool permanent,

+ int sss_ncache_set_user(struct sss_nc_ctx *ctx, bool permanent,

                          const char *domain, const char *name);

- int nss_ncache_set_group(struct nss_nc_ctx *ctx, bool permanent,

+ int sss_ncache_set_group(struct sss_nc_ctx *ctx, bool permanent,

                          const char *domain, const char *name);

- int nss_ncache_set_uid(struct nss_nc_ctx *ctx, bool permanent, uid_t uid);

- int nss_ncache_set_gid(struct nss_nc_ctx *ctx, bool permanent, gid_t gid);

- 

- int nss_ncache_reset_permament(struct nss_nc_ctx *ctx);

+ int sss_ncache_set_uid(struct sss_nc_ctx *ctx, bool permanent, uid_t uid);

+ int sss_ncache_set_gid(struct sss_nc_ctx *ctx, bool permanent, gid_t gid);

+ 

+ int sss_ncache_reset_permament(struct sss_nc_ctx *ctx);

+ 

+ /* Set up the negative cache with values from filter_users and

+  * filter_groups in the sssd.conf

+  */

+ errno_t sss_ncache_prepopulate(struct sss_nc_ctx *ncache,

+                                struct confdb_ctx *cdb,

+                                struct sss_names_ctx *names_ctx,

+                                struct sss_domain_info *domain_list);

  

  #endif /* _NSS_NEG_CACHE_H_ */

@@ -101,10 +101,9 @@

      struct cli_request *creq;

      struct cli_protocol_version *cli_protocol_version;

      int priv;

-     int creds_exchange_done;

-     int client_uid;

-     int client_gid;

-     int client_pid;

+     int32_t client_euid;

+     int32_t client_egid;

+     int32_t client_pid;

  };

  

  struct sss_cmd_table {
@@ -147,6 +146,8 @@

  typedef void (*sss_dp_callback_t)(uint16_t err_maj, uint32_t err_min,

                                    const char *err_msg, void *ptr);

  

+ void handle_requests_after_reconnect(void);

+ 

  int sss_dp_send_acct_req(struct resp_ctx *rctx, TALLOC_CTX *callback_memctx,

                           sss_dp_callback_t callback, void *callback_ctx,

                           int timeout, const char *domain,

@@ -65,6 +65,40 @@

      return 0;

  }

  

+ static errno_t get_client_cred(struct cli_ctx *cctx)

+ {

+ #ifdef HAVE_UCRED

+     int ret;

+     struct ucred client_cred;

+     socklen_t client_cred_len = sizeof(client_cred);

+ 

+     cctx->client_euid = -1;

+     cctx->client_egid = -1;

+     cctx->client_pid = -1;

+ 

+     ret = getsockopt(cctx->cfd, SOL_SOCKET, SO_PEERCRED, &client_cred,

+                      &client_cred_len);

+     if (ret != EOK) {

+         ret = errno;

+         DEBUG(1, ("getsock failed [%d][%s].\n", ret, strerror(ret)));

+         return ret;

+     }

+     if (client_cred_len != sizeof(struct ucred)) {

+         DEBUG(1, ("getsockopt returned unexpected message size.\n"));

+         return ENOMSG;

+     }

+ 

+     cctx->client_euid = client_cred.uid;

+     cctx->client_egid = client_cred.gid;

+     cctx->client_pid = client_cred.pid;

+ 

+     DEBUG(9, ("Client creds: euid[%d] egid[%d] pid[%d].\n",

+               cctx->client_euid, cctx->client_egid, cctx->client_pid));

+ #endif

+ 

+     return EOK;

+ }

+ 

  static void client_send(struct cli_ctx *cctx)

  {

      int ret;
@@ -148,134 +182,12 @@

      return;

  }

  

- static void cred_handler(struct cli_ctx *cctx, char action)

- {

- #ifdef HAVE_UCRED

-     int ret;

-     int fd;

-     struct msghdr msg;

-     struct iovec iov;

-     struct cmsghdr *cmsg;

-     struct ucred *creds;

-     /* buf must be aligned on some architectures. */

-     union ubuf {

-         int align;

-         char buf[CMSG_SPACE(sizeof(struct ucred))];

-     } u;

-     char dummy='s';

-     int enable=1;

- 

-     if (cctx->creds_exchange_done != 0) {

-         DEBUG(1, ("cred_handler called, but creds are already exchanged.\n"));

-         goto failed;

-     }

- 

-     fd = cctx->cfd;

- 

-     iov.iov_base = &dummy;

-     iov.iov_len = 1;

- 

-     memset (&msg, 0, sizeof(msg));

- 

-     msg.msg_name = NULL;

-     msg.msg_namelen = 0;

-     msg.msg_iov = &iov;

-     msg.msg_iovlen = 1;

- 

-     msg.msg_control = u.buf;

-     msg.msg_controllen = sizeof(u.buf);

- 

-     switch (action) {

-         case 'r':

-             ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(int));

-             if (ret == -1) {

-                 DEBUG(1, ("setsockopt failed: [%d][%s].\n", errno,

-                                                             strerror(errno)));

-                 goto failed;

-             }

- 

-             ret = recvmsg(fd, &msg, 0);

-             if (ret == -1) {

-                 DEBUG(1, ("recvmsg failed.[%d][%s]\n", errno, strerror(errno)));

-                 goto failed;

-             }

- 

-             cmsg = CMSG_FIRSTHDR(&msg);

- 

-             if (cmsg->cmsg_level == SOL_SOCKET &&

-                 cmsg->cmsg_type == SCM_CREDENTIALS) {

-                 creds = (struct ucred *) CMSG_DATA(cmsg);

-                 DEBUG(1, ("creds: [%d][%d][%d]\n",creds->uid, creds->gid,

-                                                   creds->pid));

-                 cctx->client_uid = creds->uid;

-                 cctx->client_gid = creds->gid;

-                 cctx->client_pid = creds->pid;

-             }

- 

-             TEVENT_FD_WRITEABLE(cctx->cfde);

- 

-             return;

-             break;

-         case 's':

-             cmsg = CMSG_FIRSTHDR(&msg);

-             cmsg->cmsg_level = SOL_SOCKET;

-             cmsg->cmsg_type = SCM_CREDENTIALS;

-             cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));

- 

-             creds = (struct ucred *) CMSG_DATA(cmsg);

- 

-             creds->uid = geteuid();

-             creds->gid = getegid();

-             creds->pid = getpid();

- 

-             msg.msg_controllen = cmsg->cmsg_len;

- 

-             ret = sendmsg(fd, &msg, 0);

-             if (ret == -1) {

-                 DEBUG(1, ("sendmsg failed.[%d][%s]\n", errno, strerror(errno)));

-                 goto failed;

-             }

-             DEBUG(4, ("Send creds to the client succesfully.\n"));

-             cctx->creds_exchange_done = 1;

- 

-             TEVENT_FD_NOT_WRITEABLE(cctx->cfde);

-             return;

-         default:

-             DEBUG(1, ("Unknown action [%c].\n", action));

-             goto failed;

-     }

- 

- failed:

-     talloc_free(cctx);

-     return;

- 

- #else

- 

-     DEBUG(9, ("Credential exchange not available over socket, "

-               "continuing without.\n"));

-     cctx->creds_exchange_done = 1;

-     return;

- 

- #endif

- }

- 

  static void client_fd_handler(struct tevent_context *ev,

                                struct tevent_fd *fde,

                                uint16_t flags, void *ptr)

  {

      struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);

  

-     if (cctx->creds_exchange_done == 0) {

-         if (flags & TEVENT_FD_READ) {

-             cred_handler(cctx, 'r');

-             return;

-         }

-         if (flags & TEVENT_FD_WRITE) {

-             cred_handler(cctx, 's');

-             return;

-         }

-     }

- 

      if (flags & TEVENT_FD_READ) {

          client_recv(cctx);

          return;
@@ -339,10 +251,12 @@

      }

  

      cctx->priv = 1;

-     cctx->creds_exchange_done = 0;

-     cctx->client_uid = -1;

-     cctx->client_gid = -1;

-     cctx->client_pid = -1;

+ 

+     ret = get_client_cred(cctx);

+     if (ret != EOK) {

+         DEBUG(2, ("get_client_cred failed, "

+                   "client cred may not be available.\n"));

+     }

  

      cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,

                                 TEVENT_FD_READ, client_fd_handler, cctx);
@@ -370,6 +284,7 @@

      struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);

      struct cli_ctx *cctx;

      socklen_t len;

+     int ret;

  

      cctx = talloc_zero(rctx, struct cli_ctx);

      if (!cctx) {
@@ -395,10 +310,11 @@

          return;

      }

  

-     cctx->creds_exchange_done = 0;

-     cctx->client_uid = -1;

-     cctx->client_gid = -1;

-     cctx->client_pid = -1;

+     ret = get_client_cred(cctx);

+     if (ret != EOK) {

+         DEBUG(2, ("get_client_cred failed, "

+                   "client cred may not be available.\n"));

+     }

  

      cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,

                                 TEVENT_FD_READ, client_fd_handler, cctx);
@@ -551,7 +467,8 @@

  

          memset(&addr, 0, sizeof(addr));

          addr.sun_family = AF_UNIX;

-         strncpy(addr.sun_path, rctx->sock_name, sizeof(addr.sun_path));

+         strncpy(addr.sun_path, rctx->sock_name, sizeof(addr.sun_path)-1);

+         addr.sun_path[sizeof(addr.sun_path)-1] = '\0';

  

          /* make sure we have no old sockets around */

          unlink(rctx->sock_name);
@@ -588,7 +505,8 @@

  

          memset(&addr, 0, sizeof(addr));

          addr.sun_family = AF_UNIX;

-         strncpy(addr.sun_path, rctx->priv_sock_name, sizeof(addr.sun_path));

+         strncpy(addr.sun_path, rctx->priv_sock_name, sizeof(addr.sun_path)-1);

+         addr.sun_path[sizeof(addr.sun_path)-1] = '\0';

  

          unlink(rctx->priv_sock_name);

  

@@ -95,18 +95,37 @@

  

      cb = sdp_req->cb_list;

      while (cb) {

+         next = cb->next;

+         /* It is the responsibility of the callback to free cb */

          cb->callback(sdp_req->err_maj,

                       sdp_req->err_min,

                       sdp_req->err_msg,

                       cb->callback_ctx);

-         next = cb->next;

-         talloc_free(cb);

          cb = next;

      }

  

      return 0;

  }

  

+ static bool reconnect_handler(hash_entry_t *item, void *user_data)

+ {

+     struct sss_dp_req *sdp_req = talloc_get_type(item->value.ptr,

+                                                  struct sss_dp_req);

+ 

+     return (talloc_free(sdp_req) == EOK ? true : false);

+ }

+ 

+ void handle_requests_after_reconnect(void)

+ {

+     int ret;

+ 

+     ret = hash_iterate(dp_requests, reconnect_handler, NULL);

+     if (ret != HASH_SUCCESS) {

+         DEBUG(1, ("hash_iterate failed, "

+                   "not all request might be handled after reconnect.\n"));

+     }

+ }

+ 

  static void sdp_req_timeout(struct tevent_context *ev,

                              struct tevent_timer *te,

                              struct timeval t, void *ptr)
@@ -155,7 +174,7 @@

          tv = tevent_timeval_current();

          tev = tevent_add_timer(sdp_req->ev, sdp_req, tv,

                                 sss_dp_invoke_callback, sdp_req);

-         if (!te) {

+         if (!tev) {

              /* Out of memory or other serious error */

              goto done;

          }

file modified
+12 -190
@@ -33,12 +33,13 @@

  #include "popt.h"

  #include "util/util.h"

  #include "responder/nss/nsssrv.h"

- #include "responder/nss/nsssrv_nc.h"

+ #include "responder/common/negcache.h"

  #include "db/sysdb.h"

  #include "confdb/confdb.h"

  #include "dbus/dbus.h"

  #include "sbus/sssd_dbus.h"

  #include "responder/common/responder_packet.h"

+ #include "responder/common/responder.h"

  #include "providers/data_provider.h"

  #include "monitor/monitor_interfaces.h"

  #include "sbus/sbus_client.h"
@@ -67,12 +68,7 @@

                            struct confdb_ctx *cdb)

  {

      TALLOC_CTX *tmpctx;

-     struct sss_domain_info *dom;

-     const char *conf_path;

-     char *domain, *name;

-     char **filter_list = NULL;

-     int ret, i;

-     bool filter_set;

+     int ret;

  

      tmpctx = talloc_new(nctx);

      if (!tmpctx) return ENOMEM;
@@ -92,7 +88,6 @@

                           &nctx->filter_users_in_groups);

      if (ret != EOK) goto done;

  

- 

      ret = confdb_get_int(cdb, nctx, CONFDB_NSS_CONF_ENTRY,

                           CONFDB_NSS_ENTRY_CACHE_NOWAIT_PERCENTAGE, 0,

                           &nctx->cache_refresh_percent);
@@ -104,186 +99,10 @@

          nctx->cache_refresh_percent = 0;

      }

  

-     filter_set = false;

-     for (dom = rctx->domains; dom; dom = dom->next) {

-         conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name);

-         if (!conf_path) {

-             ret = ENOMEM;

-             goto done;

-         }

- 

-         talloc_zfree(filter_list);

-         ret = confdb_get_string_as_list(cdb, tmpctx, conf_path,

-                                         CONFDB_NSS_FILTER_USERS, &filter_list);

-         if (ret == ENOENT) continue;

-         if (ret != EOK) goto done;

-         filter_set = true;

- 

-         for (i = 0; (filter_list && filter_list[i]); i++) {

-             ret = sss_parse_name(tmpctx, nctx->rctx->names,

-                                  filter_list[i], &domain, &name);

-             if (ret != EOK) {

-                 DEBUG(1, ("Invalid name in filterUsers list: [%s] (%d)\n",

-                          filter_list[i], ret));

-                 continue;

-             }

- 

-             if (domain && strcmp(domain, dom->name)) {

-                 DEBUG(1, ("Mismatch betwen domain name (%s) and name "

-                           "set in FQN  (%s), skipping user %s\n",

-                           dom->name, domain, name));

-                 continue;

-             }

- 

-             ret = nss_ncache_set_user(nctx->ncache, true, dom->name, name);

-             if (ret != EOK) {

-                 DEBUG(1, ("Failed to store permanent user filter for [%s]"

-                           " (%d [%s])\n", filter_list[i],

-                           ret, strerror(ret)));

-                 continue;

-             }

-         }

-     }

- 

-     ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY,

-                                     CONFDB_NSS_FILTER_USERS, &filter_list);

-     if (ret == ENOENT) {

-         if (!filter_set) {

-             filter_list = talloc_array(tmpctx, char *, 2);

-             if (!filter_list) {

-                 ret = ENOMEM;

-                 goto done;

-             }

-             filter_list[0] = talloc_strdup(tmpctx, "root");

-             if (!filter_list[0]) {

-                 ret = ENOMEM;

-                 goto done;

-             }

-             filter_list[1] = NULL;

-         }

-         ret = EOK;

-     }

-     else if (ret != EOK) goto done;

- 

-     for (i = 0; (filter_list && filter_list[i]); i++) {

-         ret = sss_parse_name(tmpctx, nctx->rctx->names,

-                              filter_list[i], &domain, &name);

-         if (ret != EOK) {

-             DEBUG(1, ("Invalid name in filterUsers list: [%s] (%d)\n",

-                      filter_list[i], ret));

-             continue;

-         }

-         if (domain) {

-             ret = nss_ncache_set_user(nctx->ncache, true, domain, name);

-             if (ret != EOK) {

-                 DEBUG(1, ("Failed to store permanent user filter for [%s]"

-                           " (%d [%s])\n", filter_list[i],

-                           ret, strerror(ret)));

-                 continue;

-             }

-         } else {

-             for (dom = rctx->domains; dom; dom = dom->next) {

-                 ret = nss_ncache_set_user(nctx->ncache, true, dom->name, name);

-                 if (ret != EOK) {

-                    DEBUG(1, ("Failed to store permanent user filter for"

-                              " [%s:%s] (%d [%s])\n",

-                              dom->name, filter_list[i],

-                              ret, strerror(ret)));

-                     continue;

-                 }

-             }

-         }

-     }

- 

-     filter_set = false;

-     for (dom = rctx->domains; dom; dom = dom->next) {

-         conf_path = talloc_asprintf(tmpctx, CONFDB_DOMAIN_PATH_TMPL, dom->name);

-         if (!conf_path) {

-             ret = ENOMEM;

-             goto done;

-         }

- 

-         talloc_zfree(filter_list);

-         ret = confdb_get_string_as_list(cdb, tmpctx, conf_path,

-                                         CONFDB_NSS_FILTER_GROUPS, &filter_list);

-         if (ret == ENOENT) continue;

-         if (ret != EOK) goto done;

-         filter_set = true;

- 

-         for (i = 0; (filter_list && filter_list[i]); i++) {

-             ret = sss_parse_name(tmpctx, nctx->rctx->names,

-                                  filter_list[i], &domain, &name);

-             if (ret != EOK) {

-                 DEBUG(1, ("Invalid name in filterGroups list: [%s] (%d)\n",

-                          filter_list[i], ret));

-                 continue;

-             }

- 

-             if (domain && strcmp(domain, dom->name)) {

-                 DEBUG(1, ("Mismatch betwen domain name (%s) and name "

-                           "set in FQN  (%s), skipping group %s\n",

-                           dom->name, domain, name));

-                 continue;

-             }

- 

-             ret = nss_ncache_set_group(nctx->ncache, true, dom->name, name);

-             if (ret != EOK) {

-                 DEBUG(1, ("Failed to store permanent group filter for [%s]"

-                           " (%d [%s])\n", filter_list[i],

-                           ret, strerror(ret)));

-                 continue;

-             }

-         }

-     }

- 

-     ret = confdb_get_string_as_list(cdb, tmpctx, CONFDB_NSS_CONF_ENTRY,

-                                     CONFDB_NSS_FILTER_GROUPS, &filter_list);

-     if (ret == ENOENT) {

-         if (!filter_set) {

-             filter_list = talloc_array(tmpctx, char *, 2);

-             if (!filter_list) {

-                 ret = ENOMEM;

-                 goto done;

-             }

-             filter_list[0] = talloc_strdup(tmpctx, "root");

-             if (!filter_list[0]) {

-                 ret = ENOMEM;

-                 goto done;

-             }

-             filter_list[1] = NULL;

-         }

-         ret = EOK;

-     }

-     else if (ret != EOK) goto done;

- 

-     for (i = 0; (filter_list && filter_list[i]); i++) {

-         ret = sss_parse_name(tmpctx, nctx->rctx->names,

-                              filter_list[i], &domain, &name);

-         if (ret != EOK) {

-             DEBUG(1, ("Invalid name in filterGroups list: [%s] (%d)\n",

-                      filter_list[i], ret));

-             continue;

-         }

-         if (domain) {

-             ret = nss_ncache_set_group(nctx->ncache, true, domain, name);

-             if (ret != EOK) {

-                 DEBUG(1, ("Failed to store permanent group filter for"

-                           " [%s] (%d [%s])\n", filter_list[i],

-                           ret, strerror(ret)));

-                 continue;

-             }

-         } else {

-             for (dom = rctx->domains; dom; dom = dom->next) {

-                 ret = nss_ncache_set_group(nctx->ncache, true, dom->name, name);

-                 if (ret != EOK) {

-                    DEBUG(1, ("Failed to store permanent group filter for"

-                              " [%s:%s] (%d [%s])\n",

-                              dom->name, filter_list[i],

-                              ret, strerror(ret)));

-                     continue;

-                 }

-             }

-         }

+     ret = sss_ncache_prepopulate(nctx->ncache, cdb, nctx->rctx->names,

+                                  nctx->rctx->domains);

+     if (ret != EOK) {

+         goto done;

      }

  

      ret = confdb_get_string(cdb, nctx, CONFDB_NSS_CONF_ENTRY,
@@ -325,7 +144,10 @@

                                  DATA_PROVIDER_VERSION,

                                  "NSS");

          /* all fine */

-         if (ret == EOK) return;

+         if (ret == EOK) {

+             handle_requests_after_reconnect();

+             return;

+         }

      }

  

      /* Failed to reconnect */
@@ -351,7 +173,7 @@

          return ENOMEM;

      }

  

-     ret = nss_ncache_init(nctx, &nctx->ncache);

+     ret = sss_ncache_init(nctx, &nctx->ncache);

      if (ret != EOK) {

          DEBUG(0, ("fatal error initializing negative cache\n"));

          return ret;

file modified
+1 -2
@@ -32,7 +32,6 @@

  #include "sbus/sssd_dbus.h"

  #include "responder/common/responder_packet.h"

  #include "responder/common/responder.h"

- #include "responder/nss/nsssrv_nc.h"

  

  #define NSS_SBUS_SERVICE_VERSION 0x0001

  #define NSS_SBUS_SERVICE_NAME "nss"
@@ -45,7 +44,7 @@

      struct resp_ctx *rctx;

  

      int neg_timeout;

-     struct nss_nc_ctx *ncache;

+     struct sss_nc_ctx *ncache;

  

      int cache_refresh_percent;

  

file modified
+25 -24
@@ -21,6 +21,7 @@

  

  #include "util/util.h"

  #include "responder/nss/nsssrv.h"

+ #include "responder/common/negcache.h"

  #include "confdb/confdb.h"

  #include "db/sysdb.h"

  #include <time.h>
@@ -158,13 +159,13 @@

          gid = ldb_msg_find_attr_as_uint64(msg, SYSDB_GIDNUM, 0);

  

          if (!name || !uid || !gid) {

-             DEBUG(1, ("Incomplete user object for %s[%llu]! Skipping\n",

+             DEBUG(1, ("Incomplete or fake user object for %s[%llu]! Skipping\n",

                        name?name:"<NULL>", (unsigned long long int)uid));

              continue;

          }

  

          if (filter_users) {

-             ncret = nss_ncache_check_user(nctx->ncache,

+             ncret = sss_ncache_check_user(nctx->ncache,

                                          nctx->neg_timeout,

                                          domain, name);

              if (ncret == EEXIST) {
@@ -448,7 +449,7 @@

  

                  if (dom->fqnames) continue;

  

-                 ncret = nss_ncache_check_user(nctx->ncache,

+                 ncret = sss_ncache_check_user(nctx->ncache,

                                                nctx->neg_timeout,

                                                dom->name, cmdctx->name);

                  if (ncret == ENOENT) break;
@@ -500,7 +501,7 @@

  

          /* set negative cache only if not result of cache check */

          if (!neghit) {

-             ret = nss_ncache_set_user(nctx->ncache, false,

+             ret = sss_ncache_set_user(nctx->ncache, false,

                                        dctx->domain->name, cmdctx->name);

              if (ret != EOK) {

                  NSS_CMD_FATAL_ERROR(cctx);
@@ -662,7 +663,7 @@

  

          /* verify this user has not yet been negatively cached,

           * or has been permanently filtered */

-         ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

+         ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

                                        dctx->domain->name, cmdctx->name);

          if (ncret == EEXIST) {

              neghit = true;
@@ -676,7 +677,7 @@

  

              /* verify this user has not yet been negatively cached,

              * or has been permanently filtered */

-             ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

+             ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

                                            dom->name, cmdctx->name);

              if (ncret == ENOENT) break;

  
@@ -795,7 +796,7 @@

              ret = EOK;

  

              dom = dctx->domain->next;

-             ncret = nss_ncache_check_uid(nctx->ncache, nctx->neg_timeout,

+             ncret = sss_ncache_check_uid(nctx->ncache, nctx->neg_timeout,

                                               cmdctx->id);

              if (ncret == EEXIST) {

                  DEBUG(3, ("Uid [%lu] does not exist! (negative cache)\n",
@@ -839,7 +840,7 @@

  

          /* set negative cache only if not result of cache check */

          if (!neghit) {

-             ret = nss_ncache_set_uid(nctx->ncache, false, cmdctx->id);

+             ret = sss_ncache_set_uid(nctx->ncache, false, cmdctx->id);

              if (ret != EOK) {

                  NSS_CMD_FATAL_ERROR(cctx);

              }
@@ -982,7 +983,7 @@

      for (dom = cctx->rctx->domains; dom; dom = dom->next) {

          /* verify this user has not yet been negatively cached,

           * or has been permanently filtered */

-         ncret = nss_ncache_check_uid(nctx->ncache, nctx->neg_timeout,

+         ncret = sss_ncache_check_uid(nctx->ncache, nctx->neg_timeout,

                                       cmdctx->id);

          if (ncret == EEXIST) {

              DEBUG(3, ("Uid [%lu] does not exist! (negative cache)\n",
@@ -1425,7 +1426,7 @@

          return nss_cmd_setpwent_ext(cctx, true);

      }

  

-     cmdctx = talloc(cctx, struct nss_cmd_ctx);

+     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);

      if (!cmdctx) {

          return ENOMEM;

      }
@@ -1542,7 +1543,7 @@

          }

  

          if (filter_groups) {

-             ret = nss_ncache_check_group(nctx->ncache,

+             ret = sss_ncache_check_group(nctx->ncache,

                                           nctx->neg_timeout, domain, name);

              if (ret == EEXIST) {

                  DEBUG(4, ("Group [%s@%s] filtered out! (negative cache)\n",
@@ -1619,7 +1620,7 @@

                  name = (const char *)el->values[j].data;

  

                  if (nctx->filter_users_in_groups) {

-                     ret = nss_ncache_check_user(nctx->ncache,

+                     ret = sss_ncache_check_user(nctx->ncache,

                                                  nctx->neg_timeout,

                                                  domain, name);

                      if (ret == EEXIST) {
@@ -1764,7 +1765,7 @@

  

                  if (dom->fqnames) continue;

  

-                 ncret = nss_ncache_check_group(nctx->ncache,

+                 ncret = sss_ncache_check_group(nctx->ncache,

                                                 nctx->neg_timeout,

                                                 dom->name, cmdctx->name);

                  if (ncret == ENOENT) break;
@@ -1817,7 +1818,7 @@

  

          /* set negative cache only if not result of cache check */

          if (!neghit) {

-             ret = nss_ncache_set_group(nctx->ncache, false,

+             ret = sss_ncache_set_group(nctx->ncache, false,

                                         dctx->domain->name, cmdctx->name);

              if (ret != EOK) {

                  NSS_CMD_FATAL_ERROR(cctx);
@@ -1972,7 +1973,7 @@

  

          /* verify this user has not yet been negatively cached,

           * or has been permanently filtered */

-         ncret = nss_ncache_check_group(nctx->ncache, nctx->neg_timeout,

+         ncret = sss_ncache_check_group(nctx->ncache, nctx->neg_timeout,

                                         dctx->domain->name, cmdctx->name);

          if (ncret == EEXIST) {

              neghit = true;
@@ -1986,7 +1987,7 @@

  

              /* verify this user has not yet been negatively cached,

               * or has been permanently filtered */

-             ncret = nss_ncache_check_group(nctx->ncache, nctx->neg_timeout,

+             ncret = sss_ncache_check_group(nctx->ncache, nctx->neg_timeout,

                                             dom->name, cmdctx->name);

              if (ncret == ENOENT) break;

  
@@ -2106,7 +2107,7 @@

  

              dom = dctx->domain->next;

  

-             ncret = nss_ncache_check_gid(nctx->ncache, nctx->neg_timeout,

+             ncret = sss_ncache_check_gid(nctx->ncache, nctx->neg_timeout,

                                           cmdctx->id);

              if (ncret == EEXIST) {

                  DEBUG(3, ("Gid [%lu] does not exist! (negative cache)\n",
@@ -2150,7 +2151,7 @@

  

          /* set negative cache only if not result of cache check */

          if (!neghit) {

-             ret = nss_ncache_set_gid(nctx->ncache, false, cmdctx->id);

+             ret = sss_ncache_set_gid(nctx->ncache, false, cmdctx->id);

              if (ret != EOK) {

                  NSS_CMD_FATAL_ERROR(cctx);

              }
@@ -2285,7 +2286,7 @@

      for (dom = cctx->rctx->domains; dom; dom = dom->next) {

          /* verify this user has not yet been negatively cached,

           * or has been permanently filtered */

-         ncret = nss_ncache_check_gid(nctx->ncache, nctx->neg_timeout,

+         ncret = sss_ncache_check_gid(nctx->ncache, nctx->neg_timeout,

                                       cmdctx->id);

          if (ncret == EEXIST) {

              DEBUG(3, ("Gid [%lu] does not exist! (negative cache)\n",
@@ -2724,7 +2725,7 @@

          return nss_cmd_setgrent_ext(cctx, true);

      }

  

-     cmdctx = talloc(cctx, struct nss_cmd_ctx);

+     cmdctx = talloc_zero(cctx, struct nss_cmd_ctx);

      if (!cmdctx) {

          return ENOMEM;

      }
@@ -2846,7 +2847,7 @@

  

                  if (dom->fqnames) continue;

  

-                 ncret = nss_ncache_check_user(nctx->ncache,

+                 ncret = sss_ncache_check_user(nctx->ncache,

                                                nctx->neg_timeout,

                                                dom->name, cmdctx->name);

                  if (ncret == ENOENT) break;
@@ -2898,7 +2899,7 @@

  

          /* set negative cache only if not result of cache check */

          if (!neghit) {

-             ret = nss_ncache_set_user(nctx->ncache, false,

+             ret = sss_ncache_set_user(nctx->ncache, false,

                                        dctx->domain->name, cmdctx->name);

              if (ret != EOK) {

                  NSS_CMD_FATAL_ERROR(cctx);
@@ -3048,7 +3049,7 @@

  

          /* verify this user has not yet been negatively cached,

           * or has been permanently filtered */

-         ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

+         ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

                                      domname, cmdctx->name);

          if (ncret == EEXIST) {

              neghit = true;
@@ -3062,7 +3063,7 @@

  

              /* verify this user has not yet been negatively cached,

              * or has been permanently filtered */

-             ncret = nss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

+             ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

                                            dom->name, cmdctx->name);

              if (ncret == ENOENT) break;

  

file modified
+28 -3
@@ -42,6 +42,7 @@

  #include "monitor/monitor_interfaces.h"

  #include "sbus/sbus_client.h"

  #include "responder/pam/pamsrv.h"

+ #include "responder/common/negcache.h"

  

  #define SSS_PAM_SBUS_SERVICE_VERSION 0x0001

  #define SSS_PAM_SBUS_SERVICE_NAME "pam"
@@ -136,7 +137,7 @@

                             "PAM", &pam_dp_interface,

                             &pctx->rctx);

      if (ret != EOK) {

-         return ret;

+         goto done;

      }

  

      pctx->rctx->pvt_ctx = pctx;
@@ -150,7 +151,7 @@

                           CONFDB_SERVICE_RECON_RETRIES, 3, &max_retries);

      if (ret != EOK) {

          DEBUG(0, ("Failed to set up automatic reconnection\n"));

-         return ret;

+         goto done;

      }

  

      for (iter = pctx->rctx->be_conns; iter; iter = iter->next) {
@@ -158,7 +159,31 @@

                              pam_dp_reconnect_init, iter);

      }

  

-     return EOK;

+     /* Set up the negative cache */

+     ret = confdb_get_int(cdb, pctx, CONFDB_NSS_CONF_ENTRY,

+                          CONFDB_NSS_ENTRY_NEG_TIMEOUT, 15,

+                          &pctx->neg_timeout);

+     if (ret != EOK) goto done;

+ 

+     ret = sss_ncache_init(pctx, &pctx->ncache);

+     if (ret != EOK) {

+         DEBUG(0, ("fatal error initializing negative cache\n"));

+         goto done;

+     }

+ 

+     ret = sss_ncache_prepopulate(pctx->ncache, cdb, pctx->rctx->names,

+                                  pctx->rctx->domains);

+     if (ret != EOK) {

+         goto done;

+     }

+ 

+     ret = EOK;

+ 

+ done:

+     if (ret != EOK) {

+         talloc_free(pctx);

+     }

+     return ret;

  }

  

  int main(int argc, const char *argv[])

@@ -34,6 +34,8 @@

  struct pam_ctx {

      int cred_expiration;

      struct resp_ctx *rctx;

+     struct sss_nc_ctx *ncache;

+     int neg_timeout;

  };

  

  struct pam_auth_req {

file modified
+94 -84
@@ -26,24 +26,22 @@

  #include "confdb/confdb.h"

  #include "responder/common/responder_packet.h"

  #include "responder/common/responder.h"

+ #include "responder/common/negcache.h"

  #include "providers/data_provider.h"

  #include "responder/pam/pamsrv.h"

  #include "db/sysdb.h"

  

  static void pam_reply(struct pam_auth_req *preq);

  

- static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, uint8_t *body, size_t blen, size_t *c) {

-     uint32_t data_size;

+ static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok,

+                            size_t data_size, uint8_t *body, size_t blen,

+                            size_t *c) {

  

-     if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL;

- 

-     memcpy(&data_size, &body[*c], sizeof(uint32_t));

-     *c += sizeof(uint32_t);

-     if (data_size < sizeof(uint32_t) || (*c)+(data_size) > blen) return EINVAL;

+     if (data_size < sizeof(uint32_t) || *c+data_size > blen ||

+         SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;

      *size = data_size - sizeof(uint32_t);

  

-     memcpy(type, &body[*c], sizeof(uint32_t));

-     *c += sizeof(uint32_t);

+     SAFEALIGN_COPY_UINT32_CHECK(type, &body[*c], blen, c);

  

      *tok = body+(*c);

  
@@ -52,15 +50,11 @@

      return EOK;

  }

  

- static int extract_string(char **var, uint8_t *body, size_t blen, size_t *c) {

-     uint32_t size;

+ static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,

+                           size_t *c) {

      uint8_t *str;

  

-     if (blen-(*c) < sizeof(uint32_t)+1) return EINVAL;

- 

-     memcpy(&size, &body[*c], sizeof(uint32_t));

-     *c += sizeof(uint32_t);

-     if (*c+size > blen) return EINVAL;

+     if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;

  

      str = body+(*c);

  
@@ -73,16 +67,13 @@

      return EOK;

  }

  

- static int extract_uint32_t(uint32_t *var, uint8_t *body, size_t blen, size_t *c) {

-     uint32_t size;

- 

-     if (blen-(*c) < 2*sizeof(uint32_t)) return EINVAL;

+ static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,

+                             size_t blen, size_t *c) {

  

-     memcpy(&size, &body[*c], sizeof(uint32_t));

-     *c += sizeof(uint32_t);

+     if (size != sizeof(uint32_t) || *c+size > blen || SIZE_T_OVERFLOW(*c, size))

+         return EINVAL;

  

-     memcpy(var, &body[*c], sizeof(uint32_t));

-     *c += sizeof(uint32_t);

+     SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);

  

      return EOK;

  }
@@ -107,59 +98,66 @@

  

      c = sizeof(uint32_t);

      do {

-         memcpy(&type, &body[c], sizeof(uint32_t));

-         c += sizeof(uint32_t);

-         if (c > blen) return EINVAL;

- 

-         switch(type) {

-             case SSS_PAM_ITEM_USER:

-                 ret = extract_string(&pam_user, body, blen, &c);

-                 if (ret != EOK) return ret;

- 

-                 ret = sss_parse_name(pd, snctx, pam_user,

-                                      &pd->domain, &pd->user);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_SERVICE:

-                 ret = extract_string(&pd->service, body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_TTY:

-                 ret = extract_string(&pd->tty, body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_RUSER:

-                 ret = extract_string(&pd->ruser, body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_RHOST:

-                 ret = extract_string(&pd->rhost, body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_CLI_PID:

-                 ret = extract_uint32_t(&pd->cli_pid,

-                                        body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_AUTHTOK:

-                 ret = extract_authtok(&pd->authtok_type, &pd->authtok_size,

-                                       &pd->authtok, body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_PAM_ITEM_NEWAUTHTOK:

-                 ret = extract_authtok(&pd->newauthtok_type,

-                                       &pd->newauthtok_size,

-                                       &pd->newauthtok, body, blen, &c);

-                 if (ret != EOK) return ret;

-                 break;

-             case SSS_END_OF_PAM_REQUEST:

-                 if (c != blen) return EINVAL;

-                 break;

-             default:

-                 DEBUG(1,("Ignoring unknown data type [%d].\n", type));

-                 size = ((uint32_t *)&body[c])[0];

-                 c += size+sizeof(uint32_t);

+         SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);

+ 

+         if (type == SSS_END_OF_PAM_REQUEST) {

+             if (c != blen) return EINVAL;

+         } else {

+             SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);

+             /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to

+              * the remaining buffer */

+             if (size > (blen - c - sizeof(uint32_t))) {

+                 DEBUG(1, ("Invalid data size.\n"));

+                 return EINVAL;

+             }

+ 

+             switch(type) {

+                 case SSS_PAM_ITEM_USER:

+                     ret = extract_string(&pam_user, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+ 

+                     ret = sss_parse_name(pd, snctx, pam_user,

+                                          &pd->domain, &pd->user);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_SERVICE:

+                     ret = extract_string(&pd->service, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_TTY:

+                     ret = extract_string(&pd->tty, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_RUSER:

+                     ret = extract_string(&pd->ruser, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_RHOST:

+                     ret = extract_string(&pd->rhost, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_CLI_PID:

+                     ret = extract_uint32_t(&pd->cli_pid, size,

+                                            body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_AUTHTOK:

+                     ret = extract_authtok(&pd->authtok_type, &pd->authtok_size,

+                                           &pd->authtok, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 case SSS_PAM_ITEM_NEWAUTHTOK:

+                     ret = extract_authtok(&pd->newauthtok_type,

+                                           &pd->newauthtok_size,

+                                           &pd->newauthtok, size, body, blen, &c);

+                     if (ret != EOK) return ret;

+                     break;

+                 default:

+                     DEBUG(1,("Ignoring unknown data type [%d].\n", type));

+                     c += size;

+             }

          }

+ 

      } while(c < blen);

  

      if (pd->user == NULL || *pd->user == '\0') return EINVAL;
@@ -230,6 +228,7 @@

  

      start += sizeof(uint32_t);

      pd->authtok_size = (int) body[start];

+     if (pd->authtok_size >= blen) return EINVAL;

  

      start += sizeof(uint32_t);

      end = start + pd->authtok_size;
@@ -249,6 +248,7 @@

  

      start += sizeof(uint32_t);

      pd->newauthtok_size = (int) body[start];

+     if (pd->newauthtok_size >= blen) return EINVAL;

  

      start += sizeof(uint32_t);

      end = start + pd->newauthtok_size;
@@ -520,7 +520,7 @@

                      req = sysdb_cache_auth_send(preq, preq->cctx->ev, sysdb,

                                                  preq->domain, pd->user,

                                                  pd->authtok, pd->authtok_size,

-                                                 pctx->rctx->cdb);

+                                                 pctx->rctx->cdb, false);

                      if (req == NULL) {

                          DEBUG(1, ("Failed to setup offline auth.\n"));

                          /* this error is not fatal, continue */
@@ -732,6 +732,9 @@

      size_t blen;

      int timeout;

      int ret;

+     errno_t ncret;

+     struct pam_ctx *pctx =

+             talloc_get_type(cctx->rctx->pvt_ctx, struct pam_ctx);

      uint32_t terminator = SSS_END_OF_PAM_REQUEST;

      preq = talloc_zero(cctx, struct pam_auth_req);

      if (!preq) {
@@ -792,13 +795,19 @@

          for (dom = preq->cctx->rctx->domains; dom; dom = dom->next) {

              if (dom->fqnames) continue;

  

- /* FIXME: need to support negative cache */

- #if HAVE_NEG_CACHE

-             ncret = sss_ncache_check_user(nctx->ncache, nctx->neg_timeout,

-                                           dom->name, cmdctx->name);

-             if (ncret == ENOENT) break;

- #endif

-             break;

+             ncret = sss_ncache_check_user(pctx->ncache, pctx->neg_timeout,

+                                           dom->name, pd->user);

+             if (ncret == ENOENT) {

+                 /* User not found in the negative cache

+                  * Proceed with PAM actions

+                  */

+                 break;

+             }

+ 

+             /* Try the next domain */

+             DEBUG(4, ("User [%s@%s] filtered out (negative cache). "

+                       "Trying next domain.\n",

+                       pd->user, dom->name));

          }

          if (!dom) {

              ret = ENOENT;
@@ -848,6 +857,7 @@

          switch (ret) {

          case ENOENT:

              pd->pam_status = PAM_USER_UNKNOWN;

+             break;

          default:

              pd->pam_status = PAM_SYSTEM_ERR;

          }

@@ -58,7 +58,8 @@

  

      if (conn->retries > 0) {

          DEBUG(6, ("SBUS is reconnecting. Deferring.\n"));

-         /* Currently trying to reconnect, defer dispatch */

+         /* Currently trying to reconnect, defer dispatch for 30ms */

+         tv = tevent_timeval_current_ofs(0, 30);

          new_event = tevent_add_timer(ev, conn, tv, sbus_dispatch, conn);

          if (new_event == NULL) {

              DEBUG(0,("Could not defer dispatch!\n"));

file modified
+86 -110
@@ -40,6 +40,8 @@

  #include <fcntl.h>

  #include <poll.h>

  

+ #include <libintl.h>

+ #define _(STRING) dgettext (PACKAGE, STRING)

  #include "config.h"

  #include "sss_cli.h"

  
@@ -55,108 +57,6 @@

      }

  }

  

- static int exchange_credentials(void)

- {

- #ifdef HAVE_UCRED

-     int ret;

-     struct msghdr msg;

-     struct cmsghdr *cmsg;

-     struct iovec iov;

-     char dummy='a';

-     /* buf must be aligned on some architectures. */

-     union ubuf {

-         int align;

-         char buf[CMSG_SPACE(sizeof(struct ucred))];

-     } u;

-     struct ucred *creds;

-     int enable = 1;

-     struct pollfd pfd;

- 

-     ret = setsockopt(sss_cli_sd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(int));

-     if (ret == -1) {

-         return errno;

-     }

- 

-     iov.iov_base = &dummy;

-     iov.iov_len = 1;

- 

-     memset(&msg, 0, sizeof(msg));

- 

-     msg.msg_name = NULL;

-     msg.msg_namelen = 0;

-     msg.msg_iov = &iov;

-     msg.msg_iovlen = 1;

- 

-     msg.msg_control = u.buf;

-     msg.msg_controllen = sizeof(u.buf);

- 

-     cmsg = CMSG_FIRSTHDR(&msg);

-     cmsg->cmsg_level = SOL_SOCKET;

-     cmsg->cmsg_type = SCM_CREDENTIALS;

-     cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));

- 

-     creds = (struct ucred *) CMSG_DATA(cmsg);

- 

-     creds->uid = geteuid();

-     creds->gid = getegid();

-     creds->pid = getpid();

- 

-     msg.msg_controllen = cmsg->cmsg_len;

- 

-     pfd.fd = sss_cli_sd;

-     pfd.events = POLLOUT;

-     ret = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);

-     if (ret != 1 || !(pfd.revents & POLLOUT) ) {

-         return errno;

-     }

- 

-     ret = sendmsg(sss_cli_sd, &msg, 0);

-     if (ret == -1) {

-         return errno;

-     }

- 

-     memset(&msg, 0, sizeof(msg));

- 

-     msg.msg_name = NULL;

-     msg.msg_namelen = 0;

-     msg.msg_iov = &iov;

-     msg.msg_iovlen = 1;

- 

-     msg.msg_control = u.buf;

-     msg.msg_controllen = sizeof(u.buf);

- 

-     pfd.fd = sss_cli_sd;

-     pfd.events = POLLIN;

-     ret = poll(&pfd, 1, SSS_CLI_SOCKET_TIMEOUT);

- 

-     if (ret != 1 || !(pfd.revents & POLLIN) ) {

-         return errno;

-     }

- 

-     ret = recvmsg(sss_cli_sd, &msg, 0);

-     if (ret == -1) {

-         return errno;

-     }

- 

-     cmsg = CMSG_FIRSTHDR(&msg);

- 

-     if (msg.msg_controllen != 0 && cmsg->cmsg_level == SOL_SOCKET &&

-                                    cmsg->cmsg_type == SCM_CREDENTIALS) {

-         creds = (struct ucred *) CMSG_DATA(cmsg);

-         if (creds->uid != 0 || creds->gid!= 0) {

-             return SSS_STATUS_UNAVAIL;

-         }

-     }

- 

-     return SSS_STATUS_SUCCESS;

- 

- #else

- 

-     return SSS_STATUS_SUCCESS;

- 

- #endif

- }

- 

  /* Requests:

   *

   * byte 0-3: 32bit unsigned with length (the complete packet length: 0 to X)
@@ -223,6 +123,7 @@

              return NSS_STATUS_UNAVAIL;

          }

  

+         errno = 0;

          if (datasent < SSS_NSS_HEADER_SIZE) {

              res = write(sss_cli_sd,

                          (char *)header + datasent,
@@ -233,8 +134,15 @@

                          (const char *)rd->data + rdsent,

                          rd->len - rdsent);

          }

+         error = errno;

  

          if ((res == -1) || (res == 0)) {

+             if ((error == EINTR) || error == EAGAIN) {

+                 /* If the write was interrupted, go back through

+                  * the loop and try again

+                  */

+                 continue;

+             }

  

              /* Write failed */

              sss_cli_close_socket();
@@ -317,6 +225,7 @@

              return NSS_STATUS_UNAVAIL;

          }

  

+         errno = 0;

          if (datarecv < SSS_NSS_HEADER_SIZE) {

              res = read(sss_cli_sd,

                         (char *)header + datarecv,
@@ -327,8 +236,15 @@

                         (char *)(*buf) + bufrecv,

                         header[0] - datarecv);

          }

+         error = errno;

  

          if ((res == -1) || (res == 0)) {

+             if ((error == EINTR) || error == EAGAIN) {

+                 /* If the read was interrupted, go back through

+                  * the loop and try again

+                  */

+                 continue;

+             }

  

              /* Read failed.  I think the only useful thing

               * we can do here is just return -1 and fail
@@ -691,12 +607,11 @@

              *errnop = EBADF;

              break;

          }

-         if (*errnop) {

-             sss_cli_close_socket();

-             return SSS_STATUS_UNAVAIL;

+         if (*errnop == 0) {

+             return SSS_STATUS_SUCCESS;

          }

  

-         return SSS_STATUS_SUCCESS;

+         sss_cli_close_socket();

      }

  

      mysd = sss_nss_open_socket(errnop, socket_name);
@@ -706,10 +621,9 @@

  

      sss_cli_sd = mysd;

  

-     if (exchange_credentials() == SSS_STATUS_SUCCESS)

-         if (sss_nss_check_version(socket_name) == NSS_STATUS_SUCCESS) {

-             return SSS_STATUS_SUCCESS;

-         }

+     if (sss_nss_check_version(socket_name) == NSS_STATUS_SUCCESS) {

+         return SSS_STATUS_SUCCESS;

+     }

  

      sss_cli_close_socket();

      *errnop = EFAULT;
@@ -740,6 +654,29 @@

      return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop);

  }

  

+ errno_t check_server_cred(int sockfd)

+ {

+ #ifdef HAVE_UCRED

+     int ret;

+     struct ucred server_cred;

+     socklen_t server_cred_len = sizeof(server_cred);

+ 

+     ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &server_cred,

+                      &server_cred_len);

+     if (ret != 0) {

+         return errno;

+     }

+ 

+     if (server_cred_len != sizeof(struct ucred)) {

+         return ESSS_BAD_CRED_MSG;

+     }

+ 

+     if (server_cred.uid != 0 || server_cred.gid != 0) {

+         return ESSS_SERVER_NOT_TRUSTED;

+     }

+ #endif

+     return 0;

+ }

  int sss_pam_make_request(enum sss_cli_command cmd,

                        struct sss_cli_req_data *rd,

                        uint8_t **repbuf, size_t *replen,
@@ -763,6 +700,7 @@

                  stat_buf.st_gid == 0 &&

                  S_ISSOCK(stat_buf.st_mode) &&

                  (stat_buf.st_mode & ~S_IFMT) == 0600 )) {

+             *errnop = ESSS_BAD_PRIV_SOCKET;

              return PAM_SERVICE_ERR;

          }

  
@@ -774,6 +712,7 @@

                  stat_buf.st_gid == 0 &&

                  S_ISSOCK(stat_buf.st_mode) &&

                  (stat_buf.st_mode & ~S_IFMT) == 0666 )) {

+             *errnop = ESSS_BAD_PUB_SOCKET;

              return PAM_SERVICE_ERR;

          }

  
@@ -783,5 +722,42 @@

          return PAM_SERVICE_ERR;

      }

  

+     ret = check_server_cred(sss_cli_sd);

+     if (ret != 0) {

+         sss_cli_close_socket();

+         *errnop = ret;

+         return PAM_SERVICE_ERR;

+     }

+ 

      return sss_nss_make_request_nochecks(cmd, rd, repbuf, replen, errnop);

  }

+ 

+ 

+ const char *ssscli_err2string(int err)

+ {

+     const char *m;

+ 

+     switch(err) {

+         case ESSS_BAD_PRIV_SOCKET:

+             return _("Privileged socket has wrong ownership or permissions.");

+             break;

+         case ESSS_BAD_PUB_SOCKET:

+             return _("Public socket has wrong ownership or permissions.");

+             break;

+         case ESSS_BAD_CRED_MSG:

+             return _("Unexpected format of the server credential message.");

+             break;

+         case ESSS_SERVER_NOT_TRUSTED:

+             return _("SSSD is not run by root.");

+             break;

+         default:

+             m = strerror(err);

+             if (m == NULL) {

+                 return _("An error occurred, but no description can be found.");

+             }

+             return m;

+             break;

+     }

+ 

+     return _("Unexpected error while looking for an error description");

+ }

file modified
+3
@@ -235,6 +235,7 @@

          *start += 1;

      }

  

+     free(repbuf);

      return NSS_STATUS_SUCCESS;

  }

  
@@ -274,6 +275,7 @@

      /* only 1 result is accepted for this function */

      if (((uint32_t *)repbuf)[0] != 1) {

          *errnop = EBADMSG;

+         free(repbuf);

          return NSS_STATUS_TRYAGAIN;

      }

  
@@ -325,6 +327,7 @@

      /* only 1 result is accepted for this function */

      if (((uint32_t *)repbuf)[0] != 1) {

          *errnop = EBADMSG;

+         free(repbuf);

          return NSS_STATUS_TRYAGAIN;

      }

  

file modified
+353 -67
@@ -35,6 +35,11 @@

  #include <stdio.h>

  #include <syslog.h>

  #include <time.h>

+ #include <sys/stat.h>

+ #include <fcntl.h>

+ #include <errno.h>

+ #include <locale.h>

+ #include <stdbool.h>

  

  #include <security/pam_modules.h>

  #include <security/pam_ext.h>
@@ -53,6 +58,11 @@

  

  #define PWEXP_FLAG "pam_sss:password_expired_flag"

  

+ #define PW_RESET_MSG_FILENAME_TEMPLATE SSSD_CONF_DIR"/customize/%s/pam_sss_pw_reset_message.%s"

+ #define PW_RESET_MSG_MAX_SIZE 4096

+ 

+ #define OPT_RETRY_KEY "retry="

+ 

  struct pam_items {

      const char* pam_service;

      const char* pam_user;
@@ -74,6 +84,7 @@

      size_t pam_newauthtok_size;

      pid_t cli_pid;

      const char *login_name;

+     char *domain_name;

  };

  

  #define DEBUG_MGS_LEN 1024
@@ -183,7 +194,7 @@

      return rp;

  }

  

- static void overwrite_and_free_authtoks(struct pam_items *pi)

+ static void overwrite_and_free_pam_items(struct pam_items *pi)

  {

      if (pi->pam_authtok != NULL) {

          _pam_overwrite_n((void *)pi->pam_authtok, pi->pam_authtok_size);
@@ -196,6 +207,12 @@

          free((void *)pi->pam_newauthtok);

          pi->pam_newauthtok = NULL;

      }

+ 

+     pi->pamstack_authtok = NULL;

+     pi->pamstack_oldauthtok = NULL;

+ 

+     free(pi->domain_name);

+     pi->domain_name = NULL;

  }

  

  static int pack_message_v3(struct pam_items *pi, size_t *size,
@@ -262,6 +279,7 @@

  

      if (rp != len) {

          D(("error during packet creation."));

+         free(buf);

          return PAM_BUF_ERR;

      }

  
@@ -389,6 +407,162 @@

      return PAM_SUCCESS;

  }

  

+ static errno_t display_pw_reset_message(pam_handle_t *pamh,

+                                         const char *domain_name,

+                                         const char *suffix)

+ {

+     int ret;

+     struct stat stat_buf;

+     char *msg_buf = NULL;

+     int fd = -1;

+     size_t size;

+     size_t total_len;

+     char *filename = NULL;

+ 

+     if (strchr(suffix, '/') != NULL || strchr(domain_name, '/') != NULL) {

+         D(("Suffix [%s] or domain name [%s] contain illegal character.", suffix,

+            domain_name));

+         return EINVAL;

+     }

+ 

+     size = sizeof(PW_RESET_MSG_FILENAME_TEMPLATE) + strlen(domain_name) +

+            strlen(suffix);

+     filename = malloc(size);

+     if (filename == NULL) {

+         D(("malloc failed."));

+         ret = ENOMEM;

+         goto done;

+     }

+     ret = snprintf(filename, size, PW_RESET_MSG_FILENAME_TEMPLATE, domain_name,

+                    suffix);

+     if (ret < 0 || ret >= size) {

+         D(("snprintf failed."));

+         ret = EFAULT;

+         goto done;

+     }

+ 

+     fd = open(filename, O_RDONLY);

+     if (fd == -1) {

+         ret = errno;

+         D(("open failed [%d][%s].\n", ret, strerror(ret)));

+         goto done;

+     }

+ 

+     ret = fstat(fd, &stat_buf);

+     if (ret == -1) {

+         ret = errno;

+         D(("fstat failed [%d][%s].", ret, strerror(ret)));

+         goto done;

+     }

+ 

+     if (!S_ISREG(stat_buf.st_mode)) {

+         logger(pamh, LOG_ERR,

+                "Password reset message file is not a regular file.");

+         ret = EINVAL;

+         goto done;

+     }

+ 

+     if (stat_buf.st_uid != 0 || stat_buf.st_gid != 0 ||

+         (stat_buf.st_mode & ~S_IFMT) != 0644) {

+         logger(pamh, LOG_ERR,"Permission error, "

+                "file [%s] must be owned by root with permissions 0644.",

+                filename);

+         ret = EPERM;

+         goto done;

+     }

+ 

+     if (stat_buf.st_size > PW_RESET_MSG_MAX_SIZE) {

+         logger(pamh, LOG_ERR, "Password reset message file is too large.");

+         ret = EFBIG;

+         goto done;

+     }

+ 

+     msg_buf = malloc(stat_buf.st_size + 1);

+     if (msg_buf == NULL) {

+         D(("malloc failed."));

+         ret = ENOMEM;

+         goto done;

+     }

+ 

+ 

+     total_len = 0;

+     while (total_len < stat_buf.st_size) {

+         ret = read(fd, msg_buf + total_len, stat_buf.st_size - total_len);

+         if (ret == -1) {

+             if (errno == EINTR || errno == EAGAIN) continue;

+             ret = errno;

+             D(("read failed [%d][%s].", ret, strerror(ret)));

+             goto done;

+         }

+         total_len += ret;

+     }

+ 

+     ret = close(fd);

+     fd = -1;

+     if (ret == -1) {

+         ret = errno;

+         D(("close failed [%d][%s].", ret, strerror(ret)));

+     }

+ 

+     if (total_len != stat_buf.st_size) {

+         D(("read fewer bytes [%d] than expected [%d].", total_len,

+            stat_buf.st_size));

+         ret = EIO;

+         goto done;

+     }

+ 

+     msg_buf[stat_buf.st_size] = '\0';

+ 

+     ret = do_pam_conversation(pamh, PAM_TEXT_INFO, msg_buf, NULL, NULL);

+     if (ret != PAM_SUCCESS) {

+         D(("do_pam_conversation failed."));

+     }

+ 

+ done:

+     if (fd != -1) {

+         close(fd);

+     }

+     free(msg_buf);

+     free(filename);

+ 

+     return ret;

+ }

+ 

+ static errno_t select_pw_reset_message(pam_handle_t *pamh, struct pam_items *pi)

+ {

+     int ret;

+     char *locale;

+     const char *domain_name;

+ 

+     domain_name = pi->domain_name;

+     if (domain_name == NULL || *domain_name == '\0') {

+         D(("Domain name is unknown."));

+         return EINVAL;

+     }

+ 

+     locale = setlocale(LC_MESSAGES, NULL);

+ 

+     ret = -1;

+     if (locale != NULL) {

+         ret = display_pw_reset_message(pamh, domain_name, locale);

+     }

+ 

+     if (ret != 0) {

+         ret = display_pw_reset_message(pamh, domain_name, "txt");

+     }

+ 

+     if (ret != 0) {

+         ret = do_pam_conversation(pamh, PAM_TEXT_INFO,

+                       _("Password reset by root is not supported."),

+                       NULL, NULL);

+         if (ret != PAM_SUCCESS) {

+             D(("do_pam_conversation failed."));

+         }

+     }

+ 

+     return ret;

+ }

+ 

  static int user_info_offline_auth(pam_handle_t *pamh, size_t buflen,

                                    uint8_t *buf)

  {
@@ -420,7 +594,7 @@

      }

  

      ret = snprintf(user_msg, sizeof(user_msg), "%s%s%s.",

-                _("Offline authentication"),

+                _("Authenticated with cached credentials"),

                expire_str[0] ? _(", your cached password will expire at: ") : "",

                expire_str[0] ? expire_str : "");

      if (ret < 0 || ret >= sizeof(user_msg)) {
@@ -546,7 +720,7 @@

      }

  

      ret = snprintf(user_msg, sizeof(user_msg), "%s%s.",

-                    _("Offline authentication, authentication is denied until: "),

+                    _("Authentication is denied until: "),

                     delay_str);

      if (ret < 0 || ret >= sizeof(user_msg)) {

          D(("snprintf failed."));
@@ -679,7 +853,8 @@

      return ret;

  }

  

- static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf)

+ static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf,

+                          struct pam_items *pi)

  {

      int ret;

      size_t p=0;
@@ -721,13 +896,21 @@

          switch(type) {

              case SSS_PAM_SYSTEM_INFO:

                  if (buf[p + (len -1)] != '\0') {

-                     D(("user info does not end with \\0."));

+                     D(("system info does not end with \\0."));

                      break;

                  }

                  logger(pamh, LOG_INFO, "system info: [%s]", &buf[p]);

                  break;

              case SSS_PAM_DOMAIN_NAME:

+                 if (buf[p + (len -1)] != '\0') {

+                     D(("domain name does not end with \\0."));

+                     break;

+                 }

                  D(("domain name: [%s]", &buf[p]));

+                 pi->domain_name = strdup((char *) &buf[p]);

+                 if (pi->domain_name == NULL) {

+                     D(("strdup failed"));

+                 }

                  break;

              case SSS_ENV_ITEM:

              case SSS_PAM_ENV_ITEM:
@@ -765,6 +948,18 @@

                      D(("eval_user_info_response failed"));

                  }

                  break;

+             case SSS_PAM_TEXT_MSG:

+                 if (buf[p + (len -1)] != '\0') {

+                     D(("system info does not end with \\0."));

+                     break;

+                 }

+ 

+                 ret = do_pam_conversation(pamh, PAM_TEXT_INFO, (char *) &buf[p],

+                                           NULL, NULL);

+                 if (ret != PAM_SUCCESS) {

+                     D(("do_pam_conversation failed."));

+                 }

+                 break;

              default:

                  D(("Unknown response type [%d]", type));

          }
@@ -835,6 +1030,8 @@

      pi->login_name = pam_modutil_getlogin(pamh);

      if (pi->login_name == NULL) pi->login_name="";

  

+     pi->domain_name = NULL;

+ 

      return PAM_SUCCESS;

  }

  
@@ -877,10 +1074,13 @@

      }

      rd.data = buf;

  

+     errnop = 0;

      ret = sss_pam_make_request(task, &rd, &repbuf, &replen, &errnop);

  

      if (ret != NSS_STATUS_SUCCESS) {

-         logger(pamh, LOG_ERR, "Request to sssd failed.");

+         if (errnop != 0) {

+             logger(pamh, LOG_ERR, "Request to sssd failed. %s", ssscli_err2string(errnop));

+         }

          pam_status = PAM_SYSTEM_ERR;

          goto done;

      }
@@ -893,7 +1093,7 @@

      }

  

      pam_status = ((int32_t *)repbuf)[0];

-     ret = eval_response(pamh, replen, repbuf);

+     ret = eval_response(pamh, replen, repbuf, pi);

      if (ret != PAM_SUCCESS) {

          D(("eval_response failed."));

          pam_status = ret;
@@ -1021,8 +1221,10 @@

  }

  

  static void eval_argv(pam_handle_t *pamh, int argc, const char **argv,

-                       uint32_t *flags)

+                       uint32_t *flags, int *retries)

  {

+     char *ep;

+ 

      for (; argc-- > 0; ++argv) {

          if (strcmp(*argv, "forward_pass") == 0) {

              *flags |= FLAGS_FORWARD_PASS;
@@ -1030,6 +1232,28 @@

              *flags |= FLAGS_USE_FIRST_PASS;

          } else if (strcmp(*argv, "use_authtok") == 0) {

              *flags |= FLAGS_USE_AUTHTOK;

+         } else if (strncmp(*argv, OPT_RETRY_KEY, strlen(OPT_RETRY_KEY)) == 0) {

+             if (*(*argv+6) == '\0') {

+                 logger(pamh, LOG_ERR, "Missing argument to option retry.");

+                 *retries = 0;

+             } else {

+                 errno = 0;

+                 *retries = strtol(*argv+6, &ep, 10);

+                 if (errno != 0) {

+                     D(("strtol failed [%d][%s]", errno, strerror(errno)));

+                     *retries = 0;

+                 }

+                 if (*ep != '\0') {

+                     logger(pamh, LOG_ERR, "Argument to option retry contains "

+                                           "extra characters.");

+                     *retries = 0;

+                 }

+                 if (*retries < 0) {

+                     logger(pamh, LOG_ERR, "Argument to option retry must not "

+                                           "be negative.");

+                     *retries = 0;

+                 }

+             }

          } else {

              logger(pamh, LOG_WARNING, "unknown option: %s", *argv);

          }
@@ -1150,15 +1374,18 @@

                     int pam_flags, int argc, const char **argv)

  {

      int ret;

+     int pam_status;

      struct pam_items pi;

      uint32_t flags = 0;

      int *exp_data;

+     bool retry = false;

+     int retries = 0;

  

      bindtextdomain(PACKAGE, LOCALEDIR);

  

      D(("Hello pam_sssd: %d", task));

  

-     eval_argv(pamh, argc, argv, &flags);

+     eval_argv(pamh, argc, argv, &flags, &retries);

  

      ret = get_pam_items(pamh, &pi);

      if (ret != PAM_SUCCESS) {
@@ -1166,72 +1393,131 @@

          return ret;

      }

  

-     switch(task) {

-         case SSS_PAM_AUTHENTICATE:

-             ret = get_authtok_for_authentication(pamh, &pi, flags);

-             if (ret != PAM_SUCCESS) {

-                 D(("failed to get authentication token: %s",

-                    pam_strerror(pamh, ret)));

-                 return ret;

-             }

-             break;

-         case SSS_PAM_CHAUTHTOK:

-             ret = get_authtok_for_password_change(pamh, &pi, flags, pam_flags);

-             if (ret != PAM_SUCCESS) {

-                 D(("failed to get tokens for password change: %s",

-                    pam_strerror(pamh, ret)));

-                 return ret;

-             }

-             if (pam_flags & PAM_PRELIM_CHECK) {

-                 task = SSS_PAM_CHAUTHTOK_PRELIM;

-             }

-             break;

-         case SSS_PAM_ACCT_MGMT:

-         case SSS_PAM_SETCRED:

-         case SSS_PAM_OPEN_SESSION:

-         case SSS_PAM_CLOSE_SESSION:

-             break;

-         default:

-             D(("Illegal task [%d]", task));

-             return PAM_SYSTEM_ERR;

-     }

+     do {

+         retry = false;

  

-     ret = send_and_receive(pamh, &pi, task);

+         switch(task) {

+             case SSS_PAM_AUTHENTICATE:

+                 ret = get_authtok_for_authentication(pamh, &pi, flags);

+                 if (ret != PAM_SUCCESS) {

+                     D(("failed to get authentication token: %s",

+                        pam_strerror(pamh, ret)));

+                     return ret;

+                 }

+                 break;

+             case SSS_PAM_CHAUTHTOK:

+                 ret = get_authtok_for_password_change(pamh, &pi, flags, pam_flags);

+                 if (ret != PAM_SUCCESS) {

+                     D(("failed to get tokens for password change: %s",

+                        pam_strerror(pamh, ret)));

+                     return ret;

+                 }

+                 if (pam_flags & PAM_PRELIM_CHECK) {

+                     task = SSS_PAM_CHAUTHTOK_PRELIM;

+                 }

+                 break;

+             case SSS_PAM_ACCT_MGMT:

+             case SSS_PAM_SETCRED:

+             case SSS_PAM_OPEN_SESSION:

+             case SSS_PAM_CLOSE_SESSION:

+                 break;

+             default:

+                 D(("Illegal task [%d]", task));

+                 return PAM_SYSTEM_ERR;

+         }

  

- /* We allow sssd to send the return code PAM_NEW_AUTHTOK_REQD during

-  * authentication, see sss_cli.h for details */

-     if (ret == PAM_NEW_AUTHTOK_REQD && task == SSS_PAM_AUTHENTICATE) {

-         D(("Authtoken expired, trying to change it"));

+         pam_status = send_and_receive(pamh, &pi, task);

  

-         exp_data = malloc(sizeof(int));

-         if (exp_data == NULL) {

-             D(("malloc failed."));

-             return PAM_BUF_ERR;

-         }

-         *exp_data = 1;

-         ret = pam_set_data(pamh, PWEXP_FLAG, exp_data, free_exp_data);

-         if (ret != PAM_SUCCESS) {

-             D(("pam_set_data failed."));

-             return ret;

-         }

+         switch (task) {

+             case SSS_PAM_AUTHENTICATE:

+                 /* We allow sssd to send the return code PAM_NEW_AUTHTOK_REQD during

+                  * authentication, see sss_cli.h for details */

+                 if (pam_status == PAM_NEW_AUTHTOK_REQD) {

+                     D(("Authtoken expired, trying to change it"));

  

-         return PAM_SUCCESS;

-     }

+                     exp_data = malloc(sizeof(int));

+                     if (exp_data == NULL) {

+                         D(("malloc failed."));

+                         pam_status = PAM_BUF_ERR;

+                         break;

+                     }

+                     *exp_data = 1;

  

-     if (ret == PAM_SUCCESS && task == SSS_PAM_ACCT_MGMT &&

-         pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==

-                                                                   PAM_SUCCESS) {

-         ret = do_pam_conversation(pamh, PAM_TEXT_INFO,

-                 _("Password expired. Change your password now."), NULL, NULL);

-         if (ret != PAM_SUCCESS) {

-             D(("do_pam_conversation failed."));

+                     pam_status = pam_set_data(pamh, PWEXP_FLAG, exp_data,

+                                               free_exp_data);

+                     if (pam_status != PAM_SUCCESS) {

+                         D(("pam_set_data failed."));

+                     }

+                 }

+                 break;

+             case SSS_PAM_ACCT_MGMT:

+                 if (pam_status == PAM_SUCCESS &&

+                     pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) ==

+                                                                       PAM_SUCCESS) {

+                     ret = do_pam_conversation(pamh, PAM_TEXT_INFO,

+                                    _("Password expired. Change your password now."),

+                                    NULL, NULL);

+                     if (ret != PAM_SUCCESS) {

+                         D(("do_pam_conversation failed."));

+                     }

+                     pam_status = PAM_NEW_AUTHTOK_REQD;

+                 }

+                 break;

+             case SSS_PAM_CHAUTHTOK:

+                 if (pam_status != PAM_SUCCESS && pam_status != PAM_USER_UNKNOWN) {

+                     ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);

+                     if (ret != PAM_SUCCESS) {

+                         D(("Failed to unset PAM_AUTHTOK [%s]",

+                            pam_strerror(pamh,ret)));

+                     }

+                     ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);

+                     if (ret != PAM_SUCCESS) {

+                         D(("Failed to unset PAM_OLDAUTHTOK [%s]",

+                            pam_strerror(pamh,ret)));

+                     }

+                 }

+                 break;

+             case SSS_PAM_CHAUTHTOK_PRELIM:

+                 if (pam_status == PAM_PERM_DENIED && pi.pam_authtok_size == 0 &&

+                     getuid() == 0 &&

+                     pam_get_data(pamh, PWEXP_FLAG, (const void **) &exp_data) !=

+                                                                       PAM_SUCCESS) {

+ 

+                     ret = select_pw_reset_message(pamh, &pi);

+                     if (ret != 0) {

+                         D(("select_pw_reset_message failed.\n"));

+                     }

+                 }

+             default:

+                 /* nothing to do */

+                 break;

          }

-         return PAM_NEW_AUTHTOK_REQD;

-     }

  

-     overwrite_and_free_authtoks(&pi);

+         overwrite_and_free_pam_items(&pi);

  

-     return ret;

+         D(("retries [%d].", retries));

+ 

+         if (pam_status != PAM_SUCCESS &&

+             (task == SSS_PAM_AUTHENTICATE || task == SSS_PAM_CHAUTHTOK_PRELIM) &&

+             retries > 0) {

+             retry = true;

+             retries--;

+ 

+             flags &= !FLAGS_USE_FIRST_PASS;

+             ret = pam_set_item(pamh, PAM_AUTHTOK, NULL);

+             if (ret != PAM_SUCCESS) {

+                 D(("Failed to unset PAM_AUTHTOK [%s]",

+                    pam_strerror(pamh,ret)));

+             }

+             ret = pam_set_item(pamh, PAM_OLDAUTHTOK, NULL);

+             if (ret != PAM_SUCCESS) {

+                 D(("Failed to unset PAM_OLDAUTHTOK [%s]",

+                    pam_strerror(pamh,ret)));

+             }

+         }

+     } while(retry);

+ 

+     return pam_status;

  }

  

  PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,

file modified
+2
@@ -208,6 +208,7 @@

      /* only 1 result is accepted for this function */

      if (((uint32_t *)repbuf)[0] != 1) {

          *errnop = EBADMSG;

+         free(repbuf);

          return NSS_STATUS_TRYAGAIN;

      }

  
@@ -259,6 +260,7 @@

      /* only 1 result is accepted for this function */

      if (((uint32_t *)repbuf)[0] != 1) {

          *errnop = EBADMSG;

+         free(repbuf);

          return NSS_STATUS_TRYAGAIN;

      }

  

file modified
+16 -1
@@ -316,9 +316,13 @@

                            * @param String, zero terminated, of the form

                            * name=value. See putenv(3) and pam_putenv(3) for

                            * details. */

-     SSS_PAM_USER_INFO    /**< A message which should be displayed to the user.

+     SSS_PAM_USER_INFO,   /**< A message which should be displayed to the user.

                            * @param User info message, see #user_info_type

                            * for details. */

+     SSS_PAM_TEXT_MSG,    /**< A plain text message which should be displayed to

+                           * the user.This should only be used in the case where

+                           * it is not possile to use SSS_PAM_USER_INFO.

+                           * @param A zero terminated string. */

  };

  

  /**
@@ -406,6 +410,17 @@

   * @}

   */ /* end of group sss_pam_cli */

  

+ enum sss_cli_error_codes {

+     ESSS_SSS_CLI_ERROR_START = 0x1000,

+     ESSS_BAD_PRIV_SOCKET,

+     ESSS_BAD_PUB_SOCKET,

+     ESSS_BAD_CRED_MSG,

+     ESSS_SERVER_NOT_TRUSTED,

+ 

+     ESS_SSS_CLI_ERROR_MAX

+ };

+ 

+ const char *ssscli_err2string(int err);

  

  enum nss_status sss_nss_make_request(enum sss_cli_command cmd,

                                       struct sss_cli_req_data *rd,

file modified
+9
@@ -48,8 +48,17 @@

  

  stop() {

      echo -n $"Stopping $prog: "

+     pid=`cat $PID_FILE`

+ 

      killproc -p $PID_FILE $SSSD -TERM

      RETVAL=$?

+ 

+     # Wait until the monitor exits

+     while (checkpid $pid)

+     do

+         usleep 100000

+     done

+ 

      echo

      [ "$RETVAL" = 0 ] && rm -f $LOCK_FILE

      return $RETVAL

@@ -98,7 +98,7 @@

                                                             ret);

  

      ret = symlink(filename, newpath);

-     fail_unless(ret == 0, "symlink failed [%d][%s]", ret, strerror(ret));

+     fail_unless(ret == 0, "symlink failed [%d][%s]", ret, strerror(errno));

  

      ret = check_file(newpath, uid, gid, mode, CHECK_REG, NULL);

      unlink(newpath);

file modified
+4 -4
@@ -37,7 +37,7 @@

  

  #define USERNAME "testuser"

  #define UID "12345"

- #define PRINCIPLE_NAME "testuser@EXAMPLE.COM"

+ #define PRINCIPAL_NAME "testuser@EXAMPLE.COM"

  #define REALM "REALM.ORG"

  #define HOME_DIRECTORY "/home/testuser"

  #define CCACHE_DIR "/var/tmp"
@@ -379,7 +379,7 @@

  

      pd->user = discard_const(USERNAME);

      kr->uid = atoi(UID);

-     kr->upn = PRINCIPLE_NAME;

+     kr->upn = PRINCIPAL_NAME;

      pd->cli_pid = atoi(PID);

  

      krb5_ctx->opts = talloc_zero_array(tmp_ctx, struct dp_option, KRB5_OPTS);
@@ -457,8 +457,8 @@

  

  START_TEST(test_upn)

  {

-     do_test(BASE"_%p", CCACHE_DIR, BASE"_"PRINCIPLE_NAME, false);

-     do_test("%d/"FILENAME, BASE"_%p", BASE"_"PRINCIPLE_NAME"/"FILENAME, true);

+     do_test(BASE"_%p", CCACHE_DIR, BASE"_"PRINCIPAL_NAME, false);

+     do_test("%d/"FILENAME, BASE"_%p", BASE"_"PRINCIPAL_NAME"/"FILENAME, true);

  }

  END_TEST

  

file modified
+88
@@ -541,6 +541,93 @@

      talloc_free(req);

  }

  

+ START_TEST(test_resolv_sort_srv_reply)

+ {

+     int ret;

+     struct ares_srv_reply *replies = NULL;

+     struct ares_srv_reply *r, *prev = NULL;

+     struct resolv_test_ctx *test_ctx;

+     int num_replies = 3;

+     int i;

+ 

+     ret = setup_resolv_test(&test_ctx);

+     if (ret != EOK) {

+         fail("Could not set up test");

+         return;

+     }

+ 

+     check_leaks_push(test_ctx);

+ 

+     /* prepare linked list with reversed values */

+     for (i = 0; i<num_replies; i++) {

+         r = talloc_zero(test_ctx, struct ares_srv_reply);

+         fail_if(r == NULL);

+         r->priority = num_replies-i;

+         r->weight   = i;

+ 

+         if (!replies) {

+             replies = r;

+             prev = r;

+         } else {

+             prev->next = r;

+             prev = prev->next;

+         }

+     }

+ 

+     /* do the sort */

+     ret = resolv_sort_srv_reply(test_ctx, &replies);

+     fail_if(ret != EOK);

+ 

+     /* check if the list is sorted */

+     prev = NULL;

+     for (i = 1, r = replies; r; r=r->next, i++) {

+         talloc_zfree(prev);

+         prev = r;

+         fail_unless(r->priority == i);

+     }

+     talloc_zfree(prev);

+ 

+     /* check if the list is complete */

+     fail_unless(i-1 == num_replies);

+ 

+     /* test if the weighting algorithm runs..not much do

+      * deterministically test here since it is based on

+      * random weight-selection */

+     replies = NULL;

+     for (i = 0; i<num_replies; i++) {

+         r = talloc_zero(test_ctx, struct ares_srv_reply);

+         fail_if(r == NULL);

+         r->priority = i % 2 + 1;

+         r->weight   = i;

+ 

+         if (!replies) {

+             replies = r;

+             prev = r;

+         } else {

+             prev->next = r;

+             prev = prev->next;

+         }

+     }

+ 

+     /* do the sort */

+     ret = resolv_sort_srv_reply(test_ctx, &replies);

+     fail_if(ret != EOK);

+ 

+     /* clean up */

+     prev = NULL;

+     for (i = 1, r = replies; r; r=r->next, i++) {

+         talloc_zfree(prev);

+         prev = r;

+     }

+     talloc_zfree(prev);

+ 

+ 

+     /* check for leaks */

+     check_leaks_pop(test_ctx);

+     talloc_zfree(test_ctx);

+ }

+ END_TEST

+ 

  START_TEST(test_resolv_free_req)

  {

      int ret = EOK;
@@ -602,6 +689,7 @@

      /* Do some testing */

      tcase_add_test(tc_resolv, test_copy_hostent);

      tcase_add_test(tc_resolv, test_resolv_ip_addr);

+     tcase_add_test(tc_resolv, test_resolv_sort_srv_reply);

      if (use_net_test) {

          tcase_add_test(tc_resolv, test_resolv_internet);

          tcase_add_test(tc_resolv, test_resolv_negative);

file modified
+10 -10
@@ -38,15 +38,15 @@

  

  #define CHECK_RESULT(expected, actual) \

      do { \

-         fail_unless(result == expected, "Expected %ld, got %ld", \

-                                         expected, result); \

+         fail_unless(actual == expected, "Expected %ld, got %ld", \

+                                         expected, actual); \

      } while(0)

  

  #define CHECK_ERRNO(expected, actual) \

      do { \

-         fail_unless(error == ERANGE, "Expected errno %d[%s], got %d[%s]", \

-                                      ERANGE, strerror(ERANGE), \

-                                      error, strerror(ERANGE)); \

+         fail_unless(actual == expected, "Expected errno %d[%s], got %d[%s]", \

+                                         expected, strerror(expected), \

+                                         actual, strerror(actual)); \

      } while(0)

  

  #define CHECK_ENDPTR(expected, actual) \
@@ -146,7 +146,7 @@

  

      CHECK_ERRNO(ERANGE, error);

      CHECK_ZERO_ENDPTR(endptr);

-     CHECK_RESULT(expected, actual);

+     CHECK_RESULT(expected, result);

  }

  END_TEST

  
@@ -163,7 +163,7 @@

  

      CHECK_ERRNO(ERANGE, error);

      CHECK_ZERO_ENDPTR(endptr);

-     CHECK_RESULT(expected, actual);

+     CHECK_RESULT(expected, result);

  }

  END_TEST

  
@@ -265,14 +265,14 @@

  {

      uint32_t result;

      const char *input = "-123";

-     uint32_t expected = -123;

+     uint32_t expected = UINT32_MAX;

      char *endptr;

      errno_t error;

  

      result = strtouint32(input, &endptr, 10);

      error = errno;

  

-     EXPECT_UNSET_ERRNO(error);

+     CHECK_ERRNO(ERANGE, error);

      CHECK_ZERO_ENDPTR(endptr);

      CHECK_RESULT(expected, result);

  }
@@ -309,7 +309,7 @@

  

      CHECK_ERRNO(ERANGE, error);

      CHECK_ZERO_ENDPTR(endptr);

-     CHECK_RESULT(expected, actual);

+     CHECK_RESULT(expected, result);

  }

  END_TEST

  

file modified
+280 -4
@@ -511,6 +511,39 @@

      return test_return(data, ret);

  }

  

+ static void test_add_incomplete_group_done(struct tevent_req *subreq);

+ 

+ static void test_add_incomplete_group(struct tevent_req *req)

+ {

+     struct test_data *data = tevent_req_callback_data(req, struct test_data);

+     struct tevent_req *subreq;

+     int ret;

+ 

+     ret = sysdb_transaction_recv(req, data, &data->handle);

+     if (ret != EOK) {

+         return test_return(data, ret);

+     }

+ 

+     subreq = sysdb_add_incomplete_group_send(data, data->ev, data->handle,

+                                        data->ctx->domain, data->groupname,

+                                        data->gid);

+     if (!subreq) {

+         test_return(data, ret);

+     }

+     tevent_req_set_callback(subreq, test_add_incomplete_group_done, data);

+ }

+ 

+ static void test_add_incomplete_group_done(struct tevent_req *subreq)

+ {

+     struct test_data *data = tevent_req_callback_data(subreq, struct test_data);

+     int ret;

+ 

+     ret = sysdb_add_group_recv(subreq);

+     talloc_zfree(subreq);

+ 

+     return test_return(data, ret);

+ }

+ 

  static void test_remove_group_done(struct tevent_req *subreq);

  

  static void test_remove_group(struct tevent_req *req)
@@ -798,7 +831,8 @@

  

      subreq = sysdb_add_group_member_send(data, data->ev,

                                           data->handle, data->ctx->domain,

-                                          data->groupname, username);

+                                          data->groupname, username,

+                                          SYSDB_MEMBER_USER);

      if (!subreq) {

          test_return(data, ENOMEM);

      }
@@ -836,7 +870,8 @@

  

      subreq = sysdb_remove_group_member_send(data, data->ev,

                                              data->handle, data->ctx->domain,

-                                             data->groupname, username);

+                                             data->groupname, username,

+                                             SYSDB_MEMBER_USER);

      if (!subreq) {

          test_return(data, ENOMEM);

      }
@@ -1179,6 +1214,41 @@

  }

  END_TEST

  

+ START_TEST (test_sysdb_add_incomplete_group)

+ {

+     struct sysdb_test_ctx *test_ctx;

+     struct test_data *data;

+     struct tevent_req *req;

+     int ret;

+ 

+     /* Setup */

+     ret = setup_sysdb_tests(&test_ctx);

+     if (ret != EOK) {

+         fail("Could not set up the test");

+         return;

+     }

+ 

+     data = talloc_zero(test_ctx, struct test_data);

+     data->ctx = test_ctx;

+     data->ev = test_ctx->ev;

+     data->gid = _i;

+     data->groupname = talloc_asprintf(data, "testgroup%d", _i);

+ 

+     req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);

+     if (!req) {

+         ret = ENOMEM;

+     }

+ 

+     if (ret == EOK) {

+         tevent_req_set_callback(req, test_add_incomplete_group, data);

+         ret = test_loop(data);

+     }

+ 

+     fail_if(ret != EOK, "Could not store incomplete group #%d", _i);

+     talloc_free(test_ctx);

+ }

+ END_TEST

+ 

  START_TEST (test_sysdb_remove_local_user)

  {

      struct sysdb_test_ctx *test_ctx;
@@ -2313,7 +2383,7 @@

      req = sysdb_cache_auth_send(data, test_ctx->ev, test_ctx->sysdb,

                                  test_ctx->domain, data->username,

                                  (const uint8_t *) password, strlen(password),

-                                 test_ctx->confdb);

+                                 test_ctx->confdb, false);

      fail_unless(req != NULL, "sysdb_cache_password_send failed.");

  

      tevent_req_set_callback(req, test_search_done, data);
@@ -2388,7 +2458,7 @@

      req = sysdb_cache_auth_send(data, test_ctx->ev, test_ctx->sysdb,

                                  test_ctx->domain, data->username,

                                  (const uint8_t *) password, strlen(password),

-                                 test_ctx->confdb);

+                                 test_ctx->confdb, false);

      fail_unless(req != NULL, "sysdb_cache_password_send failed.");

  

      tevent_req_set_callback(req, test_search_done, data);
@@ -3124,6 +3194,203 @@

  }

  END_TEST

  

+ START_TEST (test_sysdb_attrs_to_list)

+ {

+     struct sysdb_attrs *attrs_list[3];

+     char **list;

+     errno_t ret;

+ 

+     TALLOC_CTX *test_ctx = talloc_new(NULL);

+ 

+     attrs_list[0] = sysdb_new_attrs(test_ctx);

+     sysdb_attrs_add_string(attrs_list[0], "test_attr", "attr1");

+     attrs_list[1] = sysdb_new_attrs(test_ctx);

+     sysdb_attrs_add_string(attrs_list[1], "test_attr", "attr2");

+     attrs_list[2] = sysdb_new_attrs(test_ctx);

+     sysdb_attrs_add_string(attrs_list[2], "nottest_attr", "attr3");

+ 

+     ret = sysdb_attrs_to_list(test_ctx, attrs_list, 3,

+                               "test_attr", &list);

+     fail_unless(ret == EOK, "sysdb_attrs_to_list failed with code %d", ret);

+ 

+     fail_unless(strcmp(list[0],"attr1") == 0, "Expected [attr1], got [%s]",

+                                               list[0]);

+     fail_unless(strcmp(list[1],"attr2") == 0, "Expected [attr2], got [%s]",

+                                               list[1]);

+     fail_unless(list[2] == NULL, "List should be NULL-terminated");

+ 

+     talloc_free(test_ctx);

+ }

+ END_TEST

+ 

+ static void test_sysdb_update_members_add(struct tevent_req *req);

+ START_TEST (test_sysdb_update_members)

+ {

+     struct sysdb_test_ctx *test_ctx;

+     struct test_data *data;

+     struct tevent_req *req;

+     int ret;

+ 

+     /* Setup */

+     ret = setup_sysdb_tests(&test_ctx);

+     if (ret != EOK) {

+         fail("Could not set up the test");

+         return;

+     }

+ 

+     data = talloc_zero(test_ctx, struct test_data);

+     data->ctx = test_ctx;

+     data->ev = test_ctx->ev;

+ 

+     /* Start the transaction */

+     req = sysdb_transaction_send(data, data->ev, test_ctx->sysdb);

+     if (!req) {

+         ret = ENOMEM;

+     }

+ 

+     if (ret == EOK) {

+         tevent_req_set_callback(req, test_sysdb_update_members_add, data);

+ 

+         ret = test_loop(data);

+     }

+ 

+     fail_if(ret != EOK, "Could not test sysdb_update_members");

+     talloc_free(test_ctx);

+ }

+ END_TEST

+ 

+ static void test_sysdb_update_members_add_del(struct tevent_req *req);

+ static void test_sysdb_update_members_add(struct tevent_req *req)

+ {

+     struct test_data *data = tevent_req_callback_data(req, struct test_data);

+     char **add_groups;

+     char *user;

+     errno_t ret;

+ 

+     ret = sysdb_transaction_recv(req, data, &data->handle);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(0, ("Could not start transaction\n"));

+         test_return(data, ret);

+         return;

+     }

+ 

+     /* Add a user to two groups */

+     data->username = talloc_strdup(data, "testuser27000");

+     user = talloc_strdup(data, data->username);

+     add_groups = talloc_array(data, char *, 3);

+     add_groups[0] = talloc_strdup(data, "testgroup28001");

+     add_groups[1] = talloc_strdup(data, "testgroup28002");

+     add_groups[2] = NULL;

+ 

+     req = sysdb_update_members_send(data, data->ev, data->handle,

+                                     data->ctx->domain, user,

+                                     SYSDB_MEMBER_USER,

+                                     add_groups, NULL);

+     talloc_free(add_groups);

+     talloc_free(user);

+     if (!req) {

+         DEBUG(0, ("Could not add groups\n"));

+         test_return(data, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(req, test_sysdb_update_members_add_del, data);

+ }

+ 

+ static void test_sysdb_update_members_del(struct tevent_req *req);

+ static void test_sysdb_update_members_add_del(struct tevent_req *req)

+ {

+     struct test_data *data = tevent_req_callback_data(req, struct test_data);

+     errno_t ret;

+     char **add_groups = NULL;

+     char **del_groups = NULL;

+     char *user;

+ 

+     ret = sysdb_update_members_recv(req);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(0, ("Group addition failed [%d](%s)\n", ret, strerror(ret)));

+         test_return(data, ret);

+         return;

+     }

+ 

+     /* Remove a user from one group and add to another */

+     user = talloc_strdup(data, data->username);

+     del_groups = talloc_array(data, char *, 2);

+     del_groups[0] = talloc_strdup(del_groups, "testgroup28001");

+     del_groups[1] = NULL;

+     add_groups = talloc_array(data, char *, 2);

+     add_groups[0] = talloc_strdup(add_groups, "testgroup28003");

+     add_groups[1] = NULL;

+ 

+     req = sysdb_update_members_send(data, data->ev, data->handle,

+                                     data->ctx->domain, user,

+                                     SYSDB_MEMBER_USER,

+                                     add_groups, del_groups);

+     talloc_free(add_groups);

+     talloc_free(del_groups);

+     talloc_free(user);

+     if (!req) {

+         DEBUG(0, ("Could not add/del groups\n"));

+         test_return(data, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(req, test_sysdb_update_members_del, data);

+ }

+ 

+ static void test_sysdb_update_members_done(struct tevent_req *req);

+ static void test_sysdb_update_members_del(struct tevent_req *req)

+ {

+     struct test_data *data = tevent_req_callback_data(req, struct test_data);

+     errno_t ret;

+     char **del_groups = NULL;

+     char *user;

+ 

+     ret = sysdb_update_members_recv(req);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(0, ("Group replace failed [%d](%s)\n", ret, strerror(ret)));

+         test_return(data, EIO);

+         return;

+     }

+ 

+     /* Remove a user from one group and add to another */

+     user = talloc_strdup(data, data->username);

+     del_groups = talloc_array(data, char *, 3);

+     del_groups[0] = talloc_strdup(del_groups, "testgroup28002");

+     del_groups[1] = talloc_strdup(del_groups, "testgroup28003");

+     del_groups[2] = NULL;

+ 

+     req = sysdb_update_members_send(data, data->ev, data->handle,

+                                     data->ctx->domain, user,

+                                     SYSDB_MEMBER_USER,

+                                     NULL, del_groups);

+     talloc_free(del_groups);

+     talloc_free(user);

+     if (!req) {

+         DEBUG(0, ("Could not del groups\n"));

+         test_return(data, EIO);

+         return;

+     }

+ 

+     tevent_req_set_callback(req, test_sysdb_update_members_done, data);

+ }

+ 

+ static void test_sysdb_update_members_done(struct tevent_req *req)

+ {

+     struct test_data *data = tevent_req_callback_data(req, struct test_data);

+     errno_t ret;

+ 

+     ret = sysdb_update_members_recv(req);

+     talloc_zfree(req);

+     if (ret != EOK) {

+         DEBUG(0, ("Group delete failed [%d](%s)\n", ret, strerror(ret)));

+     }

+     test_return(data, ret);

+ }

+ 

  Suite *create_sysdb_suite(void)

  {

      Suite *s = suite_create("sysdb");
@@ -3148,6 +3415,9 @@

      /* test the change */

      tcase_add_loop_test(tc_sysdb, test_sysdb_get_user_attr, 27000, 27010);

  

+     /* Add and remove users in a group with sysdb_update_members */

+     tcase_add_test(tc_sysdb, test_sysdb_update_members);

+ 

      /* Remove the other half by gid */

      tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_group_by_gid, 28000, 28010);

  
@@ -3175,6 +3445,10 @@

      /* Create a new group */

      tcase_add_loop_test(tc_sysdb, test_sysdb_store_group, 28010, 28020);

  

+     /* Create and remove a incomplete group */

+     tcase_add_loop_test(tc_sysdb, test_sysdb_add_incomplete_group, 28020, 28030);

+     tcase_add_loop_test(tc_sysdb, test_sysdb_remove_local_group, 28020, 28030);

+ 

      /* Verify the groups were added */

  

      /* Verify the groups can be queried by GID */
@@ -3233,6 +3507,8 @@

  

      tcase_add_test(tc_sysdb, test_sysdb_attrs_replace_name);

  

+     tcase_add_test(tc_sysdb, test_sysdb_attrs_to_list);

+ 

  /* Add all test cases to the test suite */

      suite_add_tcase(s, tc_sysdb);

  

file added
+242
@@ -0,0 +1,242 @@

+ /*

+     SSSD

+ 

+     util-tests.c

+ 

+     Authors:

+         Stephen Gallagher <sgallagh@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include <popt.h>

+ #include <talloc.h>

+ #include <check.h>

+ #include "util/util.h"

+ #include "tests/common.h"

+ 

+ START_TEST(test_diff_string_lists)

+ {

+     TALLOC_CTX *test_ctx;

+     char **l1;

+     char **l2;

+     char **l3;

+     char **only_l1;

+     char **only_l2;

+     char **both;

+     int ret;

+ 

+     test_ctx = talloc_new(NULL);

+ 

+     /* Test with all values returned */

+     l1 = talloc_array(test_ctx, char *, 4);

+     l1[0] = talloc_strdup(l1, "a");

+     l1[1] = talloc_strdup(l1, "b");

+     l1[2] = talloc_strdup(l1, "c");

+     l1[3] = NULL;

+ 

+     l2 = talloc_array(test_ctx, char *, 4);

+     l2[0] = talloc_strdup(l1, "d");

+     l2[1] = talloc_strdup(l1, "c");

+     l2[2] = talloc_strdup(l1, "b");

+     l2[3] = NULL;

+ 

+     ret = diff_string_lists(test_ctx,

+                             l1, l2,

+                             &only_l1, &only_l2, &both);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");

+     fail_unless(only_l1[1] == NULL, "only_l1 not NULL-terminated");

+     fail_unless(strcmp(only_l2[0], "d") == 0, "Missing \"d\" from only_l2");

+     fail_unless(only_l2[1] == NULL, "only_l2 not NULL-terminated");

+     fail_unless(strcmp(both[0], "c") == 0, "Missing \"c\" from both");

+     fail_unless(strcmp(both[1], "b") == 0, "Missing \"b\" from both");

+     fail_unless(both[2] == NULL, "both not NULL-terminated");

+ 

+     talloc_zfree(only_l1);

+     talloc_zfree(only_l2);

+     talloc_zfree(both);

+ 

+     /* Test with restricted return values */

+     ret = diff_string_lists(test_ctx,

+                             l1, l2,

+                             &only_l1, &only_l2, NULL);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");

+     fail_unless(only_l1[1] == NULL, "only_l1 not NULL-terminated");

+     fail_unless(strcmp(only_l2[0], "d") == 0, "Missing \"d\" from only_l2");

+     fail_unless(only_l2[1] == NULL, "only_l2 not NULL-terminated");

+     fail_unless(both == NULL, "Nothing returned to both");

+ 

+     talloc_zfree(only_l1);

+     talloc_zfree(only_l2);

+     talloc_zfree(both);

+ 

+     ret = diff_string_lists(test_ctx,

+                             l1, l2,

+                             &only_l1, NULL, NULL);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");

+     fail_unless(only_l1[1] == NULL, "only_l1 not NULL-terminated");

+     fail_unless(only_l2 == NULL, "Nothing returned to only_l2");

+     fail_unless(both == NULL, "Nothing returned to both");

+ 

+     talloc_zfree(only_l1);

+     talloc_zfree(only_l2);

+     talloc_zfree(both);

+ 

+     ret = diff_string_lists(test_ctx,

+                             l1, l2,

+                             NULL, &only_l2, NULL);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(strcmp(only_l2[0], "d") == 0, "Missing \"d\" from only_l2");

+     fail_unless(only_l2[1] == NULL, "only_l2 not NULL-terminated");

+     fail_unless(only_l1 == NULL, "Nothing returned to only_l1");

+     fail_unless(both == NULL, "Nothing returned to both");

+ 

+     talloc_zfree(only_l1);

+     talloc_zfree(only_l2);

+     talloc_zfree(both);

+ 

+     /* Test with no overlap */

+     l3 = talloc_array(test_ctx, char *, 4);

+     l3[0] = talloc_strdup(l1, "d");

+     l3[1] = talloc_strdup(l1, "e");

+     l3[2] = talloc_strdup(l1, "f");

+     l3[3] = NULL;

+ 

+     ret = diff_string_lists(test_ctx,

+                             l1, l3,

+                             &only_l1, &only_l2, &both);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");

+     fail_unless(strcmp(only_l1[1], "b") == 0, "Missing \"b\" from only_l1");

+     fail_unless(strcmp(only_l1[2], "c") == 0, "Missing \"c\" from only_l1");

+     fail_unless(only_l1[3] == NULL, "only_l1 not NULL-terminated");

+     fail_unless(strcmp(only_l2[0], "d") == 0, "Missing \"f\" from only_l2");

+     fail_unless(strcmp(only_l2[1], "e") == 0, "Missing \"e\" from only_l2");

+     fail_unless(strcmp(only_l2[2], "f") == 0, "Missing \"d\" from only_l2");

+     fail_unless(only_l2[3] == NULL, "only_l2 not NULL-terminated");

+     fail_unless(both[0] == NULL, "both should have zero entries");

+ 

+     talloc_zfree(only_l1);

+     talloc_zfree(only_l2);

+     talloc_zfree(both);

+ 

+     /* Test with 100% overlap */

+     ret = diff_string_lists(test_ctx,

+                             l1, l1,

+                             &only_l1, &only_l2, &both);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(only_l1[0] == NULL, "only_l1 should have zero entries");

+     fail_unless(only_l2[0] == NULL, "only_l2 should have zero entries");

+     fail_unless(strcmp(both[0], "a") == 0, "Missing \"a\" from both");

+     fail_unless(strcmp(both[1], "b") == 0, "Missing \"b\" from both");

+     fail_unless(strcmp(both[2], "c") == 0, "Missing \"c\" from both");

+     fail_unless(both[3] == NULL, "both is not NULL-terminated");

+ 

+     talloc_zfree(only_l1);

+     talloc_zfree(only_l2);

+     talloc_zfree(both);

+ 

+     /* Test with no second list */

+     ret = diff_string_lists(test_ctx,

+                             l1, NULL,

+                             &only_l1, &only_l2, &both);

+ 

+     fail_unless(ret == EOK, "diff_string_lists returned error [%d]", ret);

+     fail_unless(strcmp(only_l1[0], "a") == 0, "Missing \"a\" from only_l1");

+     fail_unless(strcmp(only_l1[1], "b") == 0, "Missing \"b\" from only_l1");

+     fail_unless(strcmp(only_l1[2], "c") == 0, "Missing \"c\" from only_l1");

+     fail_unless(only_l1[3] == NULL, "only_l1 not NULL-terminated");

+     fail_unless(only_l2[0] == NULL, "only_l2 should have zero entries");

+     fail_unless(both[0] == NULL, "both should have zero entries");

+ 

+     talloc_free(test_ctx);

+ }

+ END_TEST

+ 

+ START_TEST(test_size_t_overflow)

+ {

+     fail_unless(!SIZE_T_OVERFLOW(1, 1), "unexpected overflow");

+     fail_unless(!SIZE_T_OVERFLOW(SIZE_T_MAX, 0), "unexpected overflow");

+     fail_unless(!SIZE_T_OVERFLOW(SIZE_T_MAX-10, 10), "unexpected overflow");

+     fail_unless(SIZE_T_OVERFLOW(SIZE_T_MAX, 1), "overflow not detected");

+     fail_unless(SIZE_T_OVERFLOW(SIZE_T_MAX, SIZE_T_MAX),

+                 "overflow not detected");

+     fail_unless(SIZE_T_OVERFLOW(SIZE_T_MAX, ULLONG_MAX),

+                 "overflow not detected");

+     fail_unless(SIZE_T_OVERFLOW(SIZE_T_MAX, -10), "overflow not detected");

+ }

+ END_TEST

+ 

+ Suite *util_suite(void)

+ {

+     Suite *s = suite_create("util");

+ 

+     TCase *tc_util = tcase_create("util");

+ 

+     tcase_add_test (tc_util, test_diff_string_lists);

+     tcase_add_test (tc_util, test_size_t_overflow);

+     tcase_set_timeout(tc_util, 60);

+ 

+     suite_add_tcase (s, tc_util);

+ 

+     return s;

+ }

+ 

+ int main(int argc, const char *argv[])

+ {

+     int opt;

+     int failure_count;

+     poptContext pc;

+     Suite *s = util_suite();

+     SRunner *sr = srunner_create (s);

+ 

+     struct poptOption long_options[] = {

+         POPT_AUTOHELP

+         SSSD_MAIN_OPTS

+         { NULL }

+     };

+ 

+     pc = poptGetContext(argv[0], argc, argv, long_options, 0);

+     while((opt = poptGetNextOpt(pc)) != -1) {

+         switch(opt) {

+         default:

+             fprintf(stderr, "\nInvalid option %s: %s\n\n",

+                     poptBadOption(pc, 0), poptStrerror(opt));

+             poptPrintUsage(pc, stderr, 0);

+             return 1;

+         }

+     }

+     poptFreeContext(pc);

+ 

+     tests_set_cwd();

+ 

+     srunner_run_all(sr, CK_ENV);

+     failure_count = srunner_ntests_failed (sr);

+     srunner_free (sr);

+     if (failure_count == 0) {

+         return EXIT_SUCCESS;

+     }

+     return  EXIT_FAILURE;

+ }

file modified
+56 -22
@@ -110,7 +110,7 @@

      struct dirent direntp;

      struct stat statres;

      DIR *rootdir = NULL;

-     int ret;

+     int ret, err;

  

      rootdir = opendir(root);

      if (rootdir == NULL) {
@@ -174,6 +174,7 @@

      }

  

      ret = closedir(rootdir);

+     rootdir = NULL;

      if (ret != 0) {

          ret = errno;

          goto fail;
@@ -185,7 +186,15 @@

          goto fail;

      }

  

+     ret = EOK;

+ 

  fail:

+     if (rootdir) {  /* clean up on abnormal exit but retain return code */

+         err = closedir(rootdir);

+         if (err) {

+             DEBUG(1, ("closedir failed, bad dirp?\n"));

+         }

+     }

      return ret;

  }

  
@@ -402,7 +411,7 @@

      int ifd = -1;

      int ofd = -1;

      char buf[1024];

-     ssize_t cnt, written, offset;

+     ssize_t cnt, written, res;

      struct stat fstatbuf;

  

      ifd = open(src, O_RDONLY);
@@ -454,28 +463,45 @@

          goto fail;

      }

  

-     while ((cnt = read(ifd, buf, sizeof(buf))) > 0) {

-         offset = 0;

-         while (cnt > 0) {

-             written = write(ofd, buf+offset, (size_t)cnt);

-             if (written == -1) {

-                 ret = errno;

-                 DEBUG(1, ("Cannot write() to source file '%s': [%d][%s].\n",

-                             dst, ret, strerror(ret)));

-                 goto fail;

+     while ((cnt = read(ifd, buf, sizeof(buf))) != 0) {

+         if (cnt == -1) {

+             if (errno == EINTR || errno == EAGAIN) {

+                 continue;

              }

-             offset += written;

-             cnt -= written;

+ 

+             DEBUG(1, ("Cannot read() from source file '%s': [%d][%s].\n",

+                         src, ret, strerror(ret)));

+             goto fail;

+         }

+         else if (cnt > 0) {

+             /* Copy the buffer to the new file */

+             written = 0;

+             while (written < cnt) {

+                 res = write(ofd, buf+written, (size_t)cnt-written);

+                 if (res == -1) {

+                     ret = errno;

+                     if (ret == EINTR || ret == EAGAIN) {

+                         /* retry the write */

+                         continue;

+                     }

+                     DEBUG(1, ("Cannot write() to destination file '%s': [%d][%s].\n",

+                                 dst, ret, strerror(ret)));

+                     goto fail;

+                 }

+                 else if (res <= 0) {

+                     DEBUG(1, ("Unexpected result from write(): [%d]\n", res));

+                     goto fail;

+                 }

+ 

+                 written += res;

+             }

+         }

+         else {

+             DEBUG(1, ("Unexpected return code of read [%d]\n", cnt));

+             goto fail;

          }

-     }

-     if (cnt == -1) {

-         ret = errno;

-         DEBUG(1, ("Cannot read() from source file '%s': [%d][%s].\n",

-                     dst, ret, strerror(ret)));

-         goto fail;

      }

  

- 

      ret = close(ifd);

      ifd = -1;

      if (ret != 0) {
@@ -586,8 +612,8 @@

                           uid_t uid,

                           gid_t gid)

  {

-     DIR *src_dir;

-     int ret;

+     DIR *src_dir = NULL;

+     int ret, err;

      struct dirent *result;

      struct dirent direntp;

      char *src_name, *dst_name;
@@ -634,12 +660,20 @@

      }

  

      ret = closedir(src_dir);

+     src_dir = NULL;

      if (ret != 0) {

          ret = errno;

          goto fail;

      }

  

+     ret = EOK;

  fail:

+     if (src_dir) {  /* clean up on abnormal exit but retain return code */

+         err = closedir(src_dir);

+         if (err) {

+             DEBUG(1, ("closedir failed, bad dirp?\n"));

+         }

+     }

      talloc_free(tmp_ctx);

      return ret;

  }

file modified
+3 -3
@@ -116,11 +116,11 @@

  

      va_start(ap, fmt);

      ret = vasprintf(&message, fmt, ap);

+     va_end(ap);

      if (ret < 0) {

          /* ENOMEM */

          return;

      }

-     va_end(ap);

  

      if (level <= debug_level) {

          if (debug_timestamps) {
@@ -324,7 +324,7 @@

      }

  

      ret = semanage_commit(handle);

-     if (ret != 0) {

+     if (ret < 0) {

          DEBUG(1, ("Cannot commit SELinux transaction\n"));

          ret = EIO;

          goto done;
@@ -394,7 +394,7 @@

      }

  

      ret = semanage_commit(handle);

-     if (ret != 0) {

+     if (ret < 0) {

          DEBUG(1, ("Cannot commit SELinux transaction\n"));

          ret = EIO;

          goto done;

file modified
+9 -1
@@ -595,11 +595,13 @@

                                         const char *, state->ndirect+2);

          if (!state->direct) {

              tevent_req_error(req, ENOMEM);

+             return;

          }

  

          state->direct[state->ndirect] = talloc_strdup(state->direct, name);

          if (!state->direct[state->ndirect]) {

              tevent_req_error(req, ENOMEM);

+             return;

          }

  

          state->direct[state->ndirect+1] = NULL;
@@ -718,6 +720,7 @@

      struct group_show_recurse *recurse_state = tevent_req_data(req,

                                                        struct group_show_recurse);

      const char **group_members = NULL;

+     const char **gm = NULL;

      int nmembers = 0;

      struct ldb_message *msg = NULL;

      int ret;
@@ -756,8 +759,13 @@

              tevent_req_error(req, ENOMEM);

              return;

          }

+ 

          /* to free group_members in the callback */

-         group_members = talloc_move(recurse_req, &group_members);

+         gm = talloc_move(recurse_req, &group_members);

+         if (gm == NULL) {

+             tevent_req_error(req, ENOMEM);

+             return;

+         }

          tevent_req_set_callback(recurse_req, group_show_recurse_level_done, req);

          return;

      }

file modified
+3 -80
@@ -32,76 +32,9 @@

  #include "tools/tools_util.h"

  #include "tools/sss_sync_ops.h"

  

- static void get_gid_callback(void *ptr, int error, struct ldb_result *res)

- {

-     struct tools_ctx *tctx = talloc_get_type(ptr, struct tools_ctx);

- 

-     if (error) {

-         tctx->error = error;

-         return;

-     }

- 

-     switch (res->count) {

-     case 0:

-         tctx->error = ENOENT;

-         break;

- 

-     case 1:

-         tctx->octx->gid = ldb_msg_find_attr_as_uint(res->msgs[0], SYSDB_GIDNUM, 0);

-         if (tctx->octx->gid == 0) {

-             tctx->error = ERANGE;

-         }

-         break;

- 

-     default:

-         tctx->error = EFAULT;

-         break;

-     }

- }

- 

- /* Returns a gid for a given groupname. If a numerical gid

-  * is given, returns that as integer (rationale: shadow-utils)

-  * On error, returns -EINVAL

-  */

- static int get_gid(struct tools_ctx *tctx, const char *groupname)

- {

-     char *end_ptr;

-     int ret;

- 

-     errno = 0;

-     tctx->octx->gid = strtoul(groupname, &end_ptr, 10);

-     if (groupname == '\0' || *end_ptr != '\0' ||

-         errno != 0 || tctx->octx->gid == 0) {

-         /* Does not look like a gid - find the group name */

- 

-         ret = sysdb_getgrnam(tctx->octx, tctx->sysdb,

-                              tctx->octx->domain, groupname,

-                              get_gid_callback, tctx);

-         if (ret != EOK) {

-             DEBUG(1, ("sysdb_getgrnam failed: %d\n", ret));

-             goto done;

-         }

- 

-         tctx->error = EOK;

-         tctx->octx->gid = 0;

-         while ((tctx->error == EOK) && (tctx->octx->gid == 0)) {

-             tevent_loop_once(tctx->ev);

-         }

- 

-         if (tctx->error) {

-             DEBUG(1, ("sysdb_getgrnam failed: %d\n", ret));

-             goto done;

-         }

-     }

- 

- done:

-     return ret;

- }

- 

  int main(int argc, const char **argv)

  {

      uid_t pc_uid = 0;

-     const char *pc_group = NULL;

      const char *pc_gecos = NULL;

      const char *pc_home = NULL;

      char *pc_shell = NULL;
@@ -114,7 +47,6 @@

          POPT_AUTOHELP

          { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0, _("The debug level to run with"), NULL },

          { "uid",   'u', POPT_ARG_INT, &pc_uid, 0, _("The UID of the user"), NULL },

-         { "gid",   'g', POPT_ARG_STRING, &pc_group, 0, _("The GID or group name of the user"), NULL },

          { "gecos", 'c', POPT_ARG_STRING, &pc_gecos, 0, _("The comment string"), NULL },

          { "home",  'h', POPT_ARG_STRING, &pc_home, 0, _("Home directory"), NULL },

          { "shell", 's', POPT_ARG_STRING, &pc_shell, 0, _("Login shell"), NULL },
@@ -149,6 +81,7 @@

              case 'G':

                  groups = poptGetOptArg(pc);

                  if (!groups) goto fini;

+                 break;

  

              case 'm':

                  pc_create_home = DO_CREATE_HOME;
@@ -224,16 +157,6 @@

          }

      }

  

-     /* Same as shadow-utils useradd, -g can specify gid or group name */

-     if (pc_group != NULL) {

-         ret = get_gid(tctx, pc_group);

-         if (ret != EOK) {

-             ERROR("Cannot get group information for the user\n");

-             ret = EXIT_FAILURE;

-             goto fini;

-         }

-     }

- 

      tctx->octx->uid = pc_uid;

  

      /*
@@ -283,9 +206,9 @@

  

      /* Create user's home directory and/or mail spool */

      if (tctx->octx->create_homedir) {

-         /* We need to know the UID and GID of the user, if

+         /* We need to know the UID of the user, if

           * sysdb did assign it automatically, do a lookup */

-         if (tctx->octx->uid == 0 || tctx->octx->gid == 0) {

+         if (tctx->octx->uid == 0) {

              ret = sysdb_getpwnam_sync(tctx,

                                        tctx->ev,

                                        tctx->sysdb,

file modified
+2 -2
@@ -86,7 +86,7 @@

      while (1) {

          num = read(src_fd, buf, BUFFER_SIZE);

          if (num < 0) {

-             if (errno == EINTR) continue;

+             if (errno == EINTR || errno == EAGAIN) continue;

              ret = errno;

              DEBUG(dbglvl, ("Error (%d [%s]) reading from source %s\n",

                             ret, strerror(ret), src_file));
@@ -101,7 +101,7 @@

              errno = 0;

              num = write(dst_fd, &buf[pos], count);

              if (num < 0) {

-                 if (errno == EINTR) continue;

+                 if (errno == EINTR || errno == EAGAIN) continue;

                  ret = errno;

                  DEBUG(dbglvl, ("Error (%d [%s]) writing to destination %s\n",

                                 ret, strerror(ret), dst_file));

file modified
+16
@@ -110,6 +110,22 @@

  		} \

  } while (0)

  

+ /* insert all elements from list2 after the given element 'el' in the

+  * first list */

+ #define DLIST_ADD_LIST_AFTER(list1, el, list2, type) \

+ do { \

+                 if (!(list1) || !(el) || !(list2)) { \

+                     DLIST_CONCATENATE(list1, list2, type); \

+                 } else { \

+                     type tmp; \

+                     for (tmp = (list2); tmp->next; tmp = tmp->next) ; \

+                     (list2)->prev = (el); \

+                     tmp->next = (el)->next; \

+                     (el)->next = (list2); \

+                     if ((el)->next != NULL) (el)->next->prev = tmp; \

+     } \

+ } while (0);

+ 

  #define DLIST_FOR_EACH(p, list) \

  	for ((p) = (list); (p) != NULL; (p) = (p)->next)

  

file modified
+51 -31
@@ -38,6 +38,7 @@

  

  #include "dhash.h"

  #include "util/util.h"

+ #include "util/strtonum.h"

  

  #define INITIAL_TABLE_SIZE 64

  #define PATHLEN (NAME_MAX + 14)
@@ -63,7 +64,8 @@

      char *p;

      char *e;

      char *endptr;

-     long num=0;

+     uint32_t num=0;

+     errno_t error;

  

      ret = snprintf(path, PATHLEN, "/proc/%d/status", pid);

      if (ret < 0) {
@@ -74,15 +76,28 @@

          return EINVAL;

      }

  

-     ret = lstat(path, &stat_buf);

+     fd = open(path, O_RDONLY);

+     if (fd == -1) {

+         error = errno;

+         if (error == ENOENT) {

+             DEBUG(7, ("Proc file [%s] is not available anymore, continuing.\n",

+                       path));

+             return EOK;

+         }

+         DEBUG(1, ("open failed [%d][%s].\n", error, strerror(error)));

+         return error;

+     }

+ 

+     ret = fstat(fd, &stat_buf);

      if (ret == -1) {

-         if (errno == ENOENT) {

+         error = errno;

+         if (error == ENOENT) {

              DEBUG(7, ("Proc file [%s] is not available anymore, continuing.\n",

                        path));

              return EOK;

          }

-         DEBUG(1, ("lstat failed [%d][%s].\n", errno, strerror(errno)));

-         return errno;

+         DEBUG(1, ("fstat failed [%d][%s].\n", error, strerror(error)));

+         return error;

      }

  

      if (!S_ISREG(stat_buf.st_mode)) {
@@ -90,25 +105,21 @@

          return EINVAL;

      }

  

-     fd = open(path, O_RDONLY);

-     if (fd == -1) {

-         if (errno == ENOENT) {

-             DEBUG(7, ("Proc file [%s] is not available anymore, continuing.\n",

-                       path));

-             return EOK;

+     while ((ret = read(fd, buf, BUFSIZE)) != 0) {

+         if (ret == -1) {

+             error = errno;

+             if (error == EINTR || error == EAGAIN) {

+                 continue;

+             }

+             DEBUG(1, ("read failed [%d][%s].\n", error, strerror(error)));

+             return error;

          }

-         DEBUG(1, ("open failed [%d][%s].\n", errno, strerror(errno)));

-         return errno;

-     }

-     ret = read(fd, buf, BUFSIZE);

-     if (ret == -1) {

-         DEBUG(1, ("read failed [%d][%s].\n", errno, strerror(errno)));

-         return errno;

      }

  

      ret = close(fd);

      if (ret == -1) {

-         DEBUG(1, ("close failed [%d][%s].\n", errno, strerror(errno)));

+         error = errno;

+         DEBUG(1, ("close failed [%d][%s].\n", error, strerror(error)));

      }

  

      p = strstr(buf, "\nUid:\t");
@@ -121,17 +132,19 @@

          } else {

              *e = '\0';

          }

-         num = strtol(p, &endptr, 10);

-         if(errno == ERANGE) {

-             DEBUG(1, ("strtol failed [%s].\n", strerror(errno)));

-             return errno;

+         errno = 0;

+         num = strtouint32(p, &endptr, 10);

+         error = errno;

+         if (error != 0) {

+             DEBUG(1, ("strtoul failed [%s].\n", strerror(error)));

+             return error;

          }

          if (*endptr != '\0') {

              DEBUG(1, ("uid contains extra characters\n"));

              return EINVAL;

          }

  

-         if (num < 0 || num >= INT_MAX) {

+         if (num >= UINT32_MAX) {

              DEBUG(1, ("uid out of range.\n"));

              return ERANGE;

          }
@@ -150,12 +163,14 @@

  {

      long num;

      char *endptr;

+     errno_t error;

  

      errno = 0;

      num = strtol(name, &endptr, 10);

-     if(errno == ERANGE) {

+     error = errno;

+     if (error == ERANGE) {

          perror("strtol");

-         return errno;

+         return error;

      }

  

      if (*endptr != '\0') {
@@ -183,7 +198,7 @@

  {

      DIR *proc_dir = NULL;

      struct dirent *dirent;

-     int ret;

+     int ret, err;

      pid_t pid = -1;

      uid_t uid;

  
@@ -192,8 +207,8 @@

  

      proc_dir = opendir("/proc");

      if (proc_dir == NULL) {

-         DEBUG(1, ("Cannot open proc dir.\n"));

          ret = errno;

+         DEBUG(1, ("Cannot open proc dir.\n"));

          goto done;

      };

  
@@ -235,15 +250,15 @@

          errno = 0;

      }

      if (errno != 0 && dirent == NULL) {

-         DEBUG(1 ,("readdir failed.\n"));

          ret = errno;

+         DEBUG(1, ("readdir failed.\n"));

          goto done;

      }

  

      ret = closedir(proc_dir);

      proc_dir = NULL;

      if (ret == -1) {

-         DEBUG(1 ,("closedir failed, watch out.\n"));

+         DEBUG(1, ("closedir failed, watch out.\n"));

      }

  

      if (table != NULL) {
@@ -253,7 +268,12 @@

      }

  

  done:

-     if (proc_dir != NULL) closedir(proc_dir);

+     if (proc_dir != NULL) {

+         err = closedir(proc_dir);

+         if (err) {

+             DEBUG(1, ("closedir failed, bad dirp?\n"));

+         }

+     }

      return ret;

  }

  

file modified
+84 -9
@@ -104,6 +104,10 @@

      char *file;

      int fd;

      int ret, err;

+     ssize_t len;

+     ssize_t size;

+     ssize_t written;

+     ssize_t pidlen = sizeof(pid_str - 1);

  

      file = talloc_asprintf(NULL, "%s/%s.pid", path, name);

      if (!file) {
@@ -114,9 +118,30 @@

      err = errno;

      if (fd != -1) {

  

-         pid_str[sizeof(pid_str) -1] = '\0';

-         ret = read(fd, pid_str, sizeof(pid_str) -1);

-         if (ret > 0) {

+         pid_str[pidlen] = '\0';

+ 

+         len = 0;

+         while ((ret = read(fd, pid_str + len, pidlen - len)) != 0) {

+             if (ret == -1) {

+                 if (errno == EINTR || errno == EAGAIN) {

+                     continue;

+                 }

+                 DEBUG(1, ("read failed [%d][%s].\n", errno, strerror(errno)));

+                 break;

+             } else if (ret > 0) {

+                 len += ret;

+                 if (len > pidlen) {

+                     DEBUG(1, ("read too much, this should never happen.\n"));

+                     break;

+                 }

+                 continue;

+             } else {

+                 DEBUG(1, ("unexpected return code of read [%d].\n", ret));

+                 break;

+             }

+         }

+ 

+         if (ret == 0) {

              /* let's check the pid */

  

              pid = (pid_t)atoi(pid_str);
@@ -159,10 +184,25 @@

  

      memset(pid_str, 0, sizeof(pid_str));

      snprintf(pid_str, sizeof(pid_str) -1, "%u\n", (unsigned int) getpid());

+     size = strlen(pid_str);

+ 

+     written = 0;

+     while (written < size) {

+         ret = write(fd, pid_str+written, size-written);

+         if (ret == -1) {

+             err = errno;

+             if (err == EINTR || err == EAGAIN) {

+                 continue;

+             }

+             DEBUG(1, ("write failed [%d][%s]\n", err, strerror(err)));

+             break;

+         }

+         else {

+             written += ret;

+         }

+     }

  

-     ret = write(fd, pid_str, strlen(pid_str));

-     err = errno;

-     if (ret != strlen(pid_str)) {

+     if (written != size) {

          close(fd);

          return err;

      }
@@ -178,7 +218,7 @@

  	return;

  }

  

- static void sig_term(int sig)

+ void sig_term(int sig)

  {

  #if HAVE_GETPGRP

  	static int done_sigterm;
@@ -188,7 +228,27 @@

  		kill(-getpgrp(), SIGTERM);

  	}

  #endif

- 	exit(0);

+     sss_log(SSS_LOG_INFO, "Shutting down");

+     exit(0);

+ }

+ 

+ static void default_quit(struct tevent_context *ev,

+                          struct tevent_signal *se,

+                          int signum,

+                          int count,

+                          void *siginfo,

+                          void *private_data)

+ {

+ #if HAVE_GETPGRP

+     static int done_sigterm;

+     if (done_sigterm == 0 && getpgrp() == getpid()) {

+         DEBUG(0,("SIGTERM: killing children\n"));

+         done_sigterm = 1;

+         kill(-getpgrp(), SIGTERM);

+     }

+ #endif

+     sss_log(SSS_LOG_INFO, "Shutting down");

+     exit(0);

  }

  

  #ifndef HAVE_PRCTL
@@ -233,7 +293,6 @@

  	BlockSignals(false, SIGTERM);

  

  	CatchSignal(SIGHUP, sig_hup);

- 	CatchSignal(SIGTERM, sig_term);

  

  #ifndef HAVE_PRCTL

          /* If prctl is not defined on the system, try to handle
@@ -348,6 +407,20 @@

          return 1;

      }

  

+     /* Set up an event handler for a SIGINT */

+     tes = tevent_add_signal(event_ctx, event_ctx, SIGINT, 0,

+                             default_quit, NULL);

+     if (tes == NULL) {

+         return EIO;

+     }

+ 

+     /* Set up an event handler for a SIGTERM */

+     tes = tevent_add_signal(event_ctx, event_ctx, SIGTERM, 0,

+                             default_quit, NULL);

+     if (tes == NULL) {

+         return EIO;

+     }

+ 

      ctx = talloc(event_ctx, struct main_context);

      if (ctx == NULL) {

          DEBUG(0,("Out of memory, aborting!\n"));
@@ -420,6 +493,8 @@

          }

      }

  

+     sss_log(SSS_LOG_INFO, "Starting up");

+ 

      DEBUG(3, ("CONFDB: %s\n", conf_db));

  

      if (flags & FLAGS_INTERACTIVE) {

file added
+69
@@ -0,0 +1,69 @@

+ /*

+     SSSD

+ 

+     sss_log.c

+ 

+     Authors:

+         Stephen Gallagher <sgallagh@redhat.com>

+ 

+     Copyright (C) 2010 Red Hat

+ 

+     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; either version 3 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 General Public License

+     along with this program.  If not, see <http://www.gnu.org/licenses/>.

+ */

+ 

+ #include "util/util.h"

+ #include <syslog.h>

+ 

+ static int sss_to_syslog(int priority)

+ {

+     switch(priority) {

+     case SSS_LOG_EMERG:

+         return LOG_EMERG;

+     case SSS_LOG_ALERT:

+         return LOG_ALERT;

+     case SSS_LOG_CRIT:

+         return LOG_CRIT;

+     case SSS_LOG_ERR:

+         return LOG_ERR;

+     case SSS_LOG_WARNING:

+         return LOG_WARNING;

+     case SSS_LOG_NOTICE:

+         return LOG_NOTICE;

+     case SSS_LOG_INFO:

+         return LOG_INFO;

+     case SSS_LOG_DEBUG:

+         return LOG_DEBUG;

+     default:

+         /* If we've been passed an invalid priority, it's

+          * best to assume it's an emergency.

+          */

+         return LOG_EMERG;

+     }

+ }

+ 

+ void sss_log(int priority, const char *format, ...)

+ {

+     va_list ap;

+     int syslog_priority;

+ 

+     syslog_priority = sss_to_syslog(priority);

+ 

+     openlog(debug_prg_name, 0, LOG_DAEMON);

+ 

+     va_start(ap, format);

+     vsyslog(syslog_priority, format, ap);

+     va_end(ap);

+ 

+     closelog();

+ }

file modified
+1 -1
@@ -51,7 +51,7 @@

  /* strtouint32 */

  uint32_t strtouint32(const char *nptr, char **endptr, int base)

  {

-     long long ret = 0;

+     unsigned long long ret = 0;

      errno = 0;

      ret = strtoull(nptr, endptr, base);

  

file modified
+379
@@ -22,6 +22,7 @@

  

  #include "talloc.h"

  #include "util/util.h"

+ #include "dhash.h"

  

  /* split a string into an allocated array of strings.

   * the separator is a string, and is case-sensitive.
@@ -136,3 +137,381 @@

  

      return EOK;

  }

+ 

+ static void free_args(char **args)

+ {

+     int i;

+ 

+     if (args) {

+         for (i = 0; args[i]; i++) free(args[i]);

+         free(args);

+     }

+ }

+ 

+ /* parse a string into arguments.

+  * arguments are separated by a space

+  * '\' is an escape character and can be used only to escape

+  * itself or the white space.

+  */

+ char **parse_args(const char *str)

+ {

+     const char *p;

+     char **ret, **r;

+     char *tmp;

+     int num;

+     int i, e;

+ 

+     tmp = malloc(strlen(str) + 1);

+     if (!tmp) return NULL;

+ 

+     ret = NULL;

+     num = 0;

+     e = 0;

+     i = 0;

+     p = str;

+     while (*p) {

+         switch (*p) {

+         case '\\':

+             if (e) {

+                 tmp[i] = '\\';

+                 i++;

+                 e = 0;

+             } else {

+                 e = 1;

+             }

+             break;

+         case ' ':

+             if (e) {

+                 tmp[i] = ' ';

+                 i++;

+                 e = 0;

+             } else {

+                 tmp[i] = '\0';

+                 i++;

+             }

+             break;

+         default:

+             if (e) {

+                 tmp[i] = '\\';

+                 i++;

+                 e = 0;

+             }

+             tmp[i] = *p;

+             i++;

+             break;

+         }

+ 

+         p++;

+ 

+         /* check if this was the last char */

+         if (*p == '\0') {

+             if (e) {

+                 tmp[i] = '\\';

+                 i++;

+                 e = 0;

+             }

+             tmp[i] = '\0';

+             i++;

+         }

+         if (tmp[i-1] != '\0' || strlen(tmp) == 0) {

+             /* check next char and skip multiple spaces */

+             continue;

+         }

+ 

+         r = realloc(ret, (num + 2) * sizeof(char *));

+         if (!r) goto fail;

+         ret = r;

+         ret[num+1] = NULL;

+         ret[num] = strdup(tmp);

+         if (!ret[num]) goto fail;

+         num++;

+         i = 0;

+     }

+ 

+     free(tmp);

+     return ret;

+ 

+ fail:

+     free(tmp);

+     free_args(ret);

+     return NULL;

+ }

+ 

+ char **dup_string_list(TALLOC_CTX *memctx, const char **str_list)

+ {

+     int i = 0;

+     int j = 0;

+     char **dup_list;

+ 

+     if (!str_list) {

+         return NULL;

+     }

+ 

+     /* Find the size of the list */

+     while (str_list[i]) i++;

+ 

+     dup_list = talloc_array(memctx, char *, i+1);

+     if (!dup_list) {

+         return NULL;

+     }

+ 

+     /* Copy the elements */

+     for (j = 0; j < i; j++) {

+         dup_list[j] = talloc_strdup(dup_list, str_list[j]);

+         if (!dup_list[j]) {

+             talloc_free(dup_list);

+             return NULL;

+         }

+     }

+ 

+     /* NULL-terminate the list */

+     dup_list[i] = NULL;

+ 

+     return dup_list;

+ }

+ 

+ /* Take two string lists (terminated on a NULL char*)

+  * and return up to three arrays of strings based on

+  * shared ownership.

+  *

+  * Pass NULL to any return type you don't care about

+  */

+ errno_t diff_string_lists(TALLOC_CTX *memctx,

+                           char **_list1,

+                           char **_list2,

+                           char ***_list1_only,

+                           char ***_list2_only,

+                           char ***_both_lists)

+ {

+     int error;

+     errno_t ret;

+     int i;

+     int i2 = 0;

+     int i12 = 0;

+     hash_table_t *table;

+     hash_key_t key;

+     hash_value_t value;

+     char **list1 = NULL;

+     char **list2 = NULL;

+     char **list1_only = NULL;

+     char **list2_only = NULL;

+     char **both_lists = NULL;

+     unsigned long count;

+     hash_key_t *keys;

+ 

+     TALLOC_CTX *tmp_ctx = talloc_new(memctx);

+     if (!tmp_ctx) {

+         return ENOMEM;

+     }

+ 

+     if (!_list1) {

+         list1 = talloc_array(tmp_ctx, char *, 1);

+         if (!list1) {

+             talloc_free(tmp_ctx);

+             return ENOMEM;

+         }

+         list1[0] = NULL;

+     }

+     else {

+         list1 = _list1;

+     }

+ 

+     if (!_list2) {

+         list2 = talloc_array(tmp_ctx, char *, 1);

+         if (!list2) {

+             talloc_free(tmp_ctx);

+             return ENOMEM;

+         }

+         list2[0] = NULL;

+     }

+     else {

+         list2 = _list2;

+     }

+ 

+     error = hash_create(10, &table, NULL, NULL);

+     if (error != HASH_SUCCESS) {

+         talloc_free(tmp_ctx);

+         return EIO;

+     }

+ 

+     key.type = HASH_KEY_STRING;

+     value.type = HASH_VALUE_UNDEF;

+ 

+     /* Add all entries from list 1 into a hash table */

+     i = 0;

+     while (list1[i]) {

+         key.str = talloc_strdup(tmp_ctx, list1[i]);

+         error = hash_enter(table, &key, &value);

+         if (error != HASH_SUCCESS) {

+             ret = EIO;

+             goto done;

+         }

+         i++;

+     }

+ 

+     /* Iterate through list 2 and remove matching items */

+     i = 0;

+     while (list2[i]) {

+         key.str = talloc_strdup(tmp_ctx, list2[i]);

+         error = hash_delete(table, &key);

+         if (error == HASH_SUCCESS) {

+             if (_both_lists) {

+                 /* String was present in both lists */

+                 i12++;

+                 both_lists = talloc_realloc(tmp_ctx, both_lists, char *, i12+1);

+                 if (!both_lists) {

+                     ret = ENOMEM;

+                     goto done;

+                 }

+                 both_lists[i12-1] = talloc_strdup(both_lists, list2[i]);

+                 if (!both_lists[i12-1]) {

+                     ret = ENOMEM;

+                     goto done;

+                 }

+ 

+                 both_lists[i12] = NULL;

+             }

+         }

+         else if (error == HASH_ERROR_KEY_NOT_FOUND) {

+             if (_list2_only) {

+                 /* String was present only in list2 */

+                 i2++;

+                 list2_only = talloc_realloc(tmp_ctx, list2_only,

+                                             char *, i2+1);

+                 if (!list2_only) {

+                     ret = ENOMEM;

+                     goto done;

+                 }

+                 list2_only[i2-1] = talloc_strdup(list2_only, list2[i]);

+                 if (!list2_only[i2-1]) {

+                     ret = ENOMEM;

+                     goto done;

+                 }

+ 

+                 list2_only[i2] = NULL;

+             }

+         }

+         else {

+             /* An error occurred */

+             ret = EIO;

+             goto done;

+         }

+         i++;

+     }

+ 

+     /* Get the leftover entries in the hash table */

+     if (_list1_only) {

+         error = hash_keys(table, &count, &keys);

+         if (error != HASH_SUCCESS) {

+             ret = EIO;

+             goto done;

+         }

+ 

+         list1_only = talloc_array(tmp_ctx, char *, count+1);

+         if (!list1_only) {

+             ret = ENOMEM;

+             goto done;

+         }

+ 

+         for (i = 0; i < count; i++) {

+             list1_only[i] = talloc_strdup(list1_only, keys[i].str);

+             if (!list1_only[i]) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+         }

+         list1_only[count] = NULL;

+ 

+         free(keys);

+ 

+         *_list1_only = talloc_steal(memctx, list1_only);

+     }

+ 

+     if (_list2_only) {

+         if (list2_only) {

+             *_list2_only = talloc_steal(memctx, list2_only);

+         }

+         else {

+             *_list2_only = talloc_array(memctx, char *, 1);

+             if (!(*_list2_only)) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+             *_list2_only[0] = NULL;

+         }

+     }

+ 

+     if (_both_lists) {

+         if (both_lists) {

+             *_both_lists = talloc_steal(memctx, both_lists);

+         }

+         else {

+             *_both_lists = talloc_array(memctx, char *, 1);

+             if (!(*_both_lists)) {

+                 ret = ENOMEM;

+                 goto done;

+             }

+             *_both_lists[0] = NULL;

+         }

+     }

+ 

+     ret = EOK;

+ 

+ done:

+     hash_destroy(table);

+     talloc_free(tmp_ctx);

+     return ret;

+ }

+ 

+ static void *hash_talloc(const size_t size, void *pvt)

+ {

+     return talloc_size(pvt, size);

+ }

+ 

+ static void hash_talloc_free(void *ptr, void *pvt)

+ {

+     talloc_free(ptr);

+ }

+ 

+ errno_t sss_hash_create(TALLOC_CTX *mem_ctx,

+                         unsigned long count,

+                         hash_table_t **tbl)

+ {

+     errno_t ret;

+     hash_table_t *table;

+     int hret;

+ 

+     TALLOC_CTX *internal_ctx;

+     internal_ctx = talloc_new(NULL);

+     if (!internal_ctx) {

+         return ENOMEM;

+     }

+ 

+     hret = hash_create_ex(count, &table, 0, 0, 0, 0,

+                           hash_talloc, hash_talloc_free,

+                           internal_ctx, NULL, NULL);

+     switch (hret) {

+     case HASH_SUCCESS:

+         /* Steal the table pointer onto the mem_ctx,

+          * then make the internal_ctx a child of

+          * table.

+          *

+          * This way, we can clean up the values when

+          * we talloc_free() the table

+          */

+         *tbl = talloc_steal(mem_ctx, table);

+         talloc_steal(table, internal_ctx);

+         return EOK;

+ 

+     case HASH_ERROR_NO_MEMORY:

+         ret = ENOMEM;

+     default:

+         ret = EIO;

+     }

+ 

+     DEBUG(0, ("Could not create hash table: [%d][%s]\n",

+               hret, hash_error_string(hret)));

+ 

+     talloc_free(internal_ctx);

+     return ret;

+ }

file modified
+56 -2
@@ -40,6 +40,7 @@

  #include <talloc.h>

  #include <tevent.h>

  #include <ldb.h>

+ #include <dhash.h>

  

  #ifndef HAVE_ERRNO_T

  #define HAVE_ERRNO_T
@@ -118,7 +119,11 @@

  #define FLAGS_PID_FILE 0x0004

  

  #ifndef talloc_zfree

- #define talloc_zfree(ptr) do { talloc_free(ptr); ptr = NULL; } while(0)

+ #define talloc_zfree(ptr) do { \

+         TALLOC_CTX *_tmp_ctx = ptr; \

+         ptr = NULL; \

+         talloc_free(_tmp_ctx); \

+     } while(0)

  #endif

  

  #ifndef discard_const_p
@@ -163,6 +168,11 @@

  #define OUT_OF_ID_RANGE(id, min, max) \

      (id == 0 || (min && (id < min)) || (max && (id > max)))

  

+ #define SIZE_T_MAX ((size_t) -1)

+ 

+ #define SIZE_T_OVERFLOW(current, add) \

+                         (((size_t)(add)) > (SIZE_T_MAX - ((size_t)(current))))

+ 

  static inline void

  safealign_memcpy(void *dest, const void *src, size_t n, size_t *counter)

  {
@@ -190,10 +200,17 @@

      SAFEALIGN_SET_VALUE(dest, value, int32_t, pctr)

  

  #define SAFEALIGN_COPY_UINT32_CHECK(dest, src, len, pctr) do { \

-     if ((*(pctr) + sizeof(uint32_t)) > (len)) return EINVAL; \

+     if ((*(pctr) + sizeof(uint32_t)) > (len) || \

+         SIZE_T_OVERFLOW(*(pctr), sizeof(uint32_t))) return EINVAL; \

      safealign_memcpy(dest, src, sizeof(uint32_t), pctr); \

  } while(0)

  

+ #define SAFEALIGN_COPY_INT32_CHECK(dest, src, len, pctr) do { \

+     if ((*(pctr) + sizeof(int32_t)) > (len) || \

+         SIZE_T_OVERFLOW(*(pctr), sizeof(int32_t))) return EINVAL; \

+     safealign_memcpy(dest, src, sizeof(int32_t), pctr); \

+ } while(0)

+ 

  #include "util/dlinklist.h"

  

  /* From debug.c */
@@ -203,6 +220,18 @@

  int open_debug_file(void);

  int rotate_debug_files(void);

  

+ /* From sss_log.c */

+ #define SSS_LOG_EMERG   0   /* system is unusable */

+ #define SSS_LOG_ALERT   1   /* action must be taken immediately */

+ #define SSS_LOG_CRIT    2   /* critical conditions */

+ #define SSS_LOG_ERR     3   /* error conditions */

+ #define SSS_LOG_WARNING 4   /* warning conditions */

+ #define SSS_LOG_NOTICE  5   /* normal but significant condition */

+ #define SSS_LOG_INFO    6   /* informational */

+ #define SSS_LOG_DEBUG   7   /* debug-level messages */

+ 

+ void sss_log(int priority, const char *format, ...);

+ 

  /* from server.c */

  struct main_context {

      struct tevent_context *event_ctx;
@@ -214,6 +243,7 @@

                   const char *conf_entry,

                   struct main_context **main_ctx);

  void server_loop(struct main_context *main_ctx);

+ void sig_term(int sig);

  

  /* from signal.c */

  #include <signal.h>
@@ -307,4 +337,28 @@

  /* from util.c */

  int split_on_separator(TALLOC_CTX *mem_ctx, const char *str,

                         const char sep, bool trim, char ***_list, int *size);

+ 

+ char **parse_args(const char *str);

+ 

+ errno_t sss_hash_create(TALLOC_CTX *mem_ctx,

+                         unsigned long count,

+                         hash_table_t **tbl);

+ 

+ /* Copy a NULL-terminated string list

+  * Returns NULL on out of memory error or invalid input

+  */

+ char **dup_string_list(TALLOC_CTX *memctx, const char **str_list);

+ 

+ /* Take two string lists (terminated on a NULL char*)

+  * and return up to three arrays of strings based on

+  * shared ownership.

+  *

+  * Pass NULL to any return type you don't care about

+  */

+ errno_t diff_string_lists(TALLOC_CTX *memctx,

+                           char **string1,

+                           char **string2,

+                           char ***string1_only,

+                           char ***string2_only,

+                           char ***both_strings);

  #endif /* __SSSD_UTIL_H__ */

file modified
+1 -1
@@ -1,5 +1,5 @@

  # Primary version number

- m4_define([VERSION_NUMBER], [1.1.90])

+ m4_define([VERSION_NUMBER], [1.2.5])

  

  # If the PRERELEASE_VERSION_NUMBER is set, we'll append

  # it to the release tag when creating an RPM or SRPM