libaddns/dnsgss.c

説明を見る。
00001 /*
00002   Public Interface file for Linux DNS client library implementation
00003 
00004   Copyright (C) 2006 Krishna Ganugapati <krishnag@centeris.com>
00005   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
00006 
00007      ** NOTE! The following LGPL license applies to the libaddns
00008      ** library. This does NOT imply that all of Samba is released
00009      ** under the LGPL
00010 
00011   This library is free software; you can redistribute it and/or
00012   modify it under the terms of the GNU Lesser General Public
00013   License as published by the Free Software Foundation; either
00014   version 2.1 of the License, or (at your option) any later version.
00015 
00016   This library is distributed in the hope that it will be useful,
00017   but WITHOUT ANY WARRANTY; without even the implied warranty of
00018   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019   Lesser General Public License for more details.
00020 
00021   You should have received a copy of the GNU Lesser General Public
00022   License along with this library; if not, write to the Free Software
00023   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00024   02110-1301  USA
00025 */
00026 
00027 #include "dns.h"
00028 #include <ctype.h>
00029 
00030 
00031 #ifdef HAVE_GSSAPI_SUPPORT
00032 
00033 /*********************************************************************
00034 *********************************************************************/
00035 
00036 static int strupr( char *szDomainName )
00037 {
00038         if ( !szDomainName ) {
00039                 return ( 0 );
00040         }
00041         while ( *szDomainName != '\0' ) {
00042                 *szDomainName = toupper( *szDomainName );
00043                 szDomainName++;
00044         }
00045         return ( 0 );
00046 }
00047 
00048 #if 0
00049 /*********************************************************************
00050 *********************************************************************/
00051 
00052 static void display_status_1( const char *m, OM_uint32 code, int type )
00053 {
00054         OM_uint32 maj_stat, min_stat;
00055         gss_buffer_desc msg;
00056         OM_uint32 msg_ctx;
00057 
00058         msg_ctx = 0;
00059         while ( 1 ) {
00060                 maj_stat = gss_display_status( &min_stat, code,
00061                                                type, GSS_C_NULL_OID,
00062                                                &msg_ctx, &msg );
00063                 fprintf( stdout, "GSS-API error %s: %s\n", m,
00064                          ( char * ) msg.value );
00065                 ( void ) gss_release_buffer( &min_stat, &msg );
00066 
00067                 if ( !msg_ctx )
00068                         break;
00069         }
00070 }
00071 
00072 /*********************************************************************
00073 *********************************************************************/
00074 
00075 void display_status( const char *msg, OM_uint32 maj_stat, OM_uint32 min_stat )
00076 {
00077         display_status_1( msg, maj_stat, GSS_C_GSS_CODE );
00078         display_status_1( msg, min_stat, GSS_C_MECH_CODE );
00079 }
00080 #endif
00081 
00082 static DNS_ERROR dns_negotiate_gss_ctx_int( TALLOC_CTX *mem_ctx,
00083                                             struct dns_connection *conn,
00084                                             const char *keyname,
00085                                             const gss_name_t target_name,
00086                                             gss_ctx_id_t *ctx, 
00087                                             enum dns_ServerType srv_type )
00088 {
00089         struct gss_buffer_desc_struct input_desc, *input_ptr, output_desc;
00090         OM_uint32 major, minor;
00091         OM_uint32 ret_flags;
00092         DNS_ERROR err;
00093 
00094         gss_OID_desc krb5_oid_desc =
00095                 { 9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" };
00096 
00097         *ctx = GSS_C_NO_CONTEXT;
00098         input_ptr = NULL;
00099 
00100         do {
00101                 major = gss_init_sec_context(
00102                         &minor, NULL, ctx, target_name, &krb5_oid_desc,
00103                         GSS_C_REPLAY_FLAG | GSS_C_MUTUAL_FLAG |
00104                         GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG |
00105                         GSS_C_INTEG_FLAG | GSS_C_DELEG_FLAG,
00106                         0, NULL, input_ptr, NULL, &output_desc,
00107                         &ret_flags, NULL );
00108 
00109                 if (input_ptr != NULL) {
00110                         TALLOC_FREE(input_desc.value);
00111                 }
00112 
00113                 if (output_desc.length != 0) {
00114 
00115                         struct dns_request *req;
00116                         struct dns_rrec *rec;
00117                         struct dns_buffer *buf;
00118 
00119                         time_t t = time(NULL);
00120 
00121                         err = dns_create_query(mem_ctx, keyname, QTYPE_TKEY,
00122                                                DNS_CLASS_IN, &req);
00123                         if (!ERR_DNS_IS_OK(err)) goto error;
00124 
00125                         err = dns_create_tkey_record(
00126                                 req, keyname, "gss.microsoft.com", t,
00127                                 t + 86400, DNS_TKEY_MODE_GSSAPI, 0,
00128                                 output_desc.length, (uint8 *)output_desc.value,
00129                                 &rec );
00130                         if (!ERR_DNS_IS_OK(err)) goto error;
00131 
00132                         /* Windows 2000 DNS is broken and requires the
00133                            TKEY payload in the Answer section instead
00134                            of the Additional seciton like Windows 2003 */
00135 
00136                         if ( srv_type == DNS_SRV_WIN2000 ) {
00137                                 err = dns_add_rrec(req, rec, &req->num_answers,
00138                                                    &req->answers);
00139                         } else {
00140                                 err = dns_add_rrec(req, rec, &req->num_additionals,
00141                                                    &req->additionals);
00142                         }
00143                         
00144                         if (!ERR_DNS_IS_OK(err)) goto error;
00145 
00146                         err = dns_marshall_request(req, req, &buf);
00147                         if (!ERR_DNS_IS_OK(err)) goto error;
00148 
00149                         err = dns_send(conn, buf);
00150                         if (!ERR_DNS_IS_OK(err)) goto error;
00151 
00152                         TALLOC_FREE(req);
00153                 }
00154 
00155                 gss_release_buffer(&minor, &output_desc);
00156 
00157                 if ((major != GSS_S_COMPLETE) &&
00158                     (major != GSS_S_CONTINUE_NEEDED)) {
00159                         return ERROR_DNS_GSS_ERROR;
00160                 }
00161 
00162                 if (major == GSS_S_CONTINUE_NEEDED) {
00163 
00164                         struct dns_request *resp;
00165                         struct dns_buffer *buf;
00166                         struct dns_tkey_record *tkey;
00167 
00168                         err = dns_receive(mem_ctx, conn, &buf);
00169                         if (!ERR_DNS_IS_OK(err)) goto error;
00170 
00171                         err = dns_unmarshall_request(buf, buf, &resp);
00172                         if (!ERR_DNS_IS_OK(err)) goto error;
00173 
00174                         /*
00175                          * TODO: Compare id and keyname
00176                          */
00177                         
00178                         if ((resp->num_additionals != 1) ||
00179                             (resp->num_answers == 0) ||
00180                             (resp->answers[0]->type != QTYPE_TKEY)) {
00181                                 err = ERROR_DNS_INVALID_MESSAGE;
00182                                 goto error;
00183                         }
00184 
00185                         err = dns_unmarshall_tkey_record(
00186                                 mem_ctx, resp->answers[0], &tkey);
00187                         if (!ERR_DNS_IS_OK(err)) goto error;
00188 
00189                         input_desc.length = tkey->key_length;
00190                         input_desc.value = talloc_move(mem_ctx, &tkey->key);
00191 
00192                         input_ptr = &input_desc;
00193 
00194                         TALLOC_FREE(buf);
00195                 }
00196 
00197         } while ( major == GSS_S_CONTINUE_NEEDED );
00198 
00199         /* If we arrive here, we have a valid security context */
00200 
00201         err = ERROR_DNS_SUCCESS;
00202 
00203       error:
00204 
00205         return err;
00206 }
00207 
00208 DNS_ERROR dns_negotiate_sec_ctx( const char *target_realm,
00209                                  const char *servername,
00210                                  const char *keyname,
00211                                  gss_ctx_id_t *gss_ctx,
00212                                  enum dns_ServerType srv_type )
00213 {
00214         OM_uint32 major, minor;
00215 
00216         char *upcaserealm, *targetname;
00217         DNS_ERROR err;
00218 
00219         gss_buffer_desc input_name;
00220         struct dns_connection *conn;
00221 
00222         gss_name_t targ_name;
00223 
00224         krb5_principal host_principal;
00225         krb5_context krb_ctx = NULL;
00226 
00227         gss_OID_desc nt_host_oid_desc =
00228                 { 10, (char *)"\052\206\110\206\367\022\001\002\002\002" };
00229 
00230         TALLOC_CTX *mem_ctx;
00231 
00232         if (!(mem_ctx = talloc_init("dns_negotiate_sec_ctx"))) {
00233                 return ERROR_DNS_NO_MEMORY;
00234         }
00235 
00236         err = dns_open_connection( servername, DNS_TCP, mem_ctx, &conn );
00237         if (!ERR_DNS_IS_OK(err)) goto error;
00238 
00239         if (!(upcaserealm = talloc_strdup(mem_ctx, target_realm))) {
00240                 err = ERROR_DNS_NO_MEMORY;
00241                 goto error;
00242         }
00243 
00244         strupr(upcaserealm);
00245 
00246         if (!(targetname = talloc_asprintf(mem_ctx, "dns/%s@%s",
00247                                            servername, upcaserealm))) {
00248                 err = ERROR_DNS_NO_MEMORY;
00249                 goto error;
00250         }
00251 
00252         krb5_init_context( &krb_ctx );
00253         krb5_parse_name( krb_ctx, targetname, &host_principal );
00254 
00255         /* don't free the principal until after you call
00256            gss_release_name() or else you'll get a segv
00257            as the krb5_copy_principal() does a structure 
00258            copy and not a deep copy.    --jerry*/
00259 
00260         input_name.value = &host_principal;
00261         input_name.length = sizeof( host_principal );
00262 
00263         major = gss_import_name( &minor, &input_name,
00264                                  &nt_host_oid_desc, &targ_name );
00265 
00266         if (major) {
00267                 krb5_free_principal( krb_ctx, host_principal );
00268                 krb5_free_context( krb_ctx );
00269                 err = ERROR_DNS_GSS_ERROR;
00270                 goto error;
00271         }
00272 
00273         err = dns_negotiate_gss_ctx_int(mem_ctx, conn, keyname, 
00274                                         targ_name, gss_ctx, srv_type );
00275         
00276         gss_release_name( &minor, &targ_name );
00277 
00278         /* now we can free the principal */
00279 
00280         krb5_free_principal( krb_ctx, host_principal );
00281         krb5_free_context( krb_ctx );
00282 
00283  error:
00284         TALLOC_FREE(mem_ctx);
00285 
00286         return err;
00287 }
00288 
00289 DNS_ERROR dns_sign_update(struct dns_update_request *req,
00290                           gss_ctx_id_t gss_ctx,
00291                           const char *keyname,
00292                           const char *algorithmname,
00293                           time_t time_signed, uint16 fudge)
00294 {
00295         struct dns_buffer *buf;
00296         DNS_ERROR err;
00297         struct dns_domain_name *key, *algorithm;
00298         struct gss_buffer_desc_struct msg, mic;
00299         OM_uint32 major, minor;
00300         struct dns_rrec *rec;
00301 
00302         err = dns_marshall_update_request(req, req, &buf);
00303         if (!ERR_DNS_IS_OK(err)) return err;
00304 
00305         err = dns_domain_name_from_string(buf, keyname, &key);
00306         if (!ERR_DNS_IS_OK(err)) goto error;
00307 
00308         err = dns_domain_name_from_string(buf, algorithmname, &algorithm);
00309         if (!ERR_DNS_IS_OK(err)) goto error;
00310 
00311         dns_marshall_domain_name(buf, key);
00312         dns_marshall_uint16(buf, DNS_CLASS_ANY);
00313         dns_marshall_uint32(buf, 0); /* TTL */
00314         dns_marshall_domain_name(buf, algorithm);
00315         dns_marshall_uint16(buf, 0); /* Time prefix for 48-bit time_t */
00316         dns_marshall_uint32(buf, time_signed);
00317         dns_marshall_uint16(buf, fudge);
00318         dns_marshall_uint16(buf, 0); /* error */
00319         dns_marshall_uint16(buf, 0); /* other len */
00320 
00321         err = buf->error;
00322         if (!ERR_DNS_IS_OK(buf->error)) goto error;
00323 
00324         msg.value = (void *)buf->data;
00325         msg.length = buf->offset;
00326 
00327         major = gss_get_mic(&minor, gss_ctx, 0, &msg, &mic);
00328         if (major != 0) {
00329                 err = ERROR_DNS_GSS_ERROR;
00330                 goto error;
00331         }
00332 
00333         if (mic.length > 0xffff) {
00334                 gss_release_buffer(&minor, &mic);
00335                 err = ERROR_DNS_GSS_ERROR;
00336                 goto error;
00337         }
00338 
00339         err = dns_create_tsig_record(buf, keyname, algorithmname, time_signed,
00340                                      fudge, mic.length, (uint8 *)mic.value,
00341                                      req->id, 0, &rec);
00342         gss_release_buffer(&minor, &mic);
00343         if (!ERR_DNS_IS_OK(err)) goto error;
00344 
00345         err = dns_add_rrec(req, rec, &req->num_additionals, &req->additionals);
00346 
00347  error:
00348         TALLOC_FREE(buf);
00349         return err;
00350 }
00351 
00352 #endif  /* HAVE_GSSAPI_SUPPORT */

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