LCOV - code coverage report
Current view: top level - source3/libnet - libnet_keytab.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 0 212 0.0 %
Date: 2024-02-28 12:06:22 Functions: 0 7 0.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    dump the remote SAM using rpc samsync operations
       4             : 
       5             :    Copyright (C) Guenther Deschner 2008.
       6             :    Copyright (C) Michael Adam 2008
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "smb_krb5.h"
      24             : #include "ads.h"
      25             : #include "secrets.h"
      26             : #include "libnet/libnet_keytab.h"
      27             : 
      28             : #ifdef HAVE_KRB5
      29             : 
      30             : /****************************************************************
      31             : ****************************************************************/
      32             : 
      33           0 : static int keytab_close(struct libnet_keytab_context *ctx)
      34             : {
      35           0 :         if (!ctx) {
      36           0 :                 return 0;
      37             :         }
      38             : 
      39           0 :         if (ctx->keytab && ctx->context) {
      40           0 :                 krb5_kt_close(ctx->context, ctx->keytab);
      41             :         }
      42             : 
      43           0 :         if (ctx->context) {
      44           0 :                 krb5_free_context(ctx->context);
      45             :         }
      46             : 
      47           0 :         TALLOC_FREE(ctx->ads);
      48             : 
      49           0 :         TALLOC_FREE(ctx);
      50             : 
      51           0 :         return 0;
      52             : }
      53             : 
      54             : /****************************************************************
      55             : ****************************************************************/
      56             : 
      57           0 : krb5_error_code libnet_keytab_init(TALLOC_CTX *mem_ctx,
      58             :                                    const char *keytab_name,
      59             :                                    struct libnet_keytab_context **ctx)
      60             : {
      61           0 :         krb5_error_code ret = 0;
      62           0 :         krb5_context context = NULL;
      63           0 :         krb5_keytab keytab = NULL;
      64           0 :         const char *keytab_string = NULL;
      65             : 
      66           0 :         struct libnet_keytab_context *r;
      67             : 
      68           0 :         r = talloc_zero(mem_ctx, struct libnet_keytab_context);
      69           0 :         if (!r) {
      70           0 :                 return ENOMEM;
      71             :         }
      72             : 
      73           0 :         talloc_set_destructor(r, keytab_close);
      74             : 
      75           0 :         ret = smb_krb5_init_context_common(&context);
      76           0 :         if (ret) {
      77           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
      78             :                         error_message(ret));
      79           0 :                 return ret;
      80             :         }
      81             : 
      82           0 :         ret = smb_krb5_kt_open_relative(context,
      83             :                                         keytab_name,
      84             :                                         true, /* write_access */
      85             :                                         &keytab);
      86           0 :         if (ret) {
      87           0 :                 DBG_WARNING("smb_krb5_kt_open_relative failed (%s)\n",
      88             :                             error_message(ret));
      89           0 :                 krb5_free_context(context);
      90           0 :                 return ret;
      91             :         }
      92             : 
      93           0 :         ret = smb_krb5_kt_get_name(mem_ctx, context, keytab, &keytab_string);
      94           0 :         if (ret) {
      95           0 :                 krb5_kt_close(context, keytab);
      96           0 :                 krb5_free_context(context);
      97           0 :                 return ret;
      98             :         }
      99             : 
     100           0 :         r->context = context;
     101           0 :         r->keytab = keytab;
     102           0 :         r->keytab_name = keytab_string;
     103           0 :         r->clean_old_entries = false;
     104             : 
     105           0 :         *ctx = r;
     106             : 
     107           0 :         return 0;
     108             : }
     109             : 
     110             : /****************************************************************
     111             : ****************************************************************/
     112             : 
     113             : /**
     114             :  * Remove all entries that have the given principal, kvno and enctype.
     115             :  */
     116           0 : static krb5_error_code libnet_keytab_remove_entries(krb5_context context,
     117             :                                                     krb5_keytab keytab,
     118             :                                                     const char *principal,
     119             :                                                     int kvno,
     120             :                                                     const krb5_enctype enctype,
     121             :                                                     bool ignore_kvno)
     122             : {
     123           0 :         krb5_error_code ret;
     124           0 :         krb5_kt_cursor cursor;
     125           0 :         krb5_keytab_entry kt_entry;
     126             : 
     127           0 :         ZERO_STRUCT(kt_entry);
     128           0 :         ZERO_STRUCT(cursor);
     129             : 
     130           0 :         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
     131           0 :         if (ret) {
     132           0 :                 return 0;
     133             :         }
     134             : 
     135           0 :         while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0)
     136             :         {
     137           0 :                 krb5_keyblock *keyp;
     138           0 :                 char *princ_s = NULL;
     139             : 
     140           0 :                 if (kt_entry.vno != kvno && !ignore_kvno) {
     141           0 :                         goto cont;
     142             :                 }
     143             : 
     144           0 :                 keyp = KRB5_KT_KEY(&kt_entry);
     145             : 
     146           0 :                 if (KRB5_KEY_TYPE(keyp) != enctype) {
     147           0 :                         goto cont;
     148             :                 }
     149             : 
     150           0 :                 ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal,
     151             :                                             &princ_s);
     152           0 :                 if (ret) {
     153           0 :                         DEBUG(5, ("smb_krb5_unparse_name failed (%s)\n",
     154             :                                   error_message(ret)));
     155           0 :                         goto cont;
     156             :                 }
     157             : 
     158           0 :                 if (strcmp(principal, princ_s) != 0) {
     159           0 :                         goto cont;
     160             :                 }
     161             : 
     162             :                 /* match found - remove */
     163             : 
     164           0 :                 DEBUG(10, ("found entry for principal %s, kvno %d, "
     165             :                            "enctype %d - trying to remove it\n",
     166             :                            princ_s, kt_entry.vno, KRB5_KEY_TYPE(keyp)));
     167             : 
     168           0 :                 ret = krb5_kt_end_seq_get(context, keytab, &cursor);
     169           0 :                 ZERO_STRUCT(cursor);
     170           0 :                 if (ret) {
     171           0 :                         DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n",
     172             :                                   error_message(ret)));
     173           0 :                         goto cont;
     174             :                 }
     175             : 
     176           0 :                 ret = krb5_kt_remove_entry(context, keytab,
     177             :                                            &kt_entry);
     178           0 :                 if (ret) {
     179           0 :                         DEBUG(5, ("krb5_kt_remove_entry failed (%s)\n",
     180             :                                   error_message(ret)));
     181           0 :                         goto cont;
     182             :                 }
     183           0 :                 DEBUG(10, ("removed entry for principal %s, kvno %d, "
     184             :                            "enctype %d\n", princ_s, kt_entry.vno,
     185             :                            KRB5_KEY_TYPE(keyp)));
     186             : 
     187           0 :                 ret = krb5_kt_start_seq_get(context, keytab, &cursor);
     188           0 :                 if (ret) {
     189           0 :                         DEBUG(5, ("krb5_kt_start_seq_get failed (%s)\n",
     190             :                                   error_message(ret)));
     191           0 :                         goto cont;
     192             :                 }
     193             : 
     194           0 : cont:
     195           0 :                 smb_krb5_kt_free_entry(context, &kt_entry);
     196           0 :                 TALLOC_FREE(princ_s);
     197             :         }
     198             : 
     199           0 :         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
     200           0 :         if (ret) {
     201           0 :                 DEBUG(5, ("krb5_kt_end_seq_get failed (%s)\n",
     202             :                           error_message(ret)));
     203             :         }
     204             : 
     205           0 :         return ret;
     206             : }
     207             : 
     208           0 : static krb5_error_code libnet_keytab_add_entry(krb5_context context,
     209             :                                                krb5_keytab keytab,
     210             :                                                krb5_kvno kvno,
     211             :                                                const char *princ_s,
     212             :                                                krb5_enctype enctype,
     213             :                                                krb5_data password)
     214             : {
     215           0 :         krb5_keyblock *keyp;
     216           0 :         krb5_keytab_entry kt_entry;
     217           0 :         krb5_error_code ret;
     218           0 :         krb5_principal salt_princ = NULL;
     219           0 :         char *salt_princ_s;
     220             : 
     221             :         /* remove duplicates first ... */
     222           0 :         ret = libnet_keytab_remove_entries(context, keytab, princ_s, kvno,
     223             :                                            enctype, false);
     224           0 :         if (ret) {
     225           0 :                 DEBUG(1, ("libnet_keytab_remove_entries failed: %s\n",
     226             :                           error_message(ret)));
     227             :         }
     228             : 
     229           0 :         ZERO_STRUCT(kt_entry);
     230             : 
     231           0 :         kt_entry.vno = kvno;
     232             : 
     233           0 :         ret = smb_krb5_parse_name(context, princ_s, &kt_entry.principal);
     234           0 :         if (ret) {
     235           0 :                 DEBUG(1, ("smb_krb5_parse_name(%s) failed (%s)\n",
     236             :                           princ_s, error_message(ret)));
     237           0 :                 return ret;
     238             :         }
     239             : 
     240           0 :         keyp = KRB5_KT_KEY(&kt_entry);
     241             : 
     242           0 :         salt_princ_s = kerberos_secrets_fetch_salt_princ();
     243           0 :         if (salt_princ_s == NULL) {
     244           0 :                 ret = KRB5KRB_ERR_GENERIC;
     245           0 :                 goto done;
     246             :         }
     247             : 
     248           0 :         ret = krb5_parse_name(context, salt_princ_s, &salt_princ);
     249           0 :         SAFE_FREE(salt_princ_s);
     250           0 :         if (ret != 0) {
     251           0 :                 ret = KRB5KRB_ERR_GENERIC;
     252           0 :                 goto done;
     253             :         }
     254             : 
     255           0 :         ret = create_kerberos_key_from_string(context,
     256             :                                               kt_entry.principal,
     257             :                                               salt_princ,
     258             :                                               &password,
     259             :                                               keyp,
     260             :                                               enctype,
     261             :                                               true);
     262           0 :         krb5_free_principal(context, salt_princ);
     263           0 :         if (ret != 0) {
     264           0 :                 ret = KRB5KRB_ERR_GENERIC;
     265           0 :                 goto done;
     266             :         }
     267             : 
     268           0 :         ret = krb5_kt_add_entry(context, keytab, &kt_entry);
     269           0 :         if (ret) {
     270           0 :                 DEBUG(1, ("adding entry to keytab failed (%s)\n",
     271             :                           error_message(ret)));
     272             :         }
     273             : 
     274           0 : done:
     275           0 :         krb5_free_keyblock_contents(context, keyp);
     276           0 :         krb5_free_principal(context, kt_entry.principal);
     277           0 :         ZERO_STRUCT(kt_entry);
     278           0 :         smb_krb5_kt_free_entry(context, &kt_entry);
     279             : 
     280           0 :         return ret;
     281             : }
     282             : 
     283           0 : krb5_error_code libnet_keytab_add(struct libnet_keytab_context *ctx)
     284             : {
     285           0 :         krb5_error_code ret = 0;
     286           0 :         uint32_t i;
     287             : 
     288             : 
     289           0 :         if (ctx->clean_old_entries) {
     290           0 :                 DEBUG(0, ("cleaning old entries...\n"));
     291           0 :                 for (i=0; i < ctx->count; i++) {
     292           0 :                         struct libnet_keytab_entry *entry = &ctx->entries[i];
     293             : 
     294           0 :                         ret = libnet_keytab_remove_entries(ctx->context,
     295             :                                                            ctx->keytab,
     296             :                                                            entry->principal,
     297             :                                                            0,
     298             :                                                            entry->enctype,
     299             :                                                            true);
     300           0 :                         if (ret) {
     301           0 :                                 DEBUG(1,("libnet_keytab_add: Failed to remove "
     302             :                                          "old entries for %s (enctype %u): %s\n",
     303             :                                          entry->principal, entry->enctype,
     304             :                                          error_message(ret)));
     305           0 :                                 return ret;
     306             :                         }
     307             :                 }
     308             :         }
     309             : 
     310           0 :         for (i=0; i<ctx->count; i++) {
     311             : 
     312           0 :                 struct libnet_keytab_entry *entry = &ctx->entries[i];
     313           0 :                 krb5_data password;
     314             : 
     315           0 :                 ZERO_STRUCT(password);
     316           0 :                 password.data = (char *)entry->password.data;
     317           0 :                 password.length = entry->password.length;
     318             : 
     319           0 :                 ret = libnet_keytab_add_entry(ctx->context,
     320             :                                               ctx->keytab,
     321           0 :                                               entry->kvno,
     322             :                                               entry->principal,
     323             :                                               entry->enctype,
     324             :                                               password);
     325           0 :                 if (ret) {
     326           0 :                         DEBUG(1,("libnet_keytab_add: "
     327             :                                 "Failed to add entry to keytab file\n"));
     328           0 :                         return ret;
     329             :                 }
     330             :         }
     331             : 
     332           0 :         return ret;
     333             : }
     334             : 
     335           0 : struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *ctx,
     336             :                                                  const char *principal,
     337             :                                                  int kvno,
     338             :                                                  const krb5_enctype enctype,
     339             :                                                  TALLOC_CTX *mem_ctx)
     340             : {
     341           0 :         krb5_error_code ret = 0;
     342           0 :         krb5_kt_cursor cursor;
     343           0 :         krb5_keytab_entry kt_entry;
     344           0 :         struct libnet_keytab_entry *entry = NULL;
     345             : 
     346           0 :         ZERO_STRUCT(kt_entry);
     347           0 :         ZERO_STRUCT(cursor);
     348             : 
     349           0 :         ret = krb5_kt_start_seq_get(ctx->context, ctx->keytab, &cursor);
     350           0 :         if (ret) {
     351           0 :                 DEBUG(10, ("krb5_kt_start_seq_get failed: %s\n",
     352             :                           error_message(ret)));
     353           0 :                 return NULL;
     354             :         }
     355             : 
     356           0 :         while (krb5_kt_next_entry(ctx->context, ctx->keytab, &kt_entry, &cursor) == 0)
     357           0 :         {
     358           0 :                 krb5_keyblock *keyp;
     359           0 :                 char *princ_s = NULL;
     360             : 
     361           0 :                 entry = NULL;
     362             : 
     363           0 :                 if (kt_entry.vno != kvno) {
     364           0 :                         goto cont;
     365             :                 }
     366             : 
     367           0 :                 keyp = KRB5_KT_KEY(&kt_entry);
     368             : 
     369           0 :                 if (KRB5_KEY_TYPE(keyp) != enctype) {
     370           0 :                         goto cont;
     371             :                 }
     372             : 
     373           0 :                 entry = talloc_zero(mem_ctx, struct libnet_keytab_entry);
     374           0 :                 if (!entry) {
     375           0 :                         DEBUG(3, ("talloc failed\n"));
     376           0 :                         goto fail;
     377             :                 }
     378             : 
     379           0 :                 ret = smb_krb5_unparse_name(entry, ctx->context, kt_entry.principal,
     380             :                                             &princ_s);
     381           0 :                 if (ret) {
     382           0 :                         goto cont;
     383             :                 }
     384             : 
     385           0 :                 if (strcmp(principal, princ_s) != 0) {
     386           0 :                         goto cont;
     387             :                 }
     388             : 
     389           0 :                 entry->principal = talloc_strdup(entry, princ_s);
     390           0 :                 if (!entry->principal) {
     391           0 :                         DEBUG(3, ("talloc_strdup_failed\n"));
     392           0 :                         goto fail;
     393             :                 }
     394             : 
     395           0 :                 entry->name = talloc_move(entry, &princ_s);
     396             : 
     397           0 :                 entry->password = data_blob_talloc(entry, KRB5_KEY_DATA(keyp),
     398             :                                                    KRB5_KEY_LENGTH(keyp));
     399           0 :                 if (!entry->password.data) {
     400           0 :                         DEBUG(3, ("data_blob_talloc failed\n"));
     401           0 :                         goto fail;
     402             :                 }
     403             : 
     404           0 :                 DEBUG(10, ("found entry\n"));
     405             : 
     406           0 :                 smb_krb5_kt_free_entry(ctx->context, &kt_entry);
     407           0 :                 break;
     408             : 
     409           0 : fail:
     410           0 :                 smb_krb5_kt_free_entry(ctx->context, &kt_entry);
     411           0 :                 TALLOC_FREE(entry);
     412           0 :                 break;
     413             : 
     414           0 : cont:
     415           0 :                 smb_krb5_kt_free_entry(ctx->context, &kt_entry);
     416           0 :                 TALLOC_FREE(entry);
     417           0 :                 continue;
     418             :         }
     419             : 
     420           0 :         krb5_kt_end_seq_get(ctx->context, ctx->keytab, &cursor);
     421           0 :         return entry;
     422             : }
     423             : 
     424             : /**
     425             :  * Helper function to add data to the list
     426             :  * of keytab entries. It builds the prefix from the input.
     427             :  */
     428           0 : NTSTATUS libnet_keytab_add_to_keytab_entries(TALLOC_CTX *mem_ctx,
     429             :                                              struct libnet_keytab_context *ctx,
     430             :                                              uint32_t kvno,
     431             :                                              const char *name,
     432             :                                              const char *prefix,
     433             :                                              const krb5_enctype enctype,
     434             :                                              DATA_BLOB blob)
     435             : {
     436           0 :         struct libnet_keytab_entry entry;
     437             : 
     438           0 :         entry.kvno = kvno;
     439           0 :         entry.name = talloc_strdup(mem_ctx, name);
     440           0 :         entry.principal = talloc_asprintf(mem_ctx, "%s%s%s@%s",
     441             :                                           prefix ? prefix : "",
     442             :                                           prefix ? "/" : "",
     443             :                                           name, ctx->dns_domain_name);
     444           0 :         entry.enctype = enctype;
     445           0 :         entry.password = blob;
     446           0 :         NT_STATUS_HAVE_NO_MEMORY(entry.name);
     447           0 :         NT_STATUS_HAVE_NO_MEMORY(entry.principal);
     448           0 :         NT_STATUS_HAVE_NO_MEMORY(entry.password.data);
     449             : 
     450           0 :         ADD_TO_ARRAY(mem_ctx, struct libnet_keytab_entry, entry,
     451             :                      &ctx->entries, &ctx->count);
     452           0 :         NT_STATUS_HAVE_NO_MEMORY(ctx->entries);
     453             : 
     454           0 :         return NT_STATUS_OK;
     455             : }
     456             : 
     457             : #endif /* HAVE_KRB5 */

Generated by: LCOV version 1.14