libads/kerberos_keytab.c

説明を見る。
00001 /*
00002    Unix SMB/CIFS implementation.
00003    kerberos keytab utility library
00004    Copyright (C) Andrew Tridgell 2001
00005    Copyright (C) Remus Koos 2001
00006    Copyright (C) Luke Howard 2003
00007    Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003
00008    Copyright (C) Guenther Deschner 2003
00009    Copyright (C) Rakesh Patel 2004
00010    Copyright (C) Dan Perry 2004
00011    Copyright (C) Jeremy Allison 2004
00012    Copyright (C) Gerald Carter 2006
00013 
00014    This program is free software; you can redistribute it and/or modify
00015    it under the terms of the GNU General Public License as published by
00016    the Free Software Foundation; either version 2 of the License, or
00017    (at your option) any later version.
00018 
00019    This program is distributed in the hope that it will be useful,
00020    but WITHOUT ANY WARRANTY; without even the implied warranty of
00021    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022    GNU General Public License for more details.
00023 
00024    You should have received a copy of the GNU General Public License
00025    along with this program; if not, write to the Free Software
00026    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00027 */
00028 
00029 #include "includes.h"
00030 
00031 #ifdef HAVE_KRB5
00032 
00033 /* This MAX_NAME_LEN is a constant defined in krb5.h */
00034 #ifndef MAX_KEYTAB_NAME_LEN
00035 #define MAX_KEYTAB_NAME_LEN 1100
00036 #endif
00037 
00038 
00039 /**********************************************************************
00040 **********************************************************************/
00041 
00042 static int smb_krb5_kt_add_entry( krb5_context context, krb5_keytab keytab,
00043                                   krb5_kvno kvno, const char *princ_s, 
00044                                   krb5_enctype *enctypes, krb5_data password )
00045 {
00046         krb5_error_code ret = 0;
00047         krb5_kt_cursor cursor;
00048         krb5_keytab_entry kt_entry;
00049         krb5_principal princ = NULL;
00050         int i;
00051         char *ktprinc = NULL;
00052 
00053         ZERO_STRUCT(kt_entry);
00054         ZERO_STRUCT(cursor);
00055         
00056         ret = smb_krb5_parse_name(context, princ_s, &princ);
00057         if (ret) {
00058                 DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret)));
00059                 goto out;
00060         }
00061 
00062         /* Seek and delete old keytab entries */
00063         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
00064         if (ret != KRB5_KT_END && ret != ENOENT ) {
00065                 DEBUG(3,("smb_krb5_kt_add_entry: Will try to delete old keytab entries\n"));
00066                 while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
00067                         BOOL compare_name_ok = False;
00068 
00069                         ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc);
00070                         if (ret) {
00071                                 DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_unparse_name failed (%s)\n",
00072                                         error_message(ret)));
00073                                 goto out;
00074                         }
00075 
00076                         /*---------------------------------------------------------------------------
00077                          * Save the entries with kvno - 1.   This is what microsoft does
00078                          * to allow people with existing sessions that have kvno - 1 to still
00079                          * work.   Otherwise, when the password for the machine changes, all
00080                          * kerberizied sessions will 'break' until either the client reboots or
00081                          * the client's session key expires and they get a new session ticket
00082                          * with the new kvno.
00083                          */
00084 
00085 #ifdef HAVE_KRB5_KT_COMPARE
00086                         compare_name_ok = (krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True);
00087 #else
00088                         compare_name_ok = (strcmp(ktprinc, princ_s) == 0);
00089 #endif
00090 
00091                         if (!compare_name_ok) {
00092                                 DEBUG(10,("smb_krb5_kt_add_entry: ignoring keytab entry principal %s, kvno = %d\n",
00093                                         ktprinc, kt_entry.vno));
00094                         }
00095 
00096                         SAFE_FREE(ktprinc);
00097 
00098                         if (compare_name_ok) {
00099                                 if (kt_entry.vno == kvno - 1) {
00100                                         DEBUG(5,("smb_krb5_kt_add_entry: Saving previous (kvno %d) entry for principal: %s.\n",
00101                                                 kvno - 1, princ_s));
00102                                 } else {
00103 
00104                                         DEBUG(5,("smb_krb5_kt_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n",
00105                                                 princ_s, kt_entry.vno));
00106                                         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
00107                                         ZERO_STRUCT(cursor);
00108                                         if (ret) {
00109                                                 DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_end_seq_get() failed (%s)\n",
00110                                                         error_message(ret)));
00111                                                 goto out;
00112                                         }
00113                                         ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
00114                                         if (ret) {
00115                                                 DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s)\n",
00116                                                         error_message(ret)));
00117                                                 goto out;
00118                                         }
00119 
00120                                         DEBUG(5,("smb_krb5_kt_add_entry: removed old entry for principal: %s (kvno %d).\n",
00121                                                 princ_s, kt_entry.vno));
00122 
00123                                         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
00124                                         if (ret) {
00125                                                 DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_start_seq failed (%s)\n",
00126                                                         error_message(ret)));
00127                                                 goto out;
00128                                         }
00129                                         ret = smb_krb5_kt_free_entry(context, &kt_entry);
00130                                         ZERO_STRUCT(kt_entry);
00131                                         if (ret) {
00132                                                 DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_remove_entry failed (%s)\n",
00133                                                         error_message(ret)));
00134                                                 goto out;
00135                                         }
00136                                         continue;
00137                                 }
00138                         }
00139 
00140                         /* Not a match, just free this entry and continue. */
00141                         ret = smb_krb5_kt_free_entry(context, &kt_entry);
00142                         ZERO_STRUCT(kt_entry);
00143                         if (ret) {
00144                                 DEBUG(1,("smb_krb5_kt_add_entry: smb_krb5_kt_free_entry failed (%s)\n", error_message(ret)));
00145                                 goto out;
00146                         }
00147                 }
00148 
00149                 ret = krb5_kt_end_seq_get(context, keytab, &cursor);
00150                 ZERO_STRUCT(cursor);
00151                 if (ret) {
00152                         DEBUG(1,("smb_krb5_kt_add_entry: krb5_kt_end_seq_get failed (%s)\n",error_message(ret)));
00153                         goto out;
00154                 }
00155         }
00156 
00157         /* Ensure we don't double free. */
00158         ZERO_STRUCT(kt_entry);
00159         ZERO_STRUCT(cursor);
00160 
00161         /* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */
00162 
00163         /* Now add keytab entries for all encryption types */
00164         for (i = 0; enctypes[i]; i++) {
00165                 krb5_keyblock *keyp;
00166 
00167 #if !defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) && !defined(HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK)
00168 #error krb5_keytab_entry has no key or keyblock member
00169 #endif
00170 #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEY               /* MIT */
00171                 keyp = &kt_entry.key;
00172 #endif
00173 #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK          /* Heimdal */
00174                 keyp = &kt_entry.keyblock;
00175 #endif
00176                 if (create_kerberos_key_from_string(context, princ, &password, keyp, enctypes[i])) {
00177                         continue;
00178                 }
00179 
00180                 kt_entry.principal = princ;
00181                 kt_entry.vno       = kvno;
00182 
00183                 DEBUG(3,("smb_krb5_kt_add_entry: adding keytab entry for (%s) with encryption type (%d) and version (%d)\n",
00184                         princ_s, enctypes[i], kt_entry.vno));
00185                 ret = krb5_kt_add_entry(context, keytab, &kt_entry);
00186                 krb5_free_keyblock_contents(context, keyp);
00187                 ZERO_STRUCT(kt_entry);
00188                 if (ret) {
00189                         DEBUG(1,("smb_krb5_kt_add_entry: adding entry to keytab failed (%s)\n", error_message(ret)));
00190                         goto out;
00191                 }
00192         }
00193 
00194 
00195 out:
00196         {
00197                 krb5_keytab_entry zero_kt_entry;
00198                 ZERO_STRUCT(zero_kt_entry);
00199                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
00200                         smb_krb5_kt_free_entry(context, &kt_entry);
00201                 }
00202         }
00203         if (princ) {
00204                 krb5_free_principal(context, princ);
00205         }
00206         
00207         {
00208                 krb5_kt_cursor zero_csr;
00209                 ZERO_STRUCT(zero_csr);
00210                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
00211                         krb5_kt_end_seq_get(context, keytab, &cursor);  
00212                 }
00213         }
00214         
00215         return (int)ret;
00216 }
00217 
00218 
00219 /**********************************************************************
00220  Adds a single service principal, i.e. 'host' to the system keytab
00221 ***********************************************************************/
00222 
00223 int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
00224 {
00225         krb5_error_code ret = 0;
00226         krb5_context context = NULL;
00227         krb5_keytab keytab = NULL;
00228         krb5_data password;
00229         krb5_kvno kvno;
00230         krb5_enctype enctypes[4] = { ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, 0, 0 };
00231         char *princ_s = NULL, *short_princ_s = NULL;
00232         char *password_s = NULL;
00233         char *my_fqdn;
00234         char keytab_name[MAX_KEYTAB_NAME_LEN];          
00235         TALLOC_CTX *ctx = NULL;
00236         char *machine_name;
00237 
00238 #if defined(ENCTYPE_ARCFOUR_HMAC)
00239         enctypes[2] = ENCTYPE_ARCFOUR_HMAC;
00240 #endif
00241 
00242         initialize_krb5_error_table();
00243         ret = krb5_init_context(&context);
00244         if (ret) {
00245                 DEBUG(1,("ads_keytab_add_entry: could not krb5_init_context: %s\n",error_message(ret)));
00246                 return -1;
00247         }
00248         
00249 #ifdef HAVE_WRFILE_KEYTAB       /* MIT */
00250         keytab_name[0] = 'W';
00251         keytab_name[1] = 'R';
00252         ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4);
00253 #else                           /* Heimdal */
00254         ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2);
00255 #endif
00256         if (ret) {
00257                 DEBUG(1,("ads_keytab_add_entry: krb5_kt_default_name failed (%s)\n", error_message(ret)));
00258                 goto out;
00259         }
00260         DEBUG(2,("ads_keytab_add_entry: Using default system keytab: %s\n", (char *) &keytab_name));
00261         ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab);
00262         if (ret) {
00263                 DEBUG(1,("ads_keytab_add_entry: krb5_kt_resolve failed (%s)\n", error_message(ret)));
00264                 goto out;
00265         }
00266 
00267         /* retrieve the password */
00268         if (!secrets_init()) {
00269                 DEBUG(1,("ads_keytab_add_entry: secrets_init failed\n"));
00270                 ret = -1;
00271                 goto out;
00272         }
00273         password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
00274         if (!password_s) {
00275                 DEBUG(1,("ads_keytab_add_entry: failed to fetch machine password\n"));
00276                 ret = -1;
00277                 goto out;
00278         }
00279         password.data = password_s;
00280         password.length = strlen(password_s);
00281 
00282         /* we need the dNSHostName value here */
00283         
00284         if ( (ctx = talloc_init("ads_keytab_add_entry")) == NULL ) {
00285                 DEBUG(0,("ads_keytab_add_entry: talloc() failed!\n"));
00286                 ret = -1;
00287                 goto out;
00288         }
00289         
00290         if ( (my_fqdn = ads_get_dnshostname( ads, ctx, global_myname())) == NULL ) {
00291                 DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's dns name in AD!\n"));
00292                 ret = -1;
00293                 goto out;       
00294         }
00295         
00296         if ( (machine_name = ads_get_samaccountname( ads, ctx, global_myname())) == NULL ) {
00297                 DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's short name in AD!\n"));
00298                 ret = -1;
00299                 goto out;       
00300         }
00301         /*strip the trailing '$' */
00302         machine_name[strlen(machine_name)-1] = '\0';
00303                 
00304         /* Construct our principal */
00305 
00306         if (strchr_m(srvPrinc, '@')) {
00307                 /* It's a fully-named principal. */
00308                 asprintf(&princ_s, "%s", srvPrinc);
00309         } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
00310                 /* It's the machine account, as used by smbclient clients. */
00311                 asprintf(&princ_s, "%s@%s", srvPrinc, lp_realm());
00312         } else {
00313                 /* It's a normal service principal.  Add the SPN now so that we
00314                  * can obtain credentials for it and double-check the salt value
00315                  * used to generate the service's keys. */
00316                  
00317                 asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm());
00318                 asprintf(&short_princ_s, "%s/%s@%s", srvPrinc, machine_name, lp_realm());
00319                 
00320                 /* According to http://support.microsoft.com/kb/326985/en-us, 
00321                    certain principal names are automatically mapped to the host/...
00322                    principal in the AD account.  So only create these in the 
00323                    keytab, not in AD.  --jerry */
00324                    
00325                 if ( !strequal( srvPrinc, "cifs" ) && !strequal(srvPrinc, "host" ) ) {
00326                         DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s));
00327                         
00328                         if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), my_fqdn, srvPrinc))) {
00329                                 DEBUG(1,("ads_keytab_add_entry: ads_add_service_principal_name failed.\n"));
00330                                 goto out;
00331                         }
00332                 }
00333         }
00334 
00335         kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
00336         if (kvno == -1) {       /* -1 indicates failure, everything else is OK */
00337                 DEBUG(1,("ads_keytab_add_entry: ads_get_kvno failed to determine the system's kvno.\n"));
00338                 ret = -1;
00339                 goto out;
00340         }
00341         
00342         /* add the fqdn principal to the keytab */
00343         
00344         ret = smb_krb5_kt_add_entry( context, keytab, kvno, princ_s, enctypes, password );
00345         if ( ret ) {
00346                 DEBUG(1,("ads_keytab_add_entry: Failed to add entry to keytab file\n"));
00347                 goto out;
00348         }
00349         
00350         /* add the short principal name if we have one */
00351         
00352         if ( short_princ_s ) {
00353                 ret = smb_krb5_kt_add_entry( context, keytab, kvno, short_princ_s, enctypes, password );
00354                 if ( ret ) {
00355                         DEBUG(1,("ads_keytab_add_entry: Failed to add short entry to keytab file\n"));
00356                         goto out;
00357                 }
00358         }
00359 
00360 out:
00361         SAFE_FREE( princ_s );
00362         SAFE_FREE( short_princ_s );
00363         TALLOC_FREE( ctx );
00364         
00365         if (keytab) {
00366                 krb5_kt_close(context, keytab);
00367         }
00368         if (context) {
00369                 krb5_free_context(context);
00370         }
00371         return (int)ret;
00372 }
00373 
00374 /**********************************************************************
00375  Flushes all entries from the system keytab.
00376 ***********************************************************************/
00377 
00378 int ads_keytab_flush(ADS_STRUCT *ads)
00379 {
00380         krb5_error_code ret = 0;
00381         krb5_context context = NULL;
00382         krb5_keytab keytab = NULL;
00383         krb5_kt_cursor cursor;
00384         krb5_keytab_entry kt_entry;
00385         krb5_kvno kvno;
00386         char keytab_name[MAX_KEYTAB_NAME_LEN];
00387 
00388         ZERO_STRUCT(kt_entry);
00389         ZERO_STRUCT(cursor);
00390 
00391         initialize_krb5_error_table();
00392         ret = krb5_init_context(&context);
00393         if (ret) {
00394                 DEBUG(1,("ads_keytab_flush: could not krb5_init_context: %s\n",error_message(ret)));
00395                 return ret;
00396         }
00397 #ifdef HAVE_WRFILE_KEYTAB
00398         keytab_name[0] = 'W';
00399         keytab_name[1] = 'R';
00400         ret = krb5_kt_default_name(context, (char *) &keytab_name[2], MAX_KEYTAB_NAME_LEN - 4);
00401 #else
00402         ret = krb5_kt_default_name(context, (char *) &keytab_name[0], MAX_KEYTAB_NAME_LEN - 2);
00403 #endif
00404         if (ret) {
00405                 DEBUG(1,("ads_keytab_flush: krb5_kt_default failed (%s)\n", error_message(ret)));
00406                 goto out;
00407         }
00408         DEBUG(3,("ads_keytab_flush: Using default keytab: %s\n", (char *) &keytab_name));
00409         ret = krb5_kt_resolve(context, (char *) &keytab_name, &keytab);
00410         if (ret) {
00411                 DEBUG(1,("ads_keytab_flush: krb5_kt_resolve failed (%s)\n", error_message(ret)));
00412                 goto out;
00413         }
00414 
00415         kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
00416         if (kvno == -1) {       /* -1 indicates a failure */
00417                 DEBUG(1,("ads_keytab_flush: Error determining the system's kvno.\n"));
00418                 goto out;
00419         }
00420 
00421         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
00422         if (ret != KRB5_KT_END && ret != ENOENT) {
00423                 while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
00424                         ret = krb5_kt_end_seq_get(context, keytab, &cursor);
00425                         ZERO_STRUCT(cursor);
00426                         if (ret) {
00427                                 DEBUG(1,("ads_keytab_flush: krb5_kt_end_seq_get() failed (%s)\n",error_message(ret)));
00428                                 goto out;
00429                         }
00430                         ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
00431                         if (ret) {
00432                                 DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
00433                                 goto out;
00434                         }
00435                         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
00436                         if (ret) {
00437                                 DEBUG(1,("ads_keytab_flush: krb5_kt_start_seq failed (%s)\n",error_message(ret)));
00438                                 goto out;
00439                         }
00440                         ret = smb_krb5_kt_free_entry(context, &kt_entry);
00441                         ZERO_STRUCT(kt_entry);
00442                         if (ret) {
00443                                 DEBUG(1,("ads_keytab_flush: krb5_kt_remove_entry failed (%s)\n",error_message(ret)));
00444                                 goto out;
00445                         }
00446                 }
00447         }
00448 
00449         /* Ensure we don't double free. */
00450         ZERO_STRUCT(kt_entry);
00451         ZERO_STRUCT(cursor);
00452 
00453         if (!ADS_ERR_OK(ads_clear_service_principal_names(ads, global_myname()))) {
00454                 DEBUG(1,("ads_keytab_flush: Error while clearing service principal listings in LDAP.\n"));
00455                 goto out;
00456         }
00457 
00458 out:
00459 
00460         {
00461                 krb5_keytab_entry zero_kt_entry;
00462                 ZERO_STRUCT(zero_kt_entry);
00463                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
00464                         smb_krb5_kt_free_entry(context, &kt_entry);
00465                 }
00466         }
00467         {
00468                 krb5_kt_cursor zero_csr;
00469                 ZERO_STRUCT(zero_csr);
00470                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
00471                         krb5_kt_end_seq_get(context, keytab, &cursor);  
00472                 }
00473         }
00474         if (keytab) {
00475                 krb5_kt_close(context, keytab);
00476         }
00477         if (context) {
00478                 krb5_free_context(context);
00479         }
00480         return ret;
00481 }
00482 
00483 /**********************************************************************
00484  Adds all the required service principals to the system keytab.
00485 ***********************************************************************/
00486 
00487 int ads_keytab_create_default(ADS_STRUCT *ads)
00488 {
00489         krb5_error_code ret = 0;
00490         krb5_context context = NULL;
00491         krb5_keytab keytab = NULL;
00492         krb5_kt_cursor cursor;
00493         krb5_keytab_entry kt_entry;
00494         krb5_kvno kvno;
00495         int i, found = 0;
00496         char *sam_account_name, *upn;
00497         char **oldEntries = NULL, *princ_s[26];
00498         TALLOC_CTX *ctx = NULL;
00499         fstring machine_name;
00500 
00501         memset(princ_s, '\0', sizeof(princ_s));
00502 
00503         fstrcpy( machine_name, global_myname() );
00504 
00505         /* these are the main ones we need */
00506         
00507         if ( (ret = ads_keytab_add_entry(ads, "host") ) != 0 ) {
00508                 DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'host'.\n"));
00509                 return ret;
00510         }
00511 
00512 
00513 #if 0   /* don't create the CIFS/... keytab entries since no one except smbd 
00514            really needs them and we will fall back to verifying against secrets.tdb */
00515            
00516         if ( (ret = ads_keytab_add_entry(ads, "cifs")) != 0 ) {
00517                 DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding 'cifs'.\n"));
00518                 return ret;
00519         }
00520 #endif
00521 
00522         if ( (ctx = talloc_init("ads_keytab_create_default")) == NULL ) {
00523                 DEBUG(0,("ads_keytab_create_default: talloc() failed!\n"));
00524                 return -1;
00525         }
00526 
00527         /* now add the userPrincipalName and sAMAccountName entries */
00528 
00529         if ( (sam_account_name = ads_get_samaccountname( ads, ctx, machine_name)) == NULL ) {
00530                 DEBUG(0,("ads_keytab_add_entry: unable to determine machine account's name in AD!\n"));
00531                 TALLOC_FREE( ctx );
00532                 return -1;      
00533         }
00534 
00535         /* upper case the sAMAccountName to make it easier for apps to 
00536            know what case to use in the keytab file */
00537 
00538         strupper_m( sam_account_name ); 
00539 
00540         if ( (ret = ads_keytab_add_entry(ads, sam_account_name )) != 0 ) {
00541                 DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding sAMAccountName (%s)\n",
00542                         sam_account_name));
00543                 return ret;
00544         }
00545         
00546         /* remember that not every machine account will have a upn */
00547                 
00548         upn = ads_get_upn( ads, ctx, machine_name);
00549         if ( upn ) {
00550                 if ( (ret = ads_keytab_add_entry(ads, upn)) != 0 ) {
00551                         DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding UPN (%s)\n",
00552                                 upn));
00553                         TALLOC_FREE( ctx );
00554                         return ret;
00555                 }
00556         }
00557 
00558         TALLOC_FREE( ctx );
00559 
00560         /* Now loop through the keytab and update any other existing entries... */
00561         
00562         kvno = (krb5_kvno) ads_get_kvno(ads, machine_name);
00563         if (kvno == -1) {
00564                 DEBUG(1,("ads_keytab_create_default: ads_get_kvno failed to determine the system's kvno.\n"));
00565                 return -1;
00566         }
00567         
00568         DEBUG(3,("ads_keytab_create_default: Searching for keytab entries to "
00569                 "preserve and update.\n"));
00570 
00571         ZERO_STRUCT(kt_entry);
00572         ZERO_STRUCT(cursor);
00573 
00574         initialize_krb5_error_table();
00575         ret = krb5_init_context(&context);
00576         if (ret) {
00577                 DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret)));
00578                 return ret;
00579         }
00580         ret = krb5_kt_default(context, &keytab);
00581         if (ret) {
00582                 DEBUG(1,("ads_keytab_create_default: krb5_kt_default failed (%s)\n",error_message(ret)));
00583                 goto done;
00584         }
00585 
00586         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
00587         if (ret != KRB5_KT_END && ret != ENOENT ) {
00588                 while ((ret = krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) == 0) {
00589                         smb_krb5_kt_free_entry(context, &kt_entry);
00590                         ZERO_STRUCT(kt_entry);
00591                         found++;
00592                 }
00593         }
00594         krb5_kt_end_seq_get(context, keytab, &cursor);
00595         ZERO_STRUCT(cursor);
00596 
00597         /*
00598          * Hmmm. There is no "rewind" function for the keytab. This means we have a race condition
00599          * where someone else could add entries after we've counted them. Re-open asap to minimise
00600          * the race. JRA.
00601          */
00602         
00603         DEBUG(3, ("ads_keytab_create_default: Found %d entries in the keytab.\n", found));
00604         if (!found) {
00605                 goto done;
00606         }
00607         oldEntries = SMB_MALLOC_ARRAY(char *, found );
00608         if (!oldEntries) {
00609                 DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n"));
00610                 ret = -1;
00611                 goto done;
00612         }
00613         memset(oldEntries, '\0', found * sizeof(char *));
00614 
00615         ret = krb5_kt_start_seq_get(context, keytab, &cursor);
00616         if (ret != KRB5_KT_END && ret != ENOENT ) {
00617                 while (krb5_kt_next_entry(context, keytab, &kt_entry, &cursor) == 0) {
00618                         if (kt_entry.vno != kvno) {
00619                                 char *ktprinc = NULL;
00620                                 char *p;
00621 
00622                                 /* This returns a malloc'ed string in ktprinc. */
00623                                 ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc);
00624                                 if (ret) {
00625                                         DEBUG(1,("smb_krb5_unparse_name failed (%s)\n", error_message(ret)));
00626                                         goto done;
00627                                 }
00628                                 /*
00629                                  * From looking at the krb5 source they don't seem to take locale
00630                                  * or mb strings into account. Maybe this is because they assume utf8 ?
00631                                  * In this case we may need to convert from utf8 to mb charset here ? JRA.
00632                                  */
00633                                 p = strchr_m(ktprinc, '@');
00634                                 if (p) {
00635                                         *p = '\0';
00636                                 }
00637 
00638                                 p = strchr_m(ktprinc, '/');
00639                                 if (p) {
00640                                         *p = '\0';
00641                                 }
00642                                 for (i = 0; i < found; i++) {
00643                                         if (!oldEntries[i]) {
00644                                                 oldEntries[i] = ktprinc;
00645                                                 break;
00646                                         }
00647                                         if (!strcmp(oldEntries[i], ktprinc)) {
00648                                                 SAFE_FREE(ktprinc);
00649                                                 break;
00650                                         }
00651                                 }
00652                                 if (i == found) {
00653                                         SAFE_FREE(ktprinc);
00654                                 }
00655                         }
00656                         smb_krb5_kt_free_entry(context, &kt_entry);
00657                         ZERO_STRUCT(kt_entry);
00658                 }
00659                 ret = 0;
00660                 for (i = 0; oldEntries[i]; i++) {
00661                         ret |= ads_keytab_add_entry(ads, oldEntries[i]);
00662                         SAFE_FREE(oldEntries[i]);
00663                 }
00664                 krb5_kt_end_seq_get(context, keytab, &cursor);
00665         }
00666         ZERO_STRUCT(cursor);
00667 
00668 done:
00669 
00670         SAFE_FREE(oldEntries);
00671 
00672         {
00673                 krb5_keytab_entry zero_kt_entry;
00674                 ZERO_STRUCT(zero_kt_entry);
00675                 if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) {
00676                         smb_krb5_kt_free_entry(context, &kt_entry);
00677                 }
00678         }
00679         {
00680                 krb5_kt_cursor zero_csr;
00681                 ZERO_STRUCT(zero_csr);
00682                 if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
00683                         krb5_kt_end_seq_get(context, keytab, &cursor);  
00684                 }
00685         }
00686         if (keytab) {
00687                 krb5_kt_close(context, keytab);
00688         }
00689         if (context) {
00690                 krb5_free_context(context);
00691         }
00692         return ret;
00693 }
00694 #endif /* HAVE_KRB5 */

Sambaに対してSat Aug 29 21:23:01 2009に生成されました。  doxygen 1.4.7