📄 kerberos_keytab.c
字号:
/* Unix SMB/CIFS implementation. kerberos keytab utility library Copyright (C) Andrew Tridgell 2001 Copyright (C) Remus Koos 2001 Copyright (C) Luke Howard 2003 Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003 Copyright (C) Guenther Deschner 2003 Copyright (C) Rakesh Patel 2004 Copyright (C) Dan Perry 2004 Copyright (C) Jeremy Allison 2004 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 2 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, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include "includes.h"#ifdef HAVE_KRB5/********************************************************************** Adds a single service principal, i.e. 'host' to the system keytab***********************************************************************/int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc){ krb5_error_code ret = 0; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_kt_cursor cursor; krb5_keytab_entry kt_entry; krb5_principal princ = NULL; krb5_data password; krb5_enctype *enctypes = NULL; krb5_kvno kvno; char *principal = NULL; char *princ_s = NULL; char *password_s = NULL;#ifndef MAX_KEYTAB_NAME_LEN#define MAX_KEYTAB_NAME_LEN 1100#endif char keytab_name[MAX_KEYTAB_NAME_LEN]; /* This MAX_NAME_LEN is a constant defined in krb5.h */ fstring my_fqdn; int i; char *ktprinc = NULL; ZERO_STRUCT(kt_entry); ZERO_STRUCT(cursor); initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("ads_keytab_add_entry: could not krb5_init_context: %s\n",error_message(ret))); return -1; }#ifdef HAVE_WRFILE_KEYTAB /* MIT */ keytab_name[0] = 'W'; keytab_name[1] = 'R'; ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4);#else /* Heimdal */ ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2);#endif if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_default_name failed (%s)\n", error_message(ret))); goto out; } DEBUG(2,("ads_keytab_add_entry: Using default system keytab: %s\n", (char *) &keytab_name)); ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_resolve failed (%s)\n", error_message(ret))); goto out; } /* retrieve the password */ if (!secrets_init()) { DEBUG(1,("ads_keytab_add_entry: secrets_init failed\n")); ret = -1; goto out; } password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!password_s) { DEBUG(1,("ads_keytab_add_entry: failed to fetch machine password\n")); ret = -1; goto out; } password.data = password_s; password.length = strlen(password_s); /* Construct our principal */ name_to_fqdn(my_fqdn, global_myname()); strlower_m(my_fqdn); if (strchr_m(srvPrinc, '@')) { /* It's a fully-named principal. */ asprintf(&princ_s, "%s", srvPrinc); } else if (srvPrinc[strlen(srvPrinc)-1] == '$') { /* It's the machine account, as used by smbclient clients. */ asprintf(&princ_s, "%s@%s", srvPrinc, lp_realm()); } else { /* It's a normal service principal. Add the SPN now so that we * can obtain credentials for it and double-check the salt value * used to generate the service's keys. */ asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm()); /* Update the directory with the SPN */ DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s)); if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), srvPrinc))) { DEBUG(1,("ads_keytab_add_entry: ads_add_service_principal_name failed.\n")); goto out; } } ret = get_kerberos_allowed_etypes(context,&enctypes); if (ret) { DEBUG(1,("ads_keytab_add_entry: get_kerberos_allowed_etypes failed (%s)\n",error_message(ret))); goto out; } /* Guess at how the KDC is salting keys for this principal. */ kerberos_derive_salting_principal(princ_s); ret = krb5_parse_name(context, princ_s, &princ); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); goto out; } kvno = (krb5_kvno) ads_get_kvno(ads, global_myname()); if (kvno == -1) { /* -1 indicates failure, everything else is OK */ DEBUG(1,("ads_keytab_add_entry: ads_get_kvno failed to determine the system's kvno.\n")); ret = -1; goto out; } /* Seek and delete old keytab entries */ ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret != KRB5_KT_END && ret != ENOENT ) { DEBUG(3,("ads_keytab_add_entry: Will try to delete old keytab entries\n")); while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { BOOL compare_name_ok = False; ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_unparse_name failed (%s)\n", error_message(ret))); goto out; } /*--------------------------------------------------------------------------- * Save the entries with kvno - 1. This is what microsoft does * to allow people with existing sessions that have kvno - 1 to still * work. Otherwise, when the password for the machine changes, all * kerberizied sessions will 'break' until either the client reboots or * the client's session key expires and they get a new session ticket * with the new kvno. */#ifdef HAVE_KRB5_KT_COMPARE compare_name_ok = (krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True);#else compare_name_ok = (strcmp(ktprinc, princ_s) == 0);#endif if (!compare_name_ok) { DEBUG(10,("ads_keytab_add_entry: ignoring keytab entry principal %s, kvno = %d\n", ktprinc, kt_entry.vno)); } krb5_free_unparsed_name(context, ktprinc); ktprinc = NULL; if (compare_name_ok) { if (kt_entry.vno == kvno - 1) { DEBUG(5,("ads_keytab_add_entry: Saving previous (kvno %d) entry for principal: %s.\n", kvno - 1, princ_s)); } else { DEBUG(5,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n", princ_s, kt_entry.vno)); ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n", error_message(ret))); goto out; } ret = krb5_kt_remove_entry(context, keytab, &kt_entry); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto out; } DEBUG(5,("ads_keytab_add_entry: removed old entry for principal: %s (kvno %d).\n", princ_s, kt_entry.vno)); ret = krb5_kt_start_seq_get(context, keytab, &cursor); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n", error_message(ret))); goto out; } ret = smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n", error_message(ret))); goto out; } continue; } } /* Not a match, just free this entry and continue. */ ret = smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); if (ret) { DEBUG(1,("ads_keytab_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret))); goto out; } } ret = krb5_kt_end_seq_get(context, keytab, &cursor); ZERO_STRUCT(cursor); if (ret) { DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret))); goto out; } } /* Ensure we don't double free. */ ZERO_STRUCT(kt_entry); ZERO_STRUCT(cursor); /* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */ /* Now add keytab entries for all encryption types */ for (i = 0; enctypes[i]; i++) { krb5_keyblock *keyp;#if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK)#error krb5_keytab_entry has no key or keyblock member#endif#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY /* MIT */ keyp = &kt_entry.key;#endif#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */ keyp = &kt_entry.keyblock;#endif if (create_kerberos_key_from_string(context, princ, &password, keyp, enctypes[i])) { continue; } kt_entry.principal = princ; kt_entry.vno = kvno; DEBUG(3,("ads_keytab_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n", princ_s, enctypes[i], kt_entry.vno)); ret = krb5_kt_add_entry(context, keytab, &kt_entry); krb5_free_keyblock_contents(context, keyp); ZERO_STRUCT(kt_entry); if (ret) { DEBUG(1,("ads_keytab_add_entry: adding entry to keytab failed (%s)\n", error_message(ret))); goto out; } } krb5_kt_close(context, keytab); keytab = NULL; /* Done with keytab now. No double free. */out: SAFE_FREE(principal); SAFE_FREE(password_s); SAFE_FREE(princ_s); { krb5_keytab_entry zero_kt_entry; ZERO_STRUCT(zero_kt_entry); if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { smb_krb5_kt_free_entry(context, &kt_entry); } } if (princ) { krb5_free_principal(context, princ); } if (enctypes) { free_kerberos_etypes(context, enctypes); } { krb5_kt_cursor zero_csr; ZERO_STRUCT(zero_csr); if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { krb5_kt_end_seq_get(context, keytab, &cursor); } } if (keytab) { krb5_kt_close(context, keytab); } if (context) { krb5_free_context(context); } return (int)ret;}/********************************************************************** Flushes all entries from the system keytab.***********************************************************************/int ads_keytab_flush(ADS_STRUCT *ads){ krb5_error_code ret = 0; krb5_context context = NULL; krb5_keytab keytab = NULL; krb5_kt_cursor cursor; krb5_keytab_entry kt_entry; krb5_kvno kvno;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -