00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
00133
00134
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
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
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
00256
00257
00258
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
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);
00314 dns_marshall_domain_name(buf, algorithm);
00315 dns_marshall_uint16(buf, 0);
00316 dns_marshall_uint32(buf, time_signed);
00317 dns_marshall_uint16(buf, fudge);
00318 dns_marshall_uint16(buf, 0);
00319 dns_marshall_uint16(buf, 0);
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