LCOV - code coverage report
Current view: top level - providers/ldap - ldap_child.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 356 0.0 %
Date: 2015-10-19 Functions: 0 8 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     LDAP Backend Module -- prime ccache with TGT in a child process
       5             : 
       6             :     Authors:
       7             :         Jakub Hrozek <jhrozek@redhat.com>
       8             : 
       9             :     Copyright (C) 2009 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include <sys/types.h>
      26             : #include <unistd.h>
      27             : #include <sys/stat.h>
      28             : #include <popt.h>
      29             : 
      30             : #include "util/util.h"
      31             : #include "util/sss_krb5.h"
      32             : #include "util/child_common.h"
      33             : #include "providers/dp_backend.h"
      34             : #include "providers/krb5/krb5_common.h"
      35             : 
      36             : static krb5_context krb5_error_ctx;
      37             : #define LDAP_CHILD_DEBUG(level, error) KRB5_DEBUG(level, krb5_error_ctx, error)
      38             : 
      39             : static const char *__ldap_child_krb5_error_msg;
      40             : #define KRB5_SYSLOG(krb5_error) do { \
      41             :     __ldap_child_krb5_error_msg = sss_krb5_get_error_message(krb5_error_ctx, krb5_error); \
      42             :     sss_log(SSS_LOG_ERR, "%s", __ldap_child_krb5_error_msg); \
      43             :     sss_krb5_free_error_message(krb5_error_ctx, __ldap_child_krb5_error_msg); \
      44             : } while(0)
      45             : 
      46             : struct input_buffer {
      47             :     const char *realm_str;
      48             :     const char *princ_str;
      49             :     char *keytab_name;
      50             :     krb5_deltat lifetime;
      51             :     krb5_context context;
      52             :     uid_t uid;
      53             :     gid_t gid;
      54             : };
      55             : 
      56           0 : static errno_t unpack_buffer(uint8_t *buf, size_t size,
      57             :                              struct input_buffer *ibuf)
      58             : {
      59           0 :     size_t p = 0;
      60             :     uint32_t len;
      61             : 
      62           0 :     DEBUG(SSSDBG_TRACE_LIBS, "total buffer size: %zu\n", size);
      63             : 
      64             :     /* realm_str size and length */
      65           0 :     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
      66             : 
      67           0 :     DEBUG(SSSDBG_TRACE_LIBS, "realm_str size: %d\n", len);
      68           0 :     if (len) {
      69           0 :         if (len > size - p) return EINVAL;
      70           0 :         ibuf->realm_str = talloc_strndup(ibuf, (char *)(buf + p), len);
      71           0 :         DEBUG(SSSDBG_TRACE_LIBS, "got realm_str: %s\n", ibuf->realm_str);
      72           0 :         if (ibuf->realm_str == NULL) return ENOMEM;
      73           0 :         p += len;
      74             :     }
      75             : 
      76             :     /* princ_str size and length */
      77           0 :     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
      78             : 
      79           0 :     DEBUG(SSSDBG_TRACE_LIBS, "princ_str size: %d\n", len);
      80           0 :     if (len) {
      81           0 :         if (len > size - p) return EINVAL;
      82           0 :         ibuf->princ_str = talloc_strndup(ibuf, (char *)(buf + p), len);
      83           0 :         DEBUG(SSSDBG_TRACE_LIBS, "got princ_str: %s\n", ibuf->princ_str);
      84           0 :         if (ibuf->princ_str == NULL) return ENOMEM;
      85           0 :         p += len;
      86             :     }
      87             : 
      88             :     /* keytab_name size and length */
      89           0 :     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
      90             : 
      91           0 :     DEBUG(SSSDBG_TRACE_LIBS, "keytab_name size: %d\n", len);
      92           0 :     if (len) {
      93           0 :         if (len > size - p) return EINVAL;
      94           0 :         ibuf->keytab_name = talloc_strndup(ibuf, (char *)(buf + p), len);
      95           0 :         DEBUG(SSSDBG_TRACE_LIBS, "got keytab_name: %s\n", ibuf->keytab_name);
      96           0 :         if (ibuf->keytab_name == NULL) return ENOMEM;
      97           0 :         p += len;
      98             :     }
      99             : 
     100             :     /* ticket lifetime */
     101           0 :     SAFEALIGN_COPY_UINT32_CHECK(&ibuf->lifetime, buf + p, size, &p);
     102           0 :     DEBUG(SSSDBG_TRACE_LIBS, "lifetime: %u\n", ibuf->lifetime);
     103             : 
     104             :     /* UID and GID to run as */
     105           0 :     SAFEALIGN_COPY_UINT32_CHECK(&ibuf->uid, buf + p, size, &p);
     106           0 :     SAFEALIGN_COPY_UINT32_CHECK(&ibuf->gid, buf + p, size, &p);
     107           0 :     DEBUG(SSSDBG_FUNC_DATA,
     108             :           "Will run as [%"SPRIuid"][%"SPRIgid"].\n", ibuf->uid, ibuf->gid);
     109             : 
     110           0 :     return EOK;
     111             : }
     112             : 
     113           0 : static int pack_buffer(struct response *r, int result, krb5_error_code krberr,
     114             :                        const char *msg, time_t expire_time)
     115             : {
     116             :     int len;
     117           0 :     size_t p = 0;
     118             : 
     119           0 :     len = strlen(msg);
     120           0 :     r->size = 2 * sizeof(uint32_t) + sizeof(krb5_error_code) +
     121           0 :               len + sizeof(time_t);
     122             : 
     123           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "response size: %zu\n",r->size);
     124             : 
     125           0 :     r->buf = talloc_array(r, uint8_t, r->size);
     126           0 :     if(!r->buf) {
     127           0 :         return ENOMEM;
     128             :     }
     129             : 
     130           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     131             :           "result [%d] krberr [%d] msgsize [%d] msg [%s]\n",
     132             :            result, krberr, len, msg);
     133             : 
     134             :     /* result */
     135           0 :     SAFEALIGN_SET_UINT32(&r->buf[p], result, &p);
     136             : 
     137             :     /* krb5 error code */
     138           0 :     safealign_memcpy(&r->buf[p], &krberr, sizeof(krberr), &p);
     139             : 
     140             :     /* message size */
     141           0 :     SAFEALIGN_SET_UINT32(&r->buf[p], len, &p);
     142             : 
     143             :     /* message itself */
     144           0 :     safealign_memcpy(&r->buf[p], msg, len, &p);
     145             : 
     146             :     /* ticket expiration time */
     147           0 :     safealign_memcpy(&r->buf[p], &expire_time, sizeof(expire_time), &p);
     148             : 
     149           0 :     return EOK;
     150             : }
     151             : 
     152             : static errno_t
     153           0 : set_child_debugging(krb5_context ctx)
     154             : {
     155             :     krb5_error_code kerr;
     156             : 
     157             :     /* Set the global error context */
     158           0 :     krb5_error_ctx = ctx;
     159             : 
     160           0 :     if (debug_level & SSSDBG_TRACE_ALL) {
     161           0 :         kerr = sss_child_set_krb5_tracing(ctx);
     162           0 :         if (kerr) {
     163           0 :             LDAP_CHILD_DEBUG(SSSDBG_MINOR_FAILURE, kerr);
     164           0 :             return EIO;
     165             :         }
     166             :     }
     167             : 
     168           0 :     return EOK;
     169             : }
     170             : 
     171           0 : static int lc_verify_keytab_ex(const char *principal,
     172             :                                const char *keytab_name,
     173             :                                krb5_context context,
     174             :                                krb5_keytab keytab)
     175             : {
     176             :     bool found;
     177             :     char *kt_principal;
     178             :     krb5_error_code krberr;
     179             :     krb5_kt_cursor cursor;
     180             :     krb5_keytab_entry entry;
     181             : 
     182           0 :     krberr = krb5_kt_start_seq_get(context, keytab, &cursor);
     183           0 :     if (krberr) {
     184           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     185             :               "Cannot read keytab [%s].\n", KEYTAB_CLEAN_NAME);
     186             : 
     187           0 :         sss_log(SSS_LOG_ERR, "Error reading keytab file [%s]: [%d][%s]. "
     188             :                              "Unable to create GSSAPI-encrypted LDAP "
     189             :                              "connection.",
     190             :                              KEYTAB_CLEAN_NAME, krberr,
     191             :                              sss_krb5_get_error_message(context, krberr));
     192             : 
     193           0 :         return EIO;
     194             :     }
     195             : 
     196           0 :     found = false;
     197           0 :     while ((krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0) {
     198           0 :         krberr = krb5_unparse_name(context, entry.principal, &kt_principal);
     199           0 :         if (krberr) {
     200           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     201             :                   "Could not parse keytab entry\n");
     202           0 :             sss_log(SSS_LOG_ERR, "Could not parse keytab entry\n");
     203           0 :             return EIO;
     204             :         }
     205             : 
     206           0 :         if (strcmp(principal, kt_principal) == 0) {
     207           0 :             found = true;
     208             :         }
     209           0 :         free(kt_principal);
     210           0 :         krberr = sss_krb5_free_keytab_entry_contents(context, &entry);
     211           0 :         if (krberr) {
     212             :             /* This should never happen. The API docs for this function
     213             :              * specify only success for this function
     214             :              */
     215           0 :             DEBUG(SSSDBG_CRIT_FAILURE,"Could not free keytab entry contents\n");
     216             :             /* This is non-fatal, so we'll continue here */
     217             :         }
     218             : 
     219           0 :         if (found) {
     220           0 :             break;
     221             :         }
     222             :     }
     223             : 
     224           0 :     krberr = krb5_kt_end_seq_get(context, keytab, &cursor);
     225           0 :     if (krberr) {
     226           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Could not close keytab.\n");
     227           0 :         sss_log(SSS_LOG_ERR, "Could not close keytab file [%s].",
     228             :                              KEYTAB_CLEAN_NAME);
     229           0 :         return EIO;
     230             :     }
     231             : 
     232           0 :     if (!found) {
     233           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     234             :               "Principal [%s] not found in keytab [%s]\n",
     235             :                principal,
     236             :                KEYTAB_CLEAN_NAME);
     237           0 :         sss_log(SSS_LOG_ERR, "Error processing keytab file [%s]: "
     238             :                              "Principal [%s] was not found. "
     239             :                              "Unable to create GSSAPI-encrypted LDAP connection.",
     240             :                              KEYTAB_CLEAN_NAME, principal);
     241             : 
     242           0 :         return EFAULT;
     243             :     }
     244             : 
     245           0 :     return EOK;
     246             : }
     247             : 
     248           0 : static krb5_error_code ldap_child_get_tgt_sync(TALLOC_CTX *memctx,
     249             :                                                krb5_context context,
     250             :                                                const char *realm_str,
     251             :                                                const char *princ_str,
     252             :                                                const char *keytab_name,
     253             :                                                const krb5_deltat lifetime,
     254             :                                                const char **ccname_out,
     255             :                                                time_t *expire_time_out)
     256             : {
     257             :     char *ccname;
     258             :     char *ccname_dummy;
     259           0 :     char *realm_name = NULL;
     260           0 :     char *full_princ = NULL;
     261           0 :     char *default_realm = NULL;
     262           0 :     char *tmp_str = NULL;
     263           0 :     krb5_keytab keytab = NULL;
     264           0 :     krb5_ccache ccache = NULL;
     265             :     krb5_principal kprinc;
     266             :     krb5_creds my_creds;
     267             :     krb5_get_init_creds_opt options;
     268             :     krb5_error_code krberr;
     269             :     krb5_timestamp kdc_time_offset;
     270           0 :     int canonicalize = 0;
     271             :     int kdc_time_offset_usec;
     272             :     int ret;
     273             :     TALLOC_CTX *tmp_ctx;
     274           0 :     char *ccname_file_dummy = NULL;
     275             :     char *ccname_file;
     276             : 
     277           0 :     tmp_ctx = talloc_new(memctx);
     278           0 :     if (tmp_ctx == NULL) {
     279           0 :         krberr = KRB5KRB_ERR_GENERIC;
     280           0 :         goto done;
     281             :     }
     282             : 
     283           0 :     krberr = set_child_debugging(context);
     284           0 :     if (krberr != EOK) {
     285           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Cannot set krb5_child debugging\n");
     286             :     }
     287             : 
     288           0 :     if (!realm_str) {
     289           0 :         krberr = krb5_get_default_realm(context, &default_realm);
     290           0 :         if (krberr) {
     291           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to get default realm name: %s\n",
     292             :                       sss_krb5_get_error_message(context, krberr));
     293           0 :             goto done;
     294             :         }
     295             : 
     296           0 :         realm_name = talloc_strdup(tmp_ctx, default_realm);
     297           0 :         krb5_free_default_realm(context, default_realm);
     298           0 :         if (!realm_name) {
     299           0 :             krberr = KRB5KRB_ERR_GENERIC;
     300           0 :             goto done;
     301             :         }
     302             :     } else {
     303           0 :         realm_name = talloc_strdup(tmp_ctx, realm_str);
     304           0 :         if (!realm_name) {
     305           0 :             krberr = KRB5KRB_ERR_GENERIC;
     306           0 :             goto done;
     307             :         }
     308             :     }
     309             : 
     310           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "got realm_name: [%s]\n", realm_name);
     311             : 
     312           0 :     if (princ_str) {
     313           0 :         if (!strchr(princ_str, '@')) {
     314           0 :             full_princ = talloc_asprintf(tmp_ctx, "%s@%s",
     315             :                                          princ_str, realm_name);
     316             :         } else {
     317           0 :             full_princ = talloc_strdup(tmp_ctx, princ_str);
     318             :         }
     319             :     } else {
     320             :         char hostname[HOST_NAME_MAX + 1];
     321             : 
     322           0 :         ret = gethostname(hostname, HOST_NAME_MAX);
     323           0 :         if (ret == -1) {
     324           0 :             krberr = KRB5KRB_ERR_GENERIC;
     325           0 :             goto done;
     326             :         }
     327           0 :         hostname[HOST_NAME_MAX] = '\0';
     328             : 
     329           0 :         DEBUG(SSSDBG_TRACE_LIBS, "got hostname: [%s]\n", hostname);
     330             : 
     331           0 :         ret = select_principal_from_keytab(tmp_ctx, hostname, realm_name,
     332             :                 keytab_name, &full_princ, NULL, NULL);
     333           0 :         if (ret) {
     334           0 :             krberr = KRB5_KT_IOERR;
     335           0 :             goto done;
     336             :         }
     337             :     }
     338           0 :     if (!full_princ) {
     339           0 :         krberr = KRB5KRB_ERR_GENERIC;
     340           0 :         goto done;
     341             :     }
     342           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Principal name is: [%s]\n", full_princ);
     343             : 
     344           0 :     krberr = krb5_parse_name(context, full_princ, &kprinc);
     345           0 :     if (krberr) {
     346           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unable to build principal: %s\n",
     347             :                   sss_krb5_get_error_message(context, krberr));
     348           0 :         goto done;
     349             :     }
     350             : 
     351           0 :     if (keytab_name) {
     352           0 :         krberr = krb5_kt_resolve(context, keytab_name, &keytab);
     353             :     } else {
     354           0 :         krberr = krb5_kt_default(context, &keytab);
     355             :     }
     356           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Using keytab [%s]\n", KEYTAB_CLEAN_NAME);
     357           0 :     if (krberr) {
     358           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     359             :               "Failed to read keytab file [%s]: %s\n",
     360             :                KEYTAB_CLEAN_NAME,
     361             :                sss_krb5_get_error_message(context, krberr));
     362           0 :         goto done;
     363             :     }
     364             : 
     365             :     /* Verify the keytab */
     366           0 :     ret = lc_verify_keytab_ex(full_princ, keytab_name, context, keytab);
     367           0 :     if (ret) {
     368           0 :         DEBUG(SSSDBG_OP_FAILURE,
     369             :                 "Unable to verify principal is present in the keytab\n");
     370           0 :         krberr = KRB5_KT_IOERR;
     371           0 :         goto done;
     372             :     }
     373             : 
     374           0 :     memset(&my_creds, 0, sizeof(my_creds));
     375           0 :     memset(&options, 0, sizeof(options));
     376             : 
     377           0 :     krb5_get_init_creds_opt_set_address_list(&options, NULL);
     378           0 :     krb5_get_init_creds_opt_set_forwardable(&options, 0);
     379           0 :     krb5_get_init_creds_opt_set_proxiable(&options, 0);
     380           0 :     krb5_get_init_creds_opt_set_tkt_life(&options, lifetime);
     381             : 
     382           0 :     tmp_str = getenv("KRB5_CANONICALIZE");
     383           0 :     if (tmp_str != NULL && strcasecmp(tmp_str, "true") == 0) {
     384           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Will canonicalize principals\n");
     385           0 :         canonicalize = 1;
     386             :     }
     387           0 :     sss_krb5_get_init_creds_opt_set_canonicalize(&options, canonicalize);
     388             : 
     389           0 :     ccname_file = talloc_asprintf(tmp_ctx, "%s/ccache_%s",
     390             :                                   DB_PATH, realm_name);
     391           0 :     if (ccname_file == NULL) {
     392           0 :         krberr = ENOMEM;
     393           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     394             :               "talloc_asprintf failed: %s:[%d].\n",
     395             :               strerror(krberr), krberr);
     396           0 :         goto done;
     397             :     }
     398             : 
     399           0 :     ccname_file_dummy = talloc_asprintf(tmp_ctx, "%s/ccache_%s_XXXXXX",
     400             :                                         DB_PATH, realm_name);
     401           0 :     if (ccname_file_dummy == NULL) {
     402           0 :         krberr = ENOMEM;
     403           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     404             :               "talloc_asprintf failed: %s:[%d].\n",
     405             :               strerror(krberr), krberr);
     406           0 :         goto done;
     407             :     }
     408             : 
     409           0 :     ret = sss_unique_filename(tmp_ctx, ccname_file_dummy);
     410           0 :     if (ret != EOK) {
     411           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     412             :               "sss_unique_filename failed: %s:[%d].\n",
     413             :               strerror(ret), ret);
     414           0 :         krberr = KRB5KRB_ERR_GENERIC;
     415           0 :         goto done;
     416             :     }
     417             : 
     418           0 :     krberr = krb5_get_init_creds_keytab(context, &my_creds, kprinc,
     419             :                                         keytab, 0, NULL, &options);
     420           0 :     krb5_kt_close(context, keytab);
     421           0 :     keytab = NULL;
     422           0 :     if (krberr) {
     423           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     424             :               "Failed to init credentials: %s\n",
     425             :                sss_krb5_get_error_message(context, krberr));
     426           0 :         sss_log(SSS_LOG_ERR,
     427             :                 "Failed to initialize credentials using keytab [%s]: %s. "
     428             :                 "Unable to create GSSAPI-encrypted LDAP connection.",
     429             :                 KEYTAB_CLEAN_NAME,
     430             :                 sss_krb5_get_error_message(context, krberr));
     431           0 :         goto done;
     432             :     }
     433           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "credentials initialized\n");
     434             : 
     435           0 :     ccname_dummy = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file_dummy);
     436           0 :     ccname = talloc_asprintf(tmp_ctx, "FILE:%s", ccname_file);
     437           0 :     if (ccname_dummy == NULL || ccname == NULL) {
     438           0 :         krberr = ENOMEM;
     439           0 :         goto done;
     440             :     }
     441           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "keytab ccname: [%s]\n", ccname_dummy);
     442             : 
     443           0 :     krberr = krb5_cc_resolve(context, ccname_dummy, &ccache);
     444           0 :     if (krberr) {
     445           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to set cache name: %s\n",
     446             :                   sss_krb5_get_error_message(context, krberr));
     447           0 :         goto done;
     448             :     }
     449             : 
     450             :     /* Use updated principal if changed due to canonicalization. */
     451           0 :     krberr = krb5_cc_initialize(context, ccache, my_creds.client);
     452           0 :     if (krberr) {
     453           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to init ccache: %s\n",
     454             :                   sss_krb5_get_error_message(context, krberr));
     455           0 :         goto done;
     456             :     }
     457             : 
     458           0 :     krberr = krb5_cc_store_cred(context, ccache, &my_creds);
     459           0 :     if (krberr) {
     460           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to store creds: %s\n",
     461             :                   sss_krb5_get_error_message(context, krberr));
     462           0 :         goto done;
     463             :     }
     464           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "credentials stored\n");
     465             : 
     466             : #ifdef HAVE_KRB5_GET_TIME_OFFSETS
     467           0 :     krberr = krb5_get_time_offsets(context, &kdc_time_offset,
     468             :             &kdc_time_offset_usec);
     469           0 :     if (krberr) {
     470           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get KDC time offset: %s\n",
     471             :                   sss_krb5_get_error_message(context, krberr));
     472           0 :         kdc_time_offset = 0;
     473             :     } else {
     474           0 :         if (kdc_time_offset_usec > 0) {
     475           0 :             kdc_time_offset++;
     476             :         }
     477             :     }
     478           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Got KDC time offset\n");
     479             : #else
     480             :     /* If we don't have this function, just assume no offset */
     481             :     kdc_time_offset = 0;
     482             : #endif
     483             : 
     484           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     485             :           "Renaming [%s] to [%s]\n", ccname_file_dummy, ccname_file);
     486           0 :     ret = rename(ccname_file_dummy, ccname_file);
     487           0 :     if (ret == -1) {
     488           0 :         ret = errno;
     489           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     490             :               "rename failed [%d][%s].\n", ret, strerror(ret));
     491           0 :         goto done;
     492             :     }
     493             : 
     494           0 :     krberr = 0;
     495           0 :     *ccname_out = talloc_steal(memctx, ccname);
     496           0 :     *expire_time_out = my_creds.times.endtime - kdc_time_offset;
     497             : 
     498             : done:
     499           0 :     if (krberr != 0) KRB5_SYSLOG(krberr);
     500           0 :     if (keytab) krb5_kt_close(context, keytab);
     501           0 :     if (context) krb5_free_context(context);
     502           0 :     talloc_free(tmp_ctx);
     503           0 :     return krberr;
     504             : }
     505             : 
     506           0 : static int prepare_response(TALLOC_CTX *mem_ctx,
     507             :                             const char *ccname,
     508             :                             time_t expire_time,
     509             :                             krb5_error_code kerr,
     510             :                             struct response **rsp)
     511             : {
     512             :     int ret;
     513           0 :     struct response *r = NULL;
     514           0 :     const char *krb5_msg = NULL;
     515             : 
     516           0 :     r = talloc_zero(mem_ctx, struct response);
     517           0 :     if (!r) return ENOMEM;
     518             : 
     519           0 :     r->buf = NULL;
     520           0 :     r->size = 0;
     521             : 
     522           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Building response for result [%d]\n", kerr);
     523             : 
     524           0 :     if (kerr == 0) {
     525           0 :         ret = pack_buffer(r, EOK, kerr, ccname, expire_time);
     526             :     } else {
     527           0 :         krb5_msg = sss_krb5_get_error_message(krb5_error_ctx, kerr);
     528           0 :         if (krb5_msg == NULL) {
     529           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     530             :                     "sss_krb5_get_error_message failed.\n");
     531           0 :             return ENOMEM;
     532             :         }
     533             : 
     534           0 :         ret = pack_buffer(r, EFAULT, kerr, krb5_msg, 0);
     535           0 :         sss_krb5_free_error_message(krb5_error_ctx, krb5_msg);
     536             :     }
     537             : 
     538           0 :     if (ret != EOK) {
     539           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "pack_buffer failed\n");
     540           0 :         return ret;
     541             :     }
     542             : 
     543           0 :     *rsp = r;
     544           0 :     return EOK;
     545             : }
     546             : 
     547           0 : static krb5_error_code privileged_krb5_setup(struct input_buffer *ibuf)
     548             : {
     549             :     krb5_error_code kerr;
     550             :     char *keytab_name;
     551             : 
     552           0 :     kerr = krb5_init_context(&ibuf->context);
     553           0 :     if (kerr != 0) {
     554           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to init kerberos context\n");
     555           0 :         return kerr;
     556             :     }
     557           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
     558             : 
     559           0 :     kerr = copy_keytab_into_memory(ibuf, ibuf->context, ibuf->keytab_name,
     560             :                                    &keytab_name, NULL);
     561           0 :     if (kerr != 0) {
     562           0 :         DEBUG(SSSDBG_OP_FAILURE, "copy_keytab_into_memory failed.\n");
     563           0 :         return kerr;
     564             :     }
     565           0 :     talloc_free(ibuf->keytab_name);
     566           0 :     ibuf->keytab_name = keytab_name;
     567             : 
     568           0 :     return 0;
     569             : }
     570             : 
     571           0 : int main(int argc, const char *argv[])
     572             : {
     573             :     int ret;
     574             :     int kerr;
     575             :     int opt;
     576           0 :     int debug_fd = -1;
     577             :     poptContext pc;
     578           0 :     TALLOC_CTX *main_ctx = NULL;
     579           0 :     uint8_t *buf = NULL;
     580           0 :     ssize_t len = 0;
     581           0 :     const char *ccname = NULL;
     582           0 :     time_t expire_time = 0;
     583           0 :     struct input_buffer *ibuf = NULL;
     584           0 :     struct response *resp = NULL;
     585             :     ssize_t written;
     586             : 
     587           0 :     struct poptOption long_options[] = {
     588             :         POPT_AUTOHELP
     589             :         {"debug-level", 'd', POPT_ARG_INT, &debug_level, 0,
     590           0 :          _("Debug level"), NULL},
     591             :         {"debug-timestamps", 0, POPT_ARG_INT, &debug_timestamps, 0,
     592           0 :          _("Add debug timestamps"), NULL},
     593             :         {"debug-microseconds", 0, POPT_ARG_INT, &debug_microseconds, 0,
     594           0 :          _("Show timestamps with microseconds"), NULL},
     595             :         {"debug-fd", 0, POPT_ARG_INT, &debug_fd, 0,
     596           0 :          _("An open file descriptor for the debug logs"), NULL},
     597             :         {"debug-to-stderr", 0, POPT_ARG_NONE | POPT_ARGFLAG_DOC_HIDDEN, &debug_to_stderr, 0, \
     598           0 :          _("Send the debug output to stderr directly."), NULL }, \
     599             :         POPT_TABLEEND
     600             :     };
     601             : 
     602             :     /* Set debug level to invalid value so we can decide if -d 0 was used. */
     603           0 :     debug_level = SSSDBG_INVALID;
     604             : 
     605           0 :     pc = poptGetContext(argv[0], argc, argv, long_options, 0);
     606           0 :     while((opt = poptGetNextOpt(pc)) != -1) {
     607             :         switch(opt) {
     608             :         default:
     609           0 :         fprintf(stderr, "\nInvalid option %s: %s\n\n",
     610             :                   poptBadOption(pc, 0), poptStrerror(opt));
     611           0 :             poptPrintUsage(pc, stderr, 0);
     612           0 :             _exit(-1);
     613             :         }
     614             :     }
     615             : 
     616           0 :     poptFreeContext(pc);
     617             : 
     618           0 :     DEBUG_INIT(debug_level);
     619             : 
     620           0 :     debug_prg_name = talloc_asprintf(NULL, "[sssd[ldap_child[%d]]]", getpid());
     621           0 :     if (!debug_prg_name) {
     622           0 :         debug_prg_name = "[sssd[ldap_child]]";
     623           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
     624           0 :         goto fail;
     625             :     }
     626             : 
     627           0 :     if (debug_fd != -1) {
     628           0 :         ret = set_debug_file_from_fd(debug_fd);
     629           0 :         if (ret != EOK) {
     630           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "set_debug_file_from_fd failed.\n");
     631             :         }
     632             :     }
     633             : 
     634           0 :     DEBUG(SSSDBG_TRACE_FUNC, "ldap_child started.\n");
     635             : 
     636           0 :     main_ctx = talloc_new(NULL);
     637           0 :     if (main_ctx == NULL) {
     638           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new failed.\n");
     639           0 :         talloc_free(discard_const(debug_prg_name));
     640           0 :         goto fail;
     641             :     }
     642           0 :     talloc_steal(main_ctx, debug_prg_name);
     643             : 
     644           0 :     buf = talloc_size(main_ctx, sizeof(uint8_t)*IN_BUF_SIZE);
     645           0 :     if (buf == NULL) {
     646           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
     647           0 :         goto fail;
     648             :     }
     649             : 
     650           0 :     ibuf = talloc_zero(main_ctx, struct input_buffer);
     651           0 :     if (ibuf == NULL) {
     652           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
     653           0 :         goto fail;
     654             :     }
     655             : 
     656           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "context initialized\n");
     657             : 
     658           0 :     errno = 0;
     659           0 :     len = sss_atomic_read_s(STDIN_FILENO, buf, IN_BUF_SIZE);
     660           0 :     if (len == -1) {
     661           0 :         ret = errno;
     662           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "read failed [%d][%s].\n", ret, strerror(ret));
     663           0 :         goto fail;
     664             :     }
     665             : 
     666           0 :     close(STDIN_FILENO);
     667             : 
     668           0 :     ret = unpack_buffer(buf, len, ibuf);
     669           0 :     if (ret != EOK) {
     670           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     671             :               "unpack_buffer failed.[%d][%s].\n", ret, strerror(ret));
     672           0 :         goto fail;
     673             :     }
     674             : 
     675           0 :     kerr = privileged_krb5_setup(ibuf);
     676           0 :     if (kerr != EOK) {
     677           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Privileged Krb5 setup failed.\n");
     678           0 :         goto fail;
     679             :     }
     680           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Kerberos context initialized\n");
     681             : 
     682           0 :     kerr = become_user(ibuf->uid, ibuf->gid);
     683           0 :     if (kerr != 0) {
     684           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "become_user failed.\n");
     685           0 :         goto fail;
     686             :     }
     687             : 
     688           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     689             :           "Running as [%"SPRIuid"][%"SPRIgid"].\n", geteuid(), getegid());
     690             : 
     691           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "getting TGT sync\n");
     692           0 :     kerr = ldap_child_get_tgt_sync(main_ctx, ibuf->context,
     693             :                                    ibuf->realm_str, ibuf->princ_str,
     694           0 :                                    ibuf->keytab_name, ibuf->lifetime,
     695             :                                    &ccname, &expire_time);
     696           0 :     if (kerr != EOK) {
     697           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child_get_tgt_sync failed.\n");
     698             :         /* Do not return, must report failure */
     699             :     }
     700             : 
     701           0 :     ret = prepare_response(main_ctx, ccname, expire_time, kerr, &resp);
     702           0 :     if (ret != EOK) {
     703           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "prepare_response failed. [%d][%s].\n",
     704             :                     ret, strerror(ret));
     705           0 :         goto fail;
     706             :     }
     707             : 
     708           0 :     errno = 0;
     709           0 :     written = sss_atomic_write_s(STDOUT_FILENO, resp->buf, resp->size);
     710           0 :     if (written == -1) {
     711           0 :         ret = errno;
     712           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "write failed [%d][%s].\n", ret,
     713             :                     strerror(ret));
     714           0 :         goto fail;
     715             :     }
     716             : 
     717           0 :     if (written != resp->size) {
     718           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Expected to write %zu bytes, wrote %zu\n",
     719             :               resp->size, written);
     720           0 :         goto fail;
     721             :     }
     722             : 
     723           0 :     DEBUG(SSSDBG_TRACE_FUNC, "ldap_child completed successfully\n");
     724           0 :     close(STDOUT_FILENO);
     725           0 :     talloc_free(main_ctx);
     726           0 :     _exit(0);
     727             : 
     728             : fail:
     729           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "ldap_child failed!\n");
     730           0 :     close(STDOUT_FILENO);
     731           0 :     talloc_free(main_ctx);
     732           0 :     _exit(-1);
     733             : }

Generated by: LCOV version 1.10