libsmb/clikrb5.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    simple kerberos5 routines for active directory
00004    Copyright (C) Andrew Tridgell 2001
00005    Copyright (C) Luke Howard 2002-2003
00006    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
00007    Copyright (C) Guenther Deschner 2005
00008    
00009    This program is free software; you can redistribute it and/or modify
00010    it under the terms of the GNU General Public License as published by
00011    the Free Software Foundation; either version 2 of the License, or
00012    (at your option) any later version.
00013    
00014    This program is distributed in the hope that it will be useful,
00015    but WITHOUT ANY WARRANTY; without even the implied warranty of
00016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017    GNU General Public License for more details.
00018    
00019    You should have received a copy of the GNU General Public License
00020    along with this program; if not, write to the Free Software
00021    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #define KRB5_PRIVATE    1       /* this file uses PRIVATE interfaces! */
00025 #define KRB5_DEPRECATED 1       /* this file uses DEPRECATED interfaces! */
00026 
00027 #include "includes.h"
00028 
00029 #ifdef HAVE_KRB5
00030 
00031 #ifdef HAVE_KRB5_KEYBLOCK_KEYVALUE
00032 #define KRB5_KEY_TYPE(k)        ((k)->keytype)
00033 #define KRB5_KEY_LENGTH(k)      ((k)->keyvalue.length)
00034 #define KRB5_KEY_DATA(k)        ((k)->keyvalue.data)
00035 #else
00036 #define KRB5_KEY_TYPE(k)        ((k)->enctype)
00037 #define KRB5_KEY_LENGTH(k)      ((k)->length)
00038 #define KRB5_KEY_DATA(k)        ((k)->contents)
00039 #endif /* HAVE_KRB5_KEYBLOCK_KEYVALUE */
00040 
00041 /**************************************************************
00042  Wrappers around kerberos string functions that convert from
00043  utf8 -> unix charset and vica versa.
00044 **************************************************************/
00045 
00046 /**************************************************************
00047  krb5_parse_name that takes a UNIX charset.
00048 **************************************************************/
00049 
00050  krb5_error_code smb_krb5_parse_name(krb5_context context,
00051                                 const char *name, /* in unix charset */
00052                                 krb5_principal *principal)
00053 {
00054         krb5_error_code ret;
00055         char *utf8_name;
00056 
00057         if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) {
00058                 return ENOMEM;
00059         }
00060 
00061         ret = krb5_parse_name(context, utf8_name, principal);
00062         SAFE_FREE(utf8_name);
00063         return ret;
00064 }
00065 
00066 #ifdef HAVE_KRB5_PARSE_NAME_NOREALM
00067 /**************************************************************
00068  krb5_parse_name_norealm that takes a UNIX charset.
00069 **************************************************************/
00070 
00071 static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context,
00072                                 const char *name, /* in unix charset */
00073                                 krb5_principal *principal)
00074 {
00075         krb5_error_code ret;
00076         char *utf8_name;
00077 
00078         *principal = NULL;
00079         if (push_utf8_allocate(&utf8_name, name) == (size_t)-1) {
00080                 return ENOMEM;
00081         }
00082 
00083         ret = krb5_parse_name_norealm(context, utf8_name, principal);
00084         SAFE_FREE(utf8_name);
00085         return ret;
00086 }
00087 #endif
00088 
00089 /**************************************************************
00090  krb5_parse_name that returns a UNIX charset name. Must
00091  be freed with normal free() call.
00092 **************************************************************/
00093 
00094  krb5_error_code smb_krb5_unparse_name(krb5_context context,
00095                                         krb5_const_principal principal,
00096                                         char **unix_name)
00097 {
00098         krb5_error_code ret;
00099         char *utf8_name;
00100 
00101         *unix_name = NULL;
00102         ret = krb5_unparse_name(context, principal, &utf8_name);
00103         if (ret) {
00104                 return ret;
00105         }
00106 
00107         if (pull_utf8_allocate(unix_name, utf8_name)==-1) {
00108                 krb5_free_unparsed_name(context, utf8_name);
00109                 return ENOMEM;
00110         }
00111         krb5_free_unparsed_name(context, utf8_name);
00112         return 0;
00113 }
00114 
00115 #ifndef HAVE_KRB5_SET_REAL_TIME
00116 /*
00117  * This function is not in the Heimdal mainline.
00118  */
00119  krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds)
00120 {
00121         krb5_error_code ret;
00122         int32_t sec, usec;
00123 
00124         ret = krb5_us_timeofday(context, &sec, &usec);
00125         if (ret)
00126                 return ret;
00127 
00128         context->kdc_sec_offset = seconds - sec;
00129         context->kdc_usec_offset = microseconds - usec;
00130 
00131         return 0;
00132 }
00133 #endif
00134 
00135 #if !defined(HAVE_KRB5_SET_DEFAULT_TGS_KTYPES)
00136 
00137 #if defined(HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES)
00138 
00139 /* With MIT kerberos, we should use krb5_set_default_tgs_enctypes in preference
00140  * to krb5_set_default_tgs_ktypes. See
00141  *         http://lists.samba.org/archive/samba-technical/2006-July/048271.html
00142  *
00143  * If the MIT libraries are not exporting internal symbols, we will end up in
00144  * this branch, which is correct. Otherwise we will continue to use the
00145  * internal symbol
00146  */
00147  krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
00148 {
00149     return krb5_set_default_tgs_enctypes(ctx, enc);
00150 }
00151 
00152 #elif defined(HAVE_KRB5_SET_DEFAULT_IN_TKT_ETYPES)
00153 
00154 /* Heimdal */
00155  krb5_error_code krb5_set_default_tgs_ktypes(krb5_context ctx, const krb5_enctype *enc)
00156 {
00157         return krb5_set_default_in_tkt_etypes(ctx, enc);
00158 }
00159 
00160 #endif /* HAVE_KRB5_SET_DEFAULT_TGS_ENCTYPES */
00161 
00162 #endif /* HAVE_KRB5_SET_DEFAULT_TGS_KTYPES */
00163 
00164 #if defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS)
00165 /* HEIMDAL */
00166  void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
00167 {
00168         pkaddr->addr_type = KRB5_ADDRESS_INET;
00169         pkaddr->address.length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
00170         pkaddr->address.data = (char *)&(((struct sockaddr_in *)paddr)->sin_addr);
00171 }
00172 #elif defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS)
00173 /* MIT */
00174  void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr)
00175 {
00176         pkaddr->addrtype = ADDRTYPE_INET;
00177         pkaddr->length = sizeof(((struct sockaddr_in *)paddr)->sin_addr);
00178         pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
00179 }
00180 #else
00181 #error UNKNOWN_ADDRTYPE
00182 #endif
00183 
00184 #if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK)
00185  int create_kerberos_key_from_string_direct(krb5_context context,
00186                                         krb5_principal host_princ,
00187                                         krb5_data *password,
00188                                         krb5_keyblock *key,
00189                                         krb5_enctype enctype)
00190 {
00191         int ret;
00192         krb5_data salt;
00193         krb5_encrypt_block eblock;
00194 
00195         ret = krb5_principal2salt(context, host_princ, &salt);
00196         if (ret) {
00197                 DEBUG(1,("krb5_principal2salt failed (%s)\n", error_message(ret)));
00198                 return ret;
00199         }
00200         krb5_use_enctype(context, &eblock, enctype);
00201         ret = krb5_string_to_key(context, &eblock, key, password, &salt);
00202         SAFE_FREE(salt.data);
00203         return ret;
00204 }
00205 #elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
00206  int create_kerberos_key_from_string_direct(krb5_context context,
00207                                         krb5_principal host_princ,
00208                                         krb5_data *password,
00209                                         krb5_keyblock *key,
00210                                         krb5_enctype enctype)
00211 {
00212         int ret;
00213         krb5_salt salt;
00214 
00215         ret = krb5_get_pw_salt(context, host_princ, &salt);
00216         if (ret) {
00217                 DEBUG(1,("krb5_get_pw_salt failed (%s)\n", error_message(ret)));
00218                 return ret;
00219         }
00220         
00221         ret = krb5_string_to_key_salt(context, enctype, (const char *)password->data, salt, key);
00222         krb5_free_salt(context, salt);
00223         return ret;
00224 }
00225 #else
00226 #error UNKNOWN_CREATE_KEY_FUNCTIONS
00227 #endif
00228 
00229  int create_kerberos_key_from_string(krb5_context context,
00230                                         krb5_principal host_princ,
00231                                         krb5_data *password,
00232                                         krb5_keyblock *key,
00233                                         krb5_enctype enctype)
00234 {
00235         krb5_principal salt_princ = NULL;
00236         int ret;
00237         /*
00238          * Check if we've determined that the KDC is salting keys for this
00239          * principal/enctype in a non-obvious way.  If it is, try to match
00240          * its behavior.
00241          */
00242         salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
00243         ret = create_kerberos_key_from_string_direct(context, salt_princ ? salt_princ : host_princ, password, key, enctype);
00244         if (salt_princ) {
00245                 krb5_free_principal(context, salt_princ);
00246         }
00247         return ret;
00248 }
00249 
00250 #if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
00251  krb5_error_code get_kerberos_allowed_etypes(krb5_context context, 
00252                                             krb5_enctype **enctypes)
00253 {
00254         return krb5_get_permitted_enctypes(context, enctypes);
00255 }
00256 #elif defined(HAVE_KRB5_GET_DEFAULT_IN_TKT_ETYPES)
00257  krb5_error_code get_kerberos_allowed_etypes(krb5_context context, 
00258                                             krb5_enctype **enctypes)
00259 {
00260         return krb5_get_default_in_tkt_etypes(context, enctypes);
00261 }
00262 #else
00263 #error UNKNOWN_GET_ENCTYPES_FUNCTIONS
00264 #endif
00265 
00266 #if defined(HAVE_KRB5_AUTH_CON_SETKEY) && !defined(HAVE_KRB5_AUTH_CON_SETUSERUSERKEY)
00267  krb5_error_code krb5_auth_con_setuseruserkey(krb5_context context,
00268                                         krb5_auth_context auth_context,
00269                                         krb5_keyblock *keyblock)
00270 {
00271         return krb5_auth_con_setkey(context, auth_context, keyblock);
00272 }
00273 #endif
00274 
00275 BOOL unwrap_pac(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, DATA_BLOB *unwrapped_pac_data)
00276 {
00277         DATA_BLOB pac_contents;
00278         ASN1_DATA data;
00279         int data_type;
00280 
00281         if (!auth_data->length) {
00282                 return False;
00283         }
00284 
00285         asn1_load(&data, *auth_data);
00286         asn1_start_tag(&data, ASN1_SEQUENCE(0));
00287         asn1_start_tag(&data, ASN1_SEQUENCE(0));
00288         asn1_start_tag(&data, ASN1_CONTEXT(0));
00289         asn1_read_Integer(&data, &data_type);
00290         
00291         if (data_type != KRB5_AUTHDATA_WIN2K_PAC ) {
00292                 DEBUG(10,("authorization data is not a Windows PAC (type: %d)\n", data_type));
00293                 asn1_free(&data);
00294                 return False;
00295         }
00296         
00297         asn1_end_tag(&data);
00298         asn1_start_tag(&data, ASN1_CONTEXT(1));
00299         asn1_read_OctetString(&data, &pac_contents);
00300         asn1_end_tag(&data);
00301         asn1_end_tag(&data);
00302         asn1_end_tag(&data);
00303         asn1_free(&data);
00304 
00305         *unwrapped_pac_data = data_blob_talloc(mem_ctx, pac_contents.data, pac_contents.length);
00306 
00307         data_blob_free(&pac_contents);
00308 
00309         return True;
00310 }
00311 
00312  BOOL get_auth_data_from_tkt(TALLOC_CTX *mem_ctx, DATA_BLOB *auth_data, krb5_ticket *tkt)
00313 {
00314         DATA_BLOB auth_data_wrapped;
00315         BOOL got_auth_data_pac = False;
00316         int i;
00317         
00318 #if defined(HAVE_KRB5_TKT_ENC_PART2)
00319         if (tkt->enc_part2 && tkt->enc_part2->authorization_data && 
00320             tkt->enc_part2->authorization_data[0] && 
00321             tkt->enc_part2->authorization_data[0]->length)
00322         {
00323                 for (i = 0; tkt->enc_part2->authorization_data[i] != NULL; i++) {
00324                 
00325                         if (tkt->enc_part2->authorization_data[i]->ad_type != 
00326                             KRB5_AUTHDATA_IF_RELEVANT) {
00327                                 DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n", 
00328                                         tkt->enc_part2->authorization_data[i]->ad_type));
00329                                 continue;
00330                         }
00331 
00332                         auth_data_wrapped = data_blob(tkt->enc_part2->authorization_data[i]->contents,
00333                                                       tkt->enc_part2->authorization_data[i]->length);
00334 
00335                         /* check if it is a PAC */
00336                         got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
00337                         data_blob_free(&auth_data_wrapped);
00338                         
00339                         if (got_auth_data_pac) {
00340                                 return true;
00341                         }
00342                 }
00343 
00344                 return got_auth_data_pac;
00345         }
00346                 
00347 #else
00348         if (tkt->ticket.authorization_data && 
00349             tkt->ticket.authorization_data->len)
00350         {
00351                 for (i = 0; i < tkt->ticket.authorization_data->len; i++) {
00352                         
00353                         if (tkt->ticket.authorization_data->val[i].ad_type != 
00354                             KRB5_AUTHDATA_IF_RELEVANT) {
00355                                 DEBUG(10,("get_auth_data_from_tkt: ad_type is %d\n", 
00356                                         tkt->ticket.authorization_data->val[i].ad_type));
00357                                 continue;
00358                         }
00359 
00360                         auth_data_wrapped = data_blob(tkt->ticket.authorization_data->val[i].ad_data.data,
00361                                                       tkt->ticket.authorization_data->val[i].ad_data.length);
00362 
00363                         /* check if it is a PAC */
00364                         got_auth_data_pac = unwrap_pac(mem_ctx, &auth_data_wrapped, auth_data);
00365                         data_blob_free(&auth_data_wrapped);
00366 
00367                         if (got_auth_data_pac) {
00368                                 return true;
00369                         }
00370                 }
00371 
00372                 return got_auth_data_pac;
00373         }
00374 #endif
00375         return False;
00376 }
00377 
00378  krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt)
00379 {
00380 #if defined(HAVE_KRB5_TKT_ENC_PART2)
00381         return tkt->enc_part2->client;
00382 #else
00383         return tkt->client;
00384 #endif
00385 }
00386 
00387 #if !defined(HAVE_KRB5_LOCATE_KDC)
00388 
00389 /* krb5_locate_kdc is an internal MIT symbol. MIT are not yet willing to commit
00390  * to a public interface for this functionality, so we have to be able to live
00391  * without it if the MIT libraries are hiding their internal symbols.
00392  */
00393 
00394 #if defined(KRB5_KRBHST_INIT)
00395 /* Heimdal */
00396  krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters)
00397 {
00398         krb5_krbhst_handle hnd;
00399         krb5_krbhst_info *hinfo;
00400         krb5_error_code rc;
00401         int num_kdcs, i;
00402         struct sockaddr *sa;
00403         struct addrinfo *ai;
00404 
00405         *addr_pp = NULL;
00406         *naddrs = 0;
00407 
00408         rc = krb5_krbhst_init(ctx, realm->data, KRB5_KRBHST_KDC, &hnd);
00409         if (rc) {
00410                 DEBUG(0, ("smb_krb5_locate_kdc: krb5_krbhst_init failed (%s)\n", error_message(rc)));
00411                 return rc;
00412         }
00413 
00414         for ( num_kdcs = 0; (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); num_kdcs++)
00415                 ;
00416 
00417         krb5_krbhst_reset(ctx, hnd);
00418 
00419         if (!num_kdcs) {
00420                 DEBUG(0, ("smb_krb5_locate_kdc: zero kdcs found !\n"));
00421                 krb5_krbhst_free(ctx, hnd);
00422                 return -1;
00423         }
00424 
00425         sa = SMB_MALLOC_ARRAY( struct sockaddr, num_kdcs );
00426         if (!sa) {
00427                 DEBUG(0, ("smb_krb5_locate_kdc: malloc failed\n"));
00428                 krb5_krbhst_free(ctx, hnd);
00429                 naddrs = 0;
00430                 return -1;
00431         }
00432 
00433         memset(sa, '\0', sizeof(struct sockaddr) * num_kdcs );
00434 
00435         for (i = 0; i < num_kdcs && (rc = krb5_krbhst_next(ctx, hnd, &hinfo) == 0); i++) {
00436 
00437 #if defined(HAVE_KRB5_KRBHST_GET_ADDRINFO)
00438                 rc = krb5_krbhst_get_addrinfo(ctx, hinfo, &ai);
00439                 if (rc) {
00440                         DEBUG(0,("krb5_krbhst_get_addrinfo failed: %s\n", error_message(rc)));
00441                         continue;
00442                 }
00443 #endif
00444                 if (hinfo->ai && hinfo->ai->ai_family == AF_INET) 
00445                         memcpy(&sa[i], hinfo->ai->ai_addr, sizeof(struct sockaddr));
00446         }
00447 
00448         krb5_krbhst_free(ctx, hnd);
00449 
00450         *naddrs = num_kdcs;
00451         *addr_pp = sa;
00452         return 0;
00453 }
00454 
00455 #else /* ! defined(KRB5_KRBHST_INIT) */
00456 
00457  krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
00458                 struct sockaddr **addr_pp, int *naddrs, int get_masters)
00459 {
00460         DEBUG(0, ("unable to explicitly locate the KDC on this platform\n"));
00461         return KRB5_KDC_UNREACH;
00462 }
00463 
00464 #endif /* KRB5_KRBHST_INIT */
00465 
00466 #else /* ! HAVE_KRB5_LOCATE_KDC */
00467 
00468  krb5_error_code smb_krb5_locate_kdc(krb5_context ctx, const krb5_data *realm,
00469                 struct sockaddr **addr_pp, int *naddrs, int get_masters)
00470 {
00471         return krb5_locate_kdc(ctx, realm, addr_pp, naddrs, get_masters);
00472 }
00473 
00474 #endif /* HAVE_KRB5_LOCATE_KDC */
00475 
00476 #if !defined(HAVE_KRB5_FREE_UNPARSED_NAME)
00477  void krb5_free_unparsed_name(krb5_context context, char *val)
00478 {
00479         SAFE_FREE(val);
00480 }
00481 #endif
00482 
00483  void kerberos_free_data_contents(krb5_context context, krb5_data *pdata)
00484 {
00485 #if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
00486         if (pdata->data) {
00487                 krb5_free_data_contents(context, pdata);
00488         }
00489 #else
00490         SAFE_FREE(pdata->data);
00491 #endif
00492 }
00493 
00494  void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype)
00495 {
00496 #if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS)
00497         KRB5_KEY_TYPE((&pcreds->keyblock)) = enctype;
00498 #elif defined(HAVE_KRB5_SESSION_IN_CREDS)
00499         KRB5_KEY_TYPE((&pcreds->session)) = enctype;
00500 #else
00501 #error UNKNOWN_KEYBLOCK_MEMBER_IN_KRB5_CREDS_STRUCT
00502 #endif
00503 }
00504 
00505  BOOL kerberos_compatible_enctypes(krb5_context context,
00506                                   krb5_enctype enctype1,
00507                                   krb5_enctype enctype2)
00508 {
00509 #if defined(HAVE_KRB5_C_ENCTYPE_COMPARE)
00510         krb5_boolean similar = 0;
00511 
00512         krb5_c_enctype_compare(context, enctype1, enctype2, &similar);
00513         return similar ? True : False;
00514 #elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS)
00515         return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False;
00516 #endif
00517 }
00518 
00519 static BOOL ads_cleanup_expired_creds(krb5_context context, 
00520                                       krb5_ccache  ccache,
00521                                       krb5_creds  *credsp)
00522 {
00523         krb5_error_code retval;
00524         const char *cc_type = krb5_cc_get_type(context, ccache);
00525 
00526         DEBUG(3, ("ads_cleanup_expired_creds: Ticket in ccache[%s:%s] expiration %s\n",
00527                   cc_type, krb5_cc_get_name(context, ccache),
00528                   http_timestring(credsp->times.endtime)));
00529 
00530         /* we will probably need new tickets if the current ones
00531            will expire within 10 seconds.
00532         */
00533         if (credsp->times.endtime >= (time(NULL) + 10))
00534                 return False;
00535 
00536         /* heimdal won't remove creds from a file ccache, and 
00537            perhaps we shouldn't anyway, since internally we 
00538            use memory ccaches, and a FILE one probably means that
00539            we're using creds obtained outside of our exectuable
00540         */
00541         if (strequal(cc_type, "FILE")) {
00542                 DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a %s ccache\n", cc_type));
00543                 return False;
00544         }
00545 
00546         retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
00547         if (retval) {
00548                 DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
00549                           error_message(retval)));
00550                 /* If we have an error in this, we want to display it,
00551                    but continue as though we deleted it */
00552         }
00553         return True;
00554 }
00555 
00556 /*
00557   we can't use krb5_mk_req because w2k wants the service to be in a particular format
00558 */
00559 static krb5_error_code ads_krb5_mk_req(krb5_context context, 
00560                                        krb5_auth_context *auth_context, 
00561                                        const krb5_flags ap_req_options,
00562                                        const char *principal,
00563                                        krb5_ccache ccache, 
00564                                        krb5_data *outbuf, 
00565                                        time_t *expire_time)
00566 {
00567         krb5_error_code           retval;
00568         krb5_principal    server;
00569         krb5_creds              * credsp;
00570         krb5_creds                creds;
00571         krb5_data in_data;
00572         BOOL creds_ready = False;
00573         int i = 0, maxtries = 3;
00574         
00575         retval = smb_krb5_parse_name(context, principal, &server);
00576         if (retval) {
00577                 DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
00578                 return retval;
00579         }
00580         
00581         /* obtain ticket & session key */
00582         ZERO_STRUCT(creds);
00583         if ((retval = krb5_copy_principal(context, server, &creds.server))) {
00584                 DEBUG(1,("ads_krb5_mk_req: krb5_copy_principal failed (%s)\n", 
00585                          error_message(retval)));
00586                 goto cleanup_princ;
00587         }
00588         
00589         if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
00590                 /* This can commonly fail on smbd startup with no ticket in the cache.
00591                  * Report at higher level than 1. */
00592                 DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n", 
00593                          error_message(retval)));
00594                 goto cleanup_creds;
00595         }
00596 
00597         while (!creds_ready && (i < maxtries)) {
00598 
00599                 if ((retval = krb5_get_credentials(context, 0, ccache, 
00600                                                    &creds, &credsp))) {
00601                         DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
00602                                  principal, error_message(retval)));
00603                         goto cleanup_creds;
00604                 }
00605 
00606                 /* cope with ticket being in the future due to clock skew */
00607                 if ((unsigned)credsp->times.starttime > time(NULL)) {
00608                         time_t t = time(NULL);
00609                         int time_offset =(int)((unsigned)credsp->times.starttime-t);
00610                         DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
00611                         krb5_set_real_time(context, t + time_offset + 1, 0);
00612                 }
00613 
00614                 if (!ads_cleanup_expired_creds(context, ccache, credsp)) {
00615                         creds_ready = True;
00616                 }
00617 
00618                 i++;
00619         }
00620 
00621         DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s:%s) is valid until: (%s - %u)\n",
00622                   principal, krb5_cc_get_type(context, ccache), krb5_cc_get_name(context, ccache),
00623                   http_timestring((unsigned)credsp->times.endtime), 
00624                   (unsigned)credsp->times.endtime));
00625 
00626         if (expire_time) {
00627                 *expire_time = (time_t)credsp->times.endtime;
00628         }
00629 
00630         in_data.length = 0;
00631         retval = krb5_mk_req_extended(context, auth_context, ap_req_options, 
00632                                       &in_data, credsp, outbuf);
00633         if (retval) {
00634                 DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n", 
00635                          error_message(retval)));
00636         }
00637         
00638         krb5_free_creds(context, credsp);
00639 
00640 cleanup_creds:
00641         krb5_free_cred_contents(context, &creds);
00642 
00643 cleanup_princ:
00644         krb5_free_principal(context, server);
00645 
00646         return retval;
00647 }
00648 
00649 /*
00650   get a kerberos5 ticket for the given service 
00651 */
00652 int cli_krb5_get_ticket(const char *principal, time_t time_offset, 
00653                         DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, 
00654                         uint32 extra_ap_opts, const char *ccname, 
00655                         time_t *tgs_expire)
00656 
00657 {
00658         krb5_error_code retval;
00659         krb5_data packet;
00660         krb5_context context = NULL;
00661         krb5_ccache ccdef = NULL;
00662         krb5_auth_context auth_context = NULL;
00663         krb5_enctype enc_types[] = {
00664 #ifdef ENCTYPE_ARCFOUR_HMAC
00665                 ENCTYPE_ARCFOUR_HMAC,
00666 #endif 
00667                 ENCTYPE_DES_CBC_MD5, 
00668                 ENCTYPE_DES_CBC_CRC, 
00669                 ENCTYPE_NULL};
00670 
00671         initialize_krb5_error_table();
00672         retval = krb5_init_context(&context);
00673         if (retval) {
00674                 DEBUG(1,("cli_krb5_get_ticket: krb5_init_context failed (%s)\n", 
00675                          error_message(retval)));
00676                 goto failed;
00677         }
00678 
00679         if (time_offset != 0) {
00680                 krb5_set_real_time(context, time(NULL) + time_offset, 0);
00681         }
00682 
00683         if ((retval = krb5_cc_resolve(context, ccname ?
00684                         ccname : krb5_cc_default_name(context), &ccdef))) {
00685                 DEBUG(1,("cli_krb5_get_ticket: krb5_cc_default failed (%s)\n",
00686                          error_message(retval)));
00687                 goto failed;
00688         }
00689 
00690         if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
00691                 DEBUG(1,("cli_krb5_get_ticket: krb5_set_default_tgs_ktypes failed (%s)\n",
00692                          error_message(retval)));
00693                 goto failed;
00694         }
00695 
00696         if ((retval = ads_krb5_mk_req(context, 
00697                                         &auth_context, 
00698                                         AP_OPTS_USE_SUBKEY | (krb5_flags)extra_ap_opts,
00699                                         principal,
00700                                         ccdef, &packet,
00701                                         tgs_expire))) {
00702                 goto failed;
00703         }
00704 
00705         get_krb5_smb_session_key(context, auth_context, session_key_krb5, False);
00706 
00707         *ticket = data_blob(packet.data, packet.length);
00708 
00709         kerberos_free_data_contents(context, &packet); 
00710 
00711 failed:
00712 
00713         if ( context ) {
00714                 if (ccdef)
00715                         krb5_cc_close(context, ccdef);
00716                 if (auth_context)
00717                         krb5_auth_con_free(context, auth_context);
00718                 krb5_free_context(context);
00719         }
00720                 
00721         return retval;
00722 }
00723 
00724  BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote)
00725  {
00726         krb5_keyblock *skey;
00727         krb5_error_code err;
00728         BOOL ret = False;
00729 
00730         if (remote)
00731                 err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
00732         else
00733                 err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
00734         if (err == 0 && skey != NULL) {
00735                 DEBUG(10, ("Got KRB5 session key of length %d\n",  (int)KRB5_KEY_LENGTH(skey)));
00736                 *session_key = data_blob(KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
00737                 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
00738 
00739                 ret = True;
00740 
00741                 krb5_free_keyblock(context, skey);
00742         } else {
00743                 DEBUG(10, ("KRB5 error getting session key %d\n", err));
00744         }
00745 
00746         return ret;
00747  }
00748 
00749 
00750 #if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING) && !defined(HAVE_KRB5_PRINC_COMPONENT)
00751  const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i );
00752 
00753  const krb5_data *krb5_princ_component(krb5_context context, krb5_principal principal, int i )
00754 {
00755         static krb5_data kdata;
00756 
00757         kdata.data = (char *)krb5_principal_get_comp_string(context, principal, i);
00758         kdata.length = strlen((const char *)kdata.data);
00759         return &kdata;
00760 }
00761 #endif
00762 
00763  krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry)
00764 {
00765 #if defined(HAVE_KRB5_KT_FREE_ENTRY)
00766         return krb5_kt_free_entry(context, kt_entry);
00767 #elif defined(HAVE_KRB5_FREE_KEYTAB_ENTRY_CONTENTS)
00768         return krb5_free_keytab_entry_contents(context, kt_entry);
00769 #else
00770 #error UNKNOWN_KT_FREE_FUNCTION
00771 #endif
00772 }
00773 
00774  void smb_krb5_checksum_from_pac_sig(krb5_checksum *cksum, 
00775                                     PAC_SIGNATURE_DATA *sig)
00776 {
00777 #ifdef HAVE_CHECKSUM_IN_KRB5_CHECKSUM
00778         cksum->cksumtype        = (krb5_cksumtype)sig->type;
00779         cksum->checksum.length  = sig->signature.buf_len;
00780         cksum->checksum.data    = sig->signature.buffer;
00781 #else
00782         cksum->checksum_type    = (krb5_cksumtype)sig->type;
00783         cksum->length           = sig->signature.buf_len;
00784         cksum->contents         = sig->signature.buffer;
00785 #endif
00786 }
00787 
00788  krb5_error_code smb_krb5_verify_checksum(krb5_context context,
00789                                          krb5_keyblock *keyblock,
00790                                          krb5_keyusage usage,
00791                                          krb5_checksum *cksum,
00792                                          uint8 *data,
00793                                          size_t length)
00794 {
00795         krb5_error_code ret;
00796 
00797         /* verify the checksum */
00798 
00799         /* welcome to the wonderful world of samba's kerberos abstraction layer:
00800          * 
00801          * function                     heimdal 0.6.1rc3        heimdal 0.7     MIT krb 1.4.2
00802          * -----------------------------------------------------------------------------
00803          * krb5_c_verify_checksum       -                       works           works
00804          * krb5_verify_checksum         works (6 args)          works (6 args)  broken (7 args) 
00805          */
00806 
00807 #if defined(HAVE_KRB5_C_VERIFY_CHECKSUM)
00808         {
00809                 krb5_boolean checksum_valid = False;
00810                 krb5_data input;
00811 
00812                 input.data = (char *)data;
00813                 input.length = length;
00814 
00815                 ret = krb5_c_verify_checksum(context, 
00816                                              keyblock, 
00817                                              usage,
00818                                              &input, 
00819                                              cksum,
00820                                              &checksum_valid);
00821                 if (ret) {
00822                         DEBUG(3,("smb_krb5_verify_checksum: krb5_c_verify_checksum() failed: %s\n", 
00823                                 error_message(ret)));
00824                         return ret;
00825                 }
00826 
00827                 if (!checksum_valid)
00828                         ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
00829         }
00830 
00831 #elif KRB5_VERIFY_CHECKSUM_ARGS == 6 && defined(HAVE_KRB5_CRYPTO_INIT) && defined(HAVE_KRB5_CRYPTO) && defined(HAVE_KRB5_CRYPTO_DESTROY)
00832 
00833         /* Warning: MIT's krb5_verify_checksum cannot be used as it will use a key
00834          * without enctype and it ignores any key_usage types - Guenther */
00835 
00836         {
00837 
00838                 krb5_crypto crypto;
00839                 ret = krb5_crypto_init(context,
00840                                        keyblock,
00841                                        0,
00842                                        &crypto);
00843                 if (ret) {
00844                         DEBUG(0,("smb_krb5_verify_checksum: krb5_crypto_init() failed: %s\n", 
00845                                 error_message(ret)));
00846                         return ret;
00847                 }
00848 
00849                 ret = krb5_verify_checksum(context,
00850                                            crypto,
00851                                            usage,
00852                                            data,
00853                                            length,
00854                                            cksum);
00855 
00856                 krb5_crypto_destroy(context, crypto);
00857         }
00858 
00859 #else
00860 #error UNKNOWN_KRB5_VERIFY_CHECKSUM_FUNCTION
00861 #endif
00862 
00863         return ret;
00864 }
00865 
00866  time_t get_authtime_from_tkt(krb5_ticket *tkt)
00867 {
00868 #if defined(HAVE_KRB5_TKT_ENC_PART2)
00869         return tkt->enc_part2->times.authtime;
00870 #else
00871         return tkt->ticket.authtime;
00872 #endif
00873 }
00874 
00875 #ifdef HAVE_KRB5_DECODE_AP_REQ  /* Heimdal */
00876 static int get_kvno_from_ap_req(krb5_ap_req *ap_req)
00877 {
00878 #ifdef HAVE_TICKET_POINTER_IN_KRB5_AP_REQ /* MIT */
00879         if (ap_req->ticket->enc_part.kvno)
00880                 return ap_req->ticket->enc_part.kvno;
00881 #else /* Heimdal */
00882         if (ap_req->ticket.enc_part.kvno) 
00883                 return *ap_req->ticket.enc_part.kvno;
00884 #endif
00885         return 0;
00886 }
00887 
00888 static krb5_enctype get_enctype_from_ap_req(krb5_ap_req *ap_req)
00889 {
00890 #ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */
00891         return ap_req->ticket.enc_part.etype;
00892 #else /* MIT */
00893         return ap_req->ticket->enc_part.enctype;
00894 #endif
00895 }
00896 #endif  /* HAVE_KRB5_DECODE_AP_REQ */
00897 
00898 static krb5_error_code
00899 get_key_from_keytab(krb5_context context,
00900                     krb5_const_principal server,
00901                     krb5_enctype enctype,
00902                     krb5_kvno kvno,
00903                     krb5_keyblock **out_key)
00904 {
00905         krb5_keytab_entry entry;
00906         krb5_error_code ret;
00907         krb5_keytab keytab;
00908         char *name = NULL;
00909 
00910         /* We have to open a new keytab handle here, as MIT does
00911            an implicit open/getnext/close on krb5_kt_get_entry. We
00912            may be in the middle of a keytab enumeration when this is
00913            called. JRA. */
00914 
00915         ret = krb5_kt_default(context, &keytab);
00916         if (ret) {
00917                 DEBUG(0,("get_key_from_keytab: failed to open keytab: %s\n", error_message(ret)));
00918                 return ret;
00919         }
00920 
00921         if ( DEBUGLEVEL >= 10 ) {
00922                 if (smb_krb5_unparse_name(context, server, &name) == 0) {
00923                         DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n", 
00924                                 kvno, enctype, name));
00925                         SAFE_FREE(name);
00926                 }
00927         }
00928 
00929         ret = krb5_kt_get_entry(context,
00930                                 keytab,
00931                                 server,
00932                                 kvno,
00933                                 enctype,
00934                                 &entry);
00935 
00936         if (ret) {
00937                 DEBUG(0,("get_key_from_keytab: failed to retrieve key: %s\n", error_message(ret)));
00938                 goto out;
00939         }
00940 
00941 #ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK /* Heimdal */
00942         ret = krb5_copy_keyblock(context, &entry.keyblock, out_key);
00943 #elif defined(HAVE_KRB5_KEYTAB_ENTRY_KEY) /* MIT */
00944         ret = krb5_copy_keyblock(context, &entry.key, out_key);
00945 #else
00946 #error UNKNOWN_KRB5_KEYTAB_ENTRY_FORMAT
00947 #endif
00948 
00949         if (ret) {
00950                 DEBUG(0,("get_key_from_keytab: failed to copy key: %s\n", error_message(ret)));
00951                 goto out;
00952         }
00953                 
00954         smb_krb5_kt_free_entry(context, &entry);
00955         
00956 out:    
00957         krb5_kt_close(context, keytab);
00958         return ret;
00959 }
00960 
00961 /* Prototypes */
00962 
00963  krb5_error_code smb_krb5_get_keyinfo_from_ap_req(krb5_context context, 
00964                                                  const krb5_data *inbuf, 
00965                                                  krb5_kvno *kvno, 
00966                                                  krb5_enctype *enctype)
00967 {
00968 #ifdef HAVE_KRB5_DECODE_AP_REQ /* Heimdal */
00969         {
00970                 krb5_error_code ret;
00971                 krb5_ap_req ap_req;
00972                 
00973                 ret = krb5_decode_ap_req(context, inbuf, &ap_req);
00974                 if (ret)
00975                         return ret;
00976 
00977                 *kvno = get_kvno_from_ap_req(&ap_req);
00978                 *enctype = get_enctype_from_ap_req(&ap_req);
00979 
00980                 free_AP_REQ(&ap_req);
00981                 return 0;
00982         }
00983 #endif
00984 
00985         /* Possibly not an appropriate error code. */
00986         return KRB5KDC_ERR_BADOPTION;
00987 }
00988 
00989  krb5_error_code krb5_rd_req_return_keyblock_from_keytab(krb5_context context,
00990                                                         krb5_auth_context *auth_context,
00991                                                         const krb5_data *inbuf,
00992                                                         krb5_const_principal server,
00993                                                         krb5_keytab keytab,
00994                                                         krb5_flags *ap_req_options,
00995                                                         krb5_ticket **ticket, 
00996                                                         krb5_keyblock **keyblock)
00997 {
00998         krb5_error_code ret;
00999         krb5_kvno kvno;
01000         krb5_enctype enctype;
01001         krb5_keyblock *local_keyblock;
01002 
01003         ret = krb5_rd_req(context, 
01004                           auth_context, 
01005                           inbuf, 
01006                           server, 
01007                           keytab, 
01008                           ap_req_options, 
01009                           ticket);
01010         if (ret) {
01011                 return ret;
01012         }
01013         
01014 #ifdef KRB5_TICKET_HAS_KEYINFO
01015         enctype = (*ticket)->enc_part.enctype;
01016         kvno = (*ticket)->enc_part.kvno;
01017 #else
01018         ret = smb_krb5_get_keyinfo_from_ap_req(context, inbuf, &kvno, &enctype);
01019         if (ret) {
01020                 return ret;
01021         }
01022 #endif
01023 
01024         ret = get_key_from_keytab(context, 
01025                                   server,
01026                                   enctype,
01027                                   kvno,
01028                                   &local_keyblock);
01029         if (ret) {
01030                 DEBUG(0,("krb5_rd_req_return_keyblock_from_keytab: failed to call get_key_from_keytab\n"));
01031                 goto out;
01032         }
01033 
01034 out:
01035         if (ret && local_keyblock != NULL) {
01036                 krb5_free_keyblock(context, local_keyblock);
01037         } else {
01038                 *keyblock = local_keyblock;
01039         }
01040 
01041         return ret;
01042 }
01043 
01044  krb5_error_code smb_krb5_parse_name_norealm(krb5_context context, 
01045                                             const char *name, 
01046                                             krb5_principal *principal)
01047 {
01048 #ifdef HAVE_KRB5_PARSE_NAME_NOREALM
01049         return smb_krb5_parse_name_norealm_conv(context, name, principal);
01050 #endif
01051 
01052         /* we are cheating here because parse_name will in fact set the realm.
01053          * We don't care as the only caller of smb_krb5_parse_name_norealm
01054          * ignores the realm anyway when calling
01055          * smb_krb5_principal_compare_any_realm later - Guenther */
01056 
01057         return smb_krb5_parse_name(context, name, principal);
01058 }
01059 
01060  BOOL smb_krb5_principal_compare_any_realm(krb5_context context, 
01061                                           krb5_const_principal princ1, 
01062                                           krb5_const_principal princ2)
01063 {
01064 #ifdef HAVE_KRB5_PRINCIPAL_COMPARE_ANY_REALM
01065 
01066         return krb5_principal_compare_any_realm(context, princ1, princ2);
01067 
01068 /* krb5_princ_size is a macro in MIT */
01069 #elif defined(HAVE_KRB5_PRINC_SIZE) || defined(krb5_princ_size)
01070 
01071         int i, len1, len2;
01072         const krb5_data *p1, *p2;
01073 
01074         len1 = krb5_princ_size(context, princ1);
01075         len2 = krb5_princ_size(context, princ2);
01076 
01077         if (len1 != len2)
01078                 return False;
01079 
01080         for (i = 0; i < len1; i++) {
01081 
01082                 p1 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ1), i);
01083                 p2 = krb5_princ_component(context, CONST_DISCARD(krb5_principal, princ2), i);
01084 
01085                 if (p1->length != p2->length || memcmp(p1->data, p2->data, p1->length))
01086                         return False;
01087         }
01088 
01089         return True;
01090 #else
01091 #error NO_SUITABLE_PRINCIPAL_COMPARE_FUNCTION
01092 #endif
01093 }
01094 
01095  krb5_error_code smb_krb5_renew_ticket(const char *ccache_string,       /* FILE:/tmp/krb5cc_0 */
01096                                        const char *client_string,       /* gd@BER.SUSE.DE */
01097                                        const char *service_string,      /* krbtgt/BER.SUSE.DE@BER.SUSE.DE */
01098                                        time_t *expire_time)
01099 {
01100         krb5_error_code ret;
01101         krb5_context context = NULL;
01102         krb5_ccache ccache = NULL;
01103         krb5_principal client = NULL;
01104 
01105         initialize_krb5_error_table();
01106         ret = krb5_init_context(&context);
01107         if (ret) {
01108                 goto done;
01109         }
01110 
01111         if (!ccache_string) {
01112                 ccache_string = krb5_cc_default_name(context);
01113         }
01114 
01115         DEBUG(10,("smb_krb5_renew_ticket: using %s as ccache\n", ccache_string));
01116 
01117         /* FIXME: we should not fall back to defaults */
01118         ret = krb5_cc_resolve(context, CONST_DISCARD(char *, ccache_string), &ccache);
01119         if (ret) {
01120                 goto done;
01121         }
01122 
01123 #ifdef HAVE_KRB5_GET_RENEWED_CREDS      /* MIT */
01124         {
01125                 krb5_creds creds;
01126         
01127                 if (client_string) {
01128                         ret = smb_krb5_parse_name(context, client_string, &client);
01129                         if (ret) {
01130                                 goto done;
01131                         }
01132                 } else {
01133                         ret = krb5_cc_get_principal(context, ccache, &client);
01134                         if (ret) {
01135                                 goto done;
01136                         }
01137                 }
01138         
01139                 ret = krb5_get_renewed_creds(context, &creds, client, ccache, CONST_DISCARD(char *, service_string));
01140                 if (ret) {
01141                         DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
01142                         goto done;
01143                 }
01144 
01145                 /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
01146                 ret = krb5_cc_initialize(context, ccache, client);
01147                 if (ret) {
01148                         goto done;
01149                 }
01150         
01151                 ret = krb5_cc_store_cred(context, ccache, &creds);
01152 
01153                 if (expire_time) {
01154                         *expire_time = (time_t) creds.times.endtime;
01155                 }
01156 
01157                 krb5_free_cred_contents(context, &creds);
01158         }
01159 #elif defined(HAVE_KRB5_GET_KDC_CRED)   /* Heimdal */
01160         {
01161                 krb5_kdc_flags flags;
01162                 krb5_creds creds_in;
01163                 krb5_realm *client_realm;
01164                 krb5_creds *creds;
01165 
01166                 memset(&creds_in, 0, sizeof(creds_in));
01167 
01168                 if (client_string) {
01169                         ret = smb_krb5_parse_name(context, client_string, &creds_in.client);
01170                         if (ret) {
01171                                 goto done;
01172                         }
01173                 } else {
01174                         ret = krb5_cc_get_principal(context, ccache, &creds_in.client);
01175                         if (ret) {
01176                                 goto done;
01177                         }
01178                 }
01179 
01180                 if (service_string) {
01181                         ret = smb_krb5_parse_name(context, service_string, &creds_in.server);
01182                         if (ret) { 
01183                                 goto done;
01184                         }
01185                 } else {
01186                         /* build tgt service by default */
01187                         client_realm = krb5_princ_realm(context, creds_in.client);
01188                         if (!client_realm) {
01189                                 ret = ENOMEM;
01190                                 goto done;
01191                         }
01192                         ret = krb5_make_principal(context, &creds_in.server, *client_realm, KRB5_TGS_NAME, *client_realm, NULL);
01193                         if (ret) {
01194                                 goto done;
01195                         }
01196                 }
01197 
01198                 flags.i = 0;
01199                 flags.b.renewable = flags.b.renew = True;
01200 
01201                 ret = krb5_get_kdc_cred(context, ccache, flags, NULL, NULL, &creds_in, &creds);
01202                 if (ret) {
01203                         DEBUG(10,("smb_krb5_renew_ticket: krb5_get_kdc_cred failed: %s\n", error_message(ret)));
01204                         goto done;
01205                 }
01206                 
01207                 /* hm, doesn't that create a new one if the old one wasn't there? - Guenther */
01208                 ret = krb5_cc_initialize(context, ccache, creds_in.client);
01209                 if (ret) {
01210                         goto done;
01211                 }
01212         
01213                 ret = krb5_cc_store_cred(context, ccache, creds);
01214 
01215                 if (expire_time) {
01216                         *expire_time = (time_t) creds->times.endtime;
01217                 }
01218                                                 
01219                 krb5_free_cred_contents(context, &creds_in);
01220                 krb5_free_creds(context, creds);
01221         }
01222 #else
01223 #error No suitable krb5 ticket renew function available
01224 #endif
01225 
01226 
01227 done:
01228         if (client) {
01229                 krb5_free_principal(context, client);
01230         }
01231         if (context) {
01232                 krb5_free_context(context);
01233         }
01234         if (ccache) {
01235                 krb5_cc_close(context, ccache);
01236         }
01237 
01238         return ret;
01239     
01240 }
01241 
01242  krb5_error_code smb_krb5_free_addresses(krb5_context context, smb_krb5_addresses *addr)
01243 {
01244         krb5_error_code ret = 0;
01245         if (addr == NULL) {
01246                 return ret;
01247         }
01248 #if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
01249         krb5_free_addresses(context, addr->addrs);
01250 #elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
01251         ret = krb5_free_addresses(context, addr->addrs);
01252         SAFE_FREE(addr->addrs);
01253 #endif
01254         SAFE_FREE(addr);
01255         addr = NULL;
01256         return ret;
01257 }
01258 
01259  krb5_error_code smb_krb5_gen_netbios_krb5_address(smb_krb5_addresses **kerb_addr)
01260 {
01261         krb5_error_code ret = 0;
01262         nstring buf;
01263 #if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
01264         krb5_address **addrs = NULL;
01265 #elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
01266         krb5_addresses *addrs = NULL;
01267 #endif
01268 
01269         *kerb_addr = (smb_krb5_addresses *)SMB_MALLOC(sizeof(smb_krb5_addresses));
01270         if (*kerb_addr == NULL) {
01271                 return ENOMEM;
01272         }
01273 
01274         put_name(buf, global_myname(), ' ', 0x20);
01275 
01276 #if defined(HAVE_MAGIC_IN_KRB5_ADDRESS) && defined(HAVE_ADDRTYPE_IN_KRB5_ADDRESS) /* MIT */
01277         {
01278                 int num_addr = 2;
01279 
01280                 addrs = (krb5_address **)SMB_MALLOC(sizeof(krb5_address *) * num_addr);
01281                 if (addrs == NULL) {
01282                         SAFE_FREE(kerb_addr);
01283                         return ENOMEM;
01284                 }
01285 
01286                 memset(addrs, 0, sizeof(krb5_address *) * num_addr);
01287 
01288                 addrs[0] = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
01289                 if (addrs[0] == NULL) {
01290                         SAFE_FREE(addrs);
01291                         SAFE_FREE(kerb_addr);
01292                         return ENOMEM;
01293                 }
01294 
01295                 addrs[0]->magic = KV5M_ADDRESS;
01296                 addrs[0]->addrtype = KRB5_ADDR_NETBIOS;
01297                 addrs[0]->length = MAX_NETBIOSNAME_LEN;
01298                 addrs[0]->contents = (unsigned char *)SMB_MALLOC(addrs[0]->length);
01299                 if (addrs[0]->contents == NULL) {
01300                         SAFE_FREE(addrs[0]);
01301                         SAFE_FREE(addrs);
01302                         SAFE_FREE(kerb_addr);
01303                         return ENOMEM;
01304                 }
01305 
01306                 memcpy(addrs[0]->contents, buf, addrs[0]->length);
01307 
01308                 addrs[1] = NULL;
01309         }
01310 #elif defined(HAVE_ADDR_TYPE_IN_KRB5_ADDRESS) /* Heimdal */
01311         {
01312                 addrs = (krb5_addresses *)SMB_MALLOC(sizeof(krb5_addresses));
01313                 if (addrs == NULL) {
01314                         SAFE_FREE(kerb_addr);
01315                         return ENOMEM;
01316                 }
01317 
01318                 memset(addrs, 0, sizeof(krb5_addresses));
01319 
01320                 addrs->len = 1;
01321                 addrs->val = (krb5_address *)SMB_MALLOC(sizeof(krb5_address));
01322                 if (addrs->val == NULL) {
01323                         SAFE_FREE(addrs);
01324                         SAFE_FREE(kerb_addr);
01325                         return ENOMEM;
01326                 }
01327 
01328                 addrs->val[0].addr_type = KRB5_ADDR_NETBIOS;
01329                 addrs->val[0].address.length = MAX_NETBIOSNAME_LEN;
01330                 addrs->val[0].address.data = (unsigned char *)SMB_MALLOC(addrs->val[0].address.length);
01331                 if (addrs->val[0].address.data == NULL) {
01332                         SAFE_FREE(addrs->val);
01333                         SAFE_FREE(addrs);
01334                         SAFE_FREE(kerb_addr);
01335                         return ENOMEM;
01336                 }
01337 
01338                 memcpy(addrs->val[0].address.data, buf, addrs->val[0].address.length);
01339         }
01340 #else
01341 #error UNKNOWN_KRB5_ADDRESS_FORMAT
01342 #endif
01343         (*kerb_addr)->addrs = addrs;
01344 
01345         return ret;
01346 }
01347 
01348  void smb_krb5_free_error(krb5_context context, krb5_error *krberror)
01349 {
01350 #ifdef HAVE_KRB5_FREE_ERROR_CONTENTS /* Heimdal */
01351         krb5_free_error_contents(context, krberror);
01352 #else /* MIT */
01353         krb5_free_error(context, krberror);
01354 #endif
01355 }
01356 
01357  krb5_error_code handle_krberror_packet(krb5_context context,
01358                                         krb5_data *packet)
01359 {
01360         krb5_error_code ret;
01361         BOOL got_error_code = False;
01362 
01363         DEBUG(10,("handle_krberror_packet: got error packet\n"));
01364         
01365 #ifdef HAVE_E_DATA_POINTER_IN_KRB5_ERROR /* Heimdal */
01366         {
01367                 krb5_error krberror;
01368 
01369                 if ((ret = krb5_rd_error(context, packet, &krberror))) {
01370                         DEBUG(10,("handle_krberror_packet: krb5_rd_error failed with: %s\n", 
01371                                 error_message(ret)));
01372                         return ret;
01373                 }
01374 
01375                 if (krberror.e_data == NULL || krberror.e_data->data == NULL) {
01376                         ret = (krb5_error_code) krberror.error_code;
01377                         got_error_code = True;
01378                 }
01379 
01380                 smb_krb5_free_error(context, &krberror);
01381         }
01382 #else /* MIT */
01383         {
01384                 krb5_error *krberror;
01385 
01386                 if ((ret = krb5_rd_error(context, packet, &krberror))) {
01387                         DEBUG(10,("handle_krberror_packet: krb5_rd_error failed with: %s\n", 
01388                                 error_message(ret)));
01389                         return ret;
01390                 }
01391 
01392                 if (krberror->e_data.data == NULL) {
01393                         ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
01394                         got_error_code = True;
01395                 }
01396                 smb_krb5_free_error(context, krberror);
01397         }
01398 #endif
01399         if (got_error_code) {
01400                 DEBUG(5,("handle_krberror_packet: got KERBERR from kpasswd: %s (%d)\n", 
01401                         error_message(ret), ret));
01402         }
01403         return ret;
01404 }
01405 
01406  krb5_error_code smb_krb5_get_init_creds_opt_alloc(krb5_context context,
01407                                             krb5_get_init_creds_opt **opt)
01408 {
01409 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC
01410         /* Heimdal or modern MIT version */
01411         return krb5_get_init_creds_opt_alloc(context, opt);
01412 #else
01413         /* Historical MIT version */
01414         krb5_get_init_creds_opt *my_opt;
01415 
01416         *opt = NULL;
01417 
01418         if ((my_opt = SMB_MALLOC(sizeof(krb5_get_init_creds_opt))) == NULL) {
01419                 return ENOMEM;
01420         }
01421 
01422         krb5_get_init_creds_opt_init(my_opt);
01423 
01424         *opt =  my_opt;
01425         return 0;
01426 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC  */
01427 }
01428 
01429  void smb_krb5_get_init_creds_opt_free(krb5_context context,
01430                                 krb5_get_init_creds_opt *opt)
01431 {
01432 #ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_FREE
01433 
01434 #ifdef KRB5_CREDS_OPT_FREE_REQUIRES_CONTEXT
01435         /* Modern MIT version */
01436         krb5_get_init_creds_opt_free(context, opt);
01437 #else
01438         /* Heimdal version */
01439         krb5_get_init_creds_opt_free(opt);
01440 #endif
01441 
01442 #else /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
01443         /* Historical MIT version */
01444         SAFE_FREE(opt);
01445         opt = NULL;
01446 #endif /* HAVE_KRB5_GET_INIT_CREDS_OPT_FREE */
01447 }
01448 
01449  krb5_error_code smb_krb5_mk_error(krb5_context context,
01450                                 krb5_error_code error_code,
01451                                 const krb5_principal server,
01452                                 krb5_data *reply)
01453 {
01454 #ifdef HAVE_SHORT_KRB5_MK_ERROR_INTERFACE /* MIT */
01455         /*
01456          * The MIT interface is *terrible*.
01457          * We have to construct this ourselves...
01458          */
01459         krb5_error e;
01460 
01461         memset(&e, 0, sizeof(e));
01462         krb5_us_timeofday(context, &e.stime, &e.susec);
01463         e.server = server;
01464 #if defined(krb5_err_base)
01465         e.error = error_code - krb5_err_base;
01466 #elif defined(ERROR_TABLE_BASE_krb5)
01467         e.error = error_code - ERROR_TABLE_BASE_krb5;
01468 #else
01469         e.error = error_code; /* Almost certainly wrong, but what can we do... ? */
01470 #endif
01471 
01472         return krb5_mk_error(context, &e, reply);
01473 #else /* Heimdal. */
01474         return krb5_mk_error(context,
01475                                 error_code,
01476                                 NULL,
01477                                 NULL, /* e_data */
01478                                 NULL,
01479                                 server,
01480                                 NULL,
01481                                 NULL,
01482                                 reply);
01483 #endif
01484 }
01485 
01486 #else /* HAVE_KRB5 */
01487  /* this saves a few linking headaches */
01488  int cli_krb5_get_ticket(const char *principal, time_t time_offset, 
01489                         DATA_BLOB *ticket, DATA_BLOB *session_key_krb5, uint32 extra_ap_opts,
01490                         const char *ccname, time_t *tgs_expire) 
01491 {
01492          DEBUG(0,("NO KERBEROS SUPPORT\n"));
01493          return 1;
01494 }
01495 
01496 #endif

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