summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2006-11-13 03:19:59 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 14:25:31 -0500
commit5a6288f45891be30bd8e22978f61faf487214de6 (patch)
treeb0eeb8a90125bc818ab6057a025da67facec916d /source4/heimdal/lib
parent9d7856122e9ddd1b87ff68215669bff3c28bcafd (diff)
downloadsamba-5a6288f45891be30bd8e22978f61faf487214de6.tar.gz
samba-5a6288f45891be30bd8e22978f61faf487214de6.tar.bz2
samba-5a6288f45891be30bd8e22978f61faf487214de6.zip
r19681: Update to current lorikeet-heimdal. I'm looking at using the realm
lookup plugin, the new PAC validation code as well as Heimdal's SPNEGO implementation. Andrew Bartlett (This used to be commit 05421f45ed7811697ea491e26c9d991a7faa1a64)
Diffstat (limited to 'source4/heimdal/lib')
-rw-r--r--source4/heimdal/lib/asn1/asn1_err.et3
-rw-r--r--source4/heimdal/lib/gssapi/gssapi/gssapi.h53
-rw-r--r--source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h8
-rw-r--r--source4/heimdal/lib/gssapi/krb5/gkrb5_err.et30
-rw-r--r--source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h3
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c163
-rw-r--r--source4/heimdal/lib/gssapi/mech/gss_krb5.c38
-rw-r--r--source4/heimdal/lib/krb5/krb5-private.h54
-rw-r--r--source4/heimdal/lib/krb5/krb5-protos.h27
-rw-r--r--source4/heimdal/lib/krb5/krb5.h4
-rw-r--r--source4/heimdal/lib/krb5/krb5_locl.h6
-rw-r--r--source4/heimdal/lib/krb5/krbhst.c97
-rw-r--r--source4/heimdal/lib/krb5/locate_plugin.h64
-rwxr-xr-xsource4/heimdal/lib/krb5/mit_glue.c10
-rw-r--r--source4/heimdal/lib/krb5/plugin.c242
-rw-r--r--source4/heimdal/lib/roken/socket.c302
16 files changed, 974 insertions, 130 deletions
diff --git a/source4/heimdal/lib/asn1/asn1_err.et b/source4/heimdal/lib/asn1/asn1_err.et
index 8f1f272ccc..938b8eb988 100644
--- a/source4/heimdal/lib/asn1/asn1_err.et
+++ b/source4/heimdal/lib/asn1/asn1_err.et
@@ -3,7 +3,7 @@
#
# This might look like a com_err file, but is not
#
-id "$Id: asn1_err.et,v 1.5 1998/02/16 16:17:17 joda Exp $"
+id "$Id: asn1_err.et,v 1.6 2006/10/24 14:11:20 lha Exp $"
error_table asn1
prefix ASN1
@@ -17,4 +17,5 @@ error_code BAD_ID, "ASN.1 identifier doesn't match expected value"
error_code BAD_LENGTH, "ASN.1 length doesn't match expected value"
error_code BAD_FORMAT, "ASN.1 badly-formatted encoding"
error_code PARSE_ERROR, "ASN.1 parse error"
+error_code EXTRA_DATA, "ASN.1 extra data past end of end structure"
end
diff --git a/source4/heimdal/lib/gssapi/gssapi/gssapi.h b/source4/heimdal/lib/gssapi/gssapi/gssapi.h
index 238907653e..f89e5dfbee 100644
--- a/source4/heimdal/lib/gssapi/gssapi/gssapi.h
+++ b/source4/heimdal/lib/gssapi/gssapi/gssapi.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: gssapi.h,v 1.5 2006/10/19 07:11:14 lha Exp $ */
+/* $Id: gssapi.h,v 1.6 2006/11/10 00:39:50 lha Exp $ */
#ifndef GSSAPI_GSSAPI_H_
#define GSSAPI_GSSAPI_H_
@@ -378,57 +378,6 @@ extern gss_OID GSS_SASL_DIGEST_MD5_MECHANISM;
#define GSS_S_GAP_TOKEN (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
/*
- * From RFC1964:
- *
- * 4.1.1. Non-Kerberos-specific codes
- */
-
-#define GSS_KRB5_S_G_BAD_SERVICE_NAME 1
- /* "No @ in SERVICE-NAME name string" */
-#define GSS_KRB5_S_G_BAD_STRING_UID 2
- /* "STRING-UID-NAME contains nondigits" */
-#define GSS_KRB5_S_G_NOUSER 3
- /* "UID does not resolve to username" */
-#define GSS_KRB5_S_G_VALIDATE_FAILED 4
- /* "Validation error" */
-#define GSS_KRB5_S_G_BUFFER_ALLOC 5
- /* "Couldn't allocate gss_buffer_t data" */
-#define GSS_KRB5_S_G_BAD_MSG_CTX 6
- /* "Message context invalid" */
-#define GSS_KRB5_S_G_WRONG_SIZE 7
- /* "Buffer is the wrong size" */
-#define GSS_KRB5_S_G_BAD_USAGE 8
- /* "Credential usage type is unknown" */
-#define GSS_KRB5_S_G_UNKNOWN_QOP 9
- /* "Unknown quality of protection specified" */
-
- /*
- * 4.1.2. Kerberos-specific-codes
- */
-
-#define GSS_KRB5_S_KG_CCACHE_NOMATCH 10
- /* "Principal in credential cache does not match desired name" */
-#define GSS_KRB5_S_KG_KEYTAB_NOMATCH 11
- /* "No principal in keytab matches desired name" */
-#define GSS_KRB5_S_KG_TGT_MISSING 12
- /* "Credential cache has no TGT" */
-#define GSS_KRB5_S_KG_NO_SUBKEY 13
- /* "Authenticator has no subkey" */
-#define GSS_KRB5_S_KG_CONTEXT_ESTABLISHED 14
- /* "Context is already fully established" */
-#define GSS_KRB5_S_KG_BAD_SIGN_TYPE 15
- /* "Unknown signature type in token" */
-#define GSS_KRB5_S_KG_BAD_LENGTH 16
- /* "Invalid field length in token" */
-#define GSS_KRB5_S_KG_CTX_INCOMPLETE 17
- /* "Attempt to use incomplete security context" */
-
-/*
- * This is used to make sure mechs that don't want to have external
- * references don't get any prototypes, and thus can get warnings.
- */
-
-/*
* Finally, function prototypes for the GSS-API routines.
*/
diff --git a/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h b/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h
index f06a994008..ecd90a6656 100644
--- a/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h
+++ b/source4/heimdal/lib/gssapi/gssapi/gssapi_krb5.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: gssapi_krb5.h,v 1.14 2006/11/08 23:01:01 lha Exp $ */
+/* $Id: gssapi_krb5.h,v 1.17 2006/11/10 01:05:34 lha Exp $ */
#ifndef GSSAPI_KRB5_H_
#define GSSAPI_KRB5_H_
@@ -78,6 +78,7 @@ extern gss_OID GSS_KRB5_GET_AUTHTIME_X;
extern gss_OID GSS_KRB5_GET_SERVICE_KEYBLOCK_X;
/* Extensions creds */
extern gss_OID GSS_KRB5_IMPORT_CRED_X;
+extern gss_OID GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X;
/*
* kerberos mechanism specific functions
@@ -205,6 +206,11 @@ gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status,
void *kctx);
+OM_uint32
+gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
+ gss_cred_id_t cred,
+ OM_uint32 num_enctypes,
+ int32_t *enctypes);
#ifdef __cplusplus
}
diff --git a/source4/heimdal/lib/gssapi/krb5/gkrb5_err.et b/source4/heimdal/lib/gssapi/krb5/gkrb5_err.et
new file mode 100644
index 0000000000..97e98c5e1e
--- /dev/null
+++ b/source4/heimdal/lib/gssapi/krb5/gkrb5_err.et
@@ -0,0 +1,30 @@
+#
+# extended gss krb5 error messages
+#
+
+id "$Id: gkrb5_err.et,v 1.1 2006/11/09 23:52:17 lha Exp $"
+
+error_table gk5
+
+prefix GSS_KRB5_S
+
+error_code G_BAD_SERVICE_NAME, "No @ in SERVICE-NAME name string"
+error_code G_BAD_STRING_UID, "STRING-UID-NAME contains nondigits"
+error_code G_NOUSER, "UID does not resolve to username"
+error_code G_VALIDATE_FAILED, "Validation error"
+error_code G_BUFFER_ALLOC, "Couldn't allocate gss_buffer_t data"
+error_code G_BAD_MSG_CTX, "Message context invalid"
+error_code G_WRONG_SIZE, "Buffer is the wrong size"
+error_code G_BAD_USAGE, "Credential usage type is unknown"
+error_code G_UNKNOWN_QOP, "Unknown quality of protection specified"
+
+index 128
+
+error_code KG_CCACHE_NOMATCH, "Principal in credential cache does not match desired name"
+error_code KG_KEYTAB_NOMATCH, "No principal in keytab matches desired name"
+error_code KG_TGT_MISSING, "Credential cache has no TGT"
+error_code KG_NO_SUBKEY, "Authenticator has no subkey"
+error_code KG_CONTEXT_ESTABLISHED, "Context is already fully established"
+error_code KG_BAD_SIGN_TYPE, "Unknown signature type in token"
+error_code KG_BAD_LENGTH, "Invalid field length in token"
+error_code KG_CTX_INCOMPLETE, "Attempt to use incomplete security context"
diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
index ea7a561b5b..39c800bf31 100644
--- a/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
+++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5_locl.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: gsskrb5_locl.h,v 1.7 2006/11/07 17:57:43 lha Exp $ */
+/* $Id: gsskrb5_locl.h,v 1.8 2006/11/10 00:36:40 lha Exp $ */
#ifndef GSSKRB5_LOCL_H
#define GSSKRB5_LOCL_H
@@ -41,6 +41,7 @@
#endif
#include <krb5_locl.h>
+#include <gkrb5_err.h>
#include <gssapi.h>
#include <gssapi_mech.h>
#include <assert.h>
diff --git a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
index d3a21464da..73207806a0 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_accept_sec_context.c
@@ -27,7 +27,108 @@
*/
#include "mech_locl.h"
-RCSID("$Id: gss_accept_sec_context.c,v 1.6 2006/10/25 00:45:12 lha Exp $");
+RCSID("$Id: gss_accept_sec_context.c,v 1.7 2006/11/10 03:30:12 lha Exp $");
+
+static OM_uint32
+parse_header(const gss_buffer_t input_token, gss_OID mech_oid)
+{
+ unsigned char *p = input_token->value;
+ size_t len = input_token->length;
+ size_t a, b;
+
+ /*
+ * Token must start with [APPLICATION 0] SEQUENCE.
+ * But if it doesn't assume its DCE-STYLE Kerberos!
+ */
+ if (len == 0)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ p++;
+ len--;
+
+ /*
+ * Decode the length and make sure it agrees with the
+ * token length.
+ */
+ if (len == 0)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ if ((*p & 0x80) == 0) {
+ a = *p;
+ p++;
+ len--;
+ } else {
+ b = *p & 0x7f;
+ p++;
+ len--;
+ if (len < b)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ a = 0;
+ while (b) {
+ a = (a << 8) | *p;
+ p++;
+ len--;
+ b--;
+ }
+ }
+ if (a != len)
+ return (GSS_S_DEFECTIVE_TOKEN);
+
+ /*
+ * Decode the OID for the mechanism. Simplify life by
+ * assuming that the OID length is less than 128 bytes.
+ */
+ if (len < 2 || *p != 0x06)
+ return (GSS_S_DEFECTIVE_TOKEN);
+ if ((p[1] & 0x80) || p[1] > (len - 2))
+ return (GSS_S_DEFECTIVE_TOKEN);
+ mech_oid->length = p[1];
+ p += 2;
+ len -= 2;
+ mech_oid->elements = p;
+
+ return GSS_S_COMPLETE;
+}
+
+static gss_OID_desc krb5_mechanism =
+ {9, rk_UNCONST("\x2a\x86\x48\x86\xf7\x12\x01\x02\x02")};
+static gss_OID_desc spnego_mechanism =
+ {6, rk_UNCONST("\x2b\x06\x01\x05\x05\x02")};
+
+static OM_uint32
+choose_mech(const gss_buffer_t input, gss_OID mech_oid)
+{
+ OM_uint32 status;
+
+ /*
+ * First try to parse the gssapi token header and see if its a
+ * correct header, use that in the first hand.
+ */
+
+ status = parse_header(input, mech_oid);
+ if (status == GSS_S_COMPLETE)
+ return GSS_S_COMPLETE;
+
+ /*
+ * Lets guess what mech is really is, callback function to mech ??
+ */
+
+ if (input->length != 0 && ((const char *)input->value)[0] == 0x6E) {
+ /* Could be a raw AP-REQ (check for APPLICATION tag) */
+ *mech_oid = krb5_mechanism;
+ return GSS_S_COMPLETE;
+ } else if (input->length == 0) {
+ /*
+ * There is the a wiered mode of SPNEGO (in CIFS and
+ * SASL GSS-SPENGO where the first token is zero
+ * length and the acceptor returns a mech_list, lets
+ * home that is what is happening now.
+ */
+ *mech_oid = spnego_mechanism;
+ return GSS_S_COMPLETE;
+ }
+ return status;
+}
+
OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
gss_ctx_id_t *context_handle,
@@ -64,64 +165,12 @@ OM_uint32 gss_accept_sec_context(OM_uint32 *minor_status,
* parse the input token to figure out the mechanism to use.
*/
if (*context_handle == GSS_C_NO_CONTEXT) {
- unsigned char *p = input_token->value;
- size_t len = input_token->length;
- size_t a, b;
gss_OID_desc mech_oid;
- /*
- * Token must start with [APPLICATION 0] SEQUENCE.
- * But if it doesn't assume its DCE-STYLE Kerberos!
- * And if it's not there at all, then we are requesting a mech list from SPNEGO
- */
- if (len == 0) {
- mech_oid = *GSS_SPNEGO_MECHANISM;
- } else if (*p != 0x60) {
- mech_oid = *GSS_KRB5_MECHANISM;
- } else {
- p++;
- len--;
-
- /*
- * Decode the length and make sure it agrees with the
- * token length.
- */
- if (len == 0)
- return (GSS_S_DEFECTIVE_TOKEN);
- if ((*p & 0x80) == 0) {
- a = *p;
- p++;
- len--;
- } else {
- b = *p & 0x7f;
- p++;
- len--;
- if (len < b)
- return (GSS_S_DEFECTIVE_TOKEN);
- a = 0;
- while (b) {
- a = (a << 8) | *p;
- p++;
- len--;
- b--;
- }
- }
- if (a != len)
- return (GSS_S_DEFECTIVE_TOKEN);
-
- /*
- * Decode the OID for the mechanism. Simplify life by
- * assuming that the OID length is less than 128 bytes.
- */
- if (len < 2 || *p != 0x06)
- return (GSS_S_DEFECTIVE_TOKEN);
- if ((p[1] & 0x80) || p[1] > (len - 2))
- return (GSS_S_DEFECTIVE_TOKEN);
- mech_oid.length = p[1];
- p += 2;
- len -= 2;
- mech_oid.elements = p;
- }
+ major_status = choose_mech(input_token, &mech_oid);
+ if (major_status != GSS_S_COMPLETE)
+ return major_status;
+
/*
* Now that we have a mechanism, we can find the
* implementation.
diff --git a/source4/heimdal/lib/gssapi/mech/gss_krb5.c b/source4/heimdal/lib/gssapi/mech/gss_krb5.c
index 34cdbeb3c1..76a2c2b637 100644
--- a/source4/heimdal/lib/gssapi/mech/gss_krb5.c
+++ b/source4/heimdal/lib/gssapi/mech/gss_krb5.c
@@ -27,7 +27,7 @@
*/
#include "mech_locl.h"
-RCSID("$Id: gss_krb5.c,v 1.20 2006/11/08 23:11:03 lha Exp $");
+RCSID("$Id: gss_krb5.c,v 1.21 2006/11/10 00:57:27 lha Exp $");
#include <krb5.h>
#include <roken.h>
@@ -421,13 +421,41 @@ gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
*/
OM_uint32
-gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
+gss_krb5_set_allowable_enctypes(OM_uint32 *min_status,
gss_cred_id_t cred,
OM_uint32 num_enctypes,
- krb5_enctype *enctypes)
+ int32_t *enctypes)
{
- *minor_status = 0;
- return GSS_S_COMPLETE;
+ OM_uint32 maj_status;
+ gss_buffer_desc buffer;
+ krb5_storage *sp;
+ krb5_data data;
+
+ sp = krb5_storage_emem();
+ if (sp == NULL) {
+ *min_status = ENOMEM;
+ maj_status = GSS_S_FAILURE;
+ goto out;
+ }
+
+ while(*enctypes) {
+ krb5_store_int32(sp, *enctypes);
+ enctypes++;
+ }
+
+ krb5_storage_to_data(sp, &data);
+
+ buffer.value = data.data;
+ buffer.length = data.length;
+
+ maj_status = gss_set_cred_option(min_status,
+ &cred,
+ GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
+ &buffer);
+out:
+ if (sp)
+ krb5_storage_free(sp);
+ return maj_status;
}
/*
diff --git a/source4/heimdal/lib/krb5/krb5-private.h b/source4/heimdal/lib/krb5/krb5-private.h
index 0bf184a530..ba2f75ad22 100644
--- a/source4/heimdal/lib/krb5/krb5-private.h
+++ b/source4/heimdal/lib/krb5/krb5-private.h
@@ -299,6 +299,37 @@ _krb5_oid_to_enctype (
const heim_oid */*oid*/,
krb5_enctype */*etype*/);
+void
+_krb5_pac_free (
+ krb5_context /*context*/,
+ struct krb5_pac */*pac*/);
+
+krb5_error_code
+_krb5_pac_parse (
+ krb5_context /*context*/,
+ const void */*ptr*/,
+ size_t /*len*/,
+ struct krb5_pac **/*pac*/);
+
+krb5_error_code
+_krb5_pac_sign (
+ krb5_context /*context*/,
+ struct krb5_pac */*p*/,
+ time_t /*authtime*/,
+ krb5_principal /*principal*/,
+ krb5_keyblock */*server_key*/,
+ krb5_keyblock */*priv_key*/,
+ krb5_data */*data*/);
+
+krb5_error_code
+_krb5_pac_verify (
+ krb5_context /*context*/,
+ struct krb5_pac */*pac*/,
+ time_t /*authtime*/,
+ krb5_principal /*principal*/,
+ krb5_keyblock */*server*/,
+ krb5_keyblock */*privsvr*/);
+
krb5_error_code
_krb5_parse_moduli (
krb5_context /*context*/,
@@ -380,6 +411,29 @@ _krb5_pk_verify_sign (
krb5_data */*content*/,
struct krb5_pk_cert **/*signer*/);
+krb5_error_code
+_krb5_plugin_find (
+ krb5_context /*context*/,
+ enum plugin_type /*type*/,
+ const char */*name*/,
+ struct krb5_plugin **/*list*/);
+
+void
+_krb5_plugin_free (struct krb5_plugin */*list*/);
+
+struct krb5_plugin *
+_krb5_plugin_get_next (struct krb5_plugin */*p*/);
+
+void *
+_krb5_plugin_get_symbol (struct krb5_plugin */*p*/);
+
+krb5_error_code
+_krb5_plugin_register (
+ krb5_context /*context*/,
+ enum plugin_type /*type*/,
+ const char */*name*/,
+ void */*symbol*/);
+
krb5_error_code KRB5_LIB_FUNCTION
_krb5_principal2principalname (
PrincipalName */*p*/,
diff --git a/source4/heimdal/lib/krb5/krb5-protos.h b/source4/heimdal/lib/krb5/krb5-protos.h
index 104f10bdf2..8b61e8d7d2 100644
--- a/source4/heimdal/lib/krb5/krb5-protos.h
+++ b/source4/heimdal/lib/krb5/krb5-protos.h
@@ -499,6 +499,12 @@ krb5_boolean KRB5_LIB_FUNCTION
krb5_c_is_keyed_cksum (krb5_cksumtype /*ctype*/);
krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_keylength (
+ krb5_context /*context*/,
+ krb5_enctype /*enctype*/,
+ size_t */*len*/);
+
+krb5_error_code KRB5_LIB_FUNCTION
krb5_c_make_checksum (
krb5_context /*context*/,
krb5_cksumtype /*cksumtype*/,
@@ -2165,6 +2171,9 @@ krb5_get_krbhst (
const krb5_realm */*realm*/,
char ***/*hostlist*/);
+time_t KRB5_LIB_FUNCTION
+krb5_get_max_time_skew (krb5_context /*context*/);
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_pw_salt (
krb5_context /*context*/,
@@ -2177,9 +2186,6 @@ krb5_get_server_rcache (
const krb5_data */*piece*/,
krb5_rcache */*id*/);
-time_t KRB5_LIB_FUNCTION
-krb5_get_time_wrap (krb5_context /*context*/);
-
krb5_boolean KRB5_LIB_FUNCTION
krb5_get_use_admin_kdc (krb5_context /*context*/);
@@ -3165,6 +3171,11 @@ krb5_set_ignore_addresses (
krb5_context /*context*/,
const krb5_addresses */*addresses*/);
+void KRB5_LIB_FUNCTION
+krb5_set_max_time_skew (
+ krb5_context /*context*/,
+ time_t /*t*/);
+
krb5_error_code KRB5_LIB_FUNCTION
krb5_set_password (
krb5_context /*context*/,
@@ -3198,11 +3209,6 @@ krb5_set_send_to_kdc_func (
void */*data*/);
void KRB5_LIB_FUNCTION
-krb5_set_time_wrap (
- krb5_context /*context*/,
- time_t /*t*/);
-
-void KRB5_LIB_FUNCTION
krb5_set_use_admin_kdc (
krb5_context /*context*/,
krb5_boolean /*flag*/);
@@ -3271,6 +3277,11 @@ krb5_storage_from_mem (
void */*buf*/,
size_t /*len*/);
+krb5_storage * KRB5_LIB_FUNCTION
+krb5_storage_from_readonly_mem (
+ const void */*buf*/,
+ size_t /*len*/);
+
krb5_flags KRB5_LIB_FUNCTION
krb5_storage_get_byteorder (
krb5_storage */*sp*/,
diff --git a/source4/heimdal/lib/krb5/krb5.h b/source4/heimdal/lib/krb5/krb5.h
index f5c8b069de..1b26e8b3e7 100644
--- a/source4/heimdal/lib/krb5/krb5.h
+++ b/source4/heimdal/lib/krb5/krb5.h
@@ -31,7 +31,7 @@
* SUCH DAMAGE.
*/
-/* $Id: krb5.h,v 1.254 2006/11/07 00:17:42 lha Exp $ */
+/* $Id: krb5.h,v 1.255 2006/11/12 08:33:07 lha Exp $ */
#ifndef __KRB5_H__
#define __KRB5_H__
@@ -78,6 +78,8 @@ typedef struct krb5_get_creds_opt_data *krb5_get_creds_opt;
struct krb5_digest;
typedef struct krb5_digest *krb5_digest;
+struct krb5_pac;
+
typedef struct krb5_rd_req_in_ctx *krb5_rd_req_in_ctx;
typedef struct krb5_rd_req_out_ctx *krb5_rd_req_out_ctx;
diff --git a/source4/heimdal/lib/krb5/krb5_locl.h b/source4/heimdal/lib/krb5/krb5_locl.h
index 89b3c6ad40..3fb5461b3c 100644
--- a/source4/heimdal/lib/krb5/krb5_locl.h
+++ b/source4/heimdal/lib/krb5/krb5_locl.h
@@ -148,6 +148,12 @@ struct krb5_dh_moduli;
/* v4 glue */
struct _krb5_krb_auth_data;
+struct krb5_plugin;
+enum plugin_type {
+ PLUGIN_TYPE_DATA = 1,
+ PLUGIN_TYPE_FUNC
+};
+
#include <der.h>
#include <krb5.h>
diff --git a/source4/heimdal/lib/krb5/krbhst.c b/source4/heimdal/lib/krb5/krbhst.c
index e7b2579229..f395f0d0c3 100644
--- a/source4/heimdal/lib/krb5/krbhst.c
+++ b/source4/heimdal/lib/krb5/krbhst.c
@@ -33,8 +33,9 @@
#include "krb5_locl.h"
#include <resolve.h>
+#include "locate_plugin.h"
-RCSID("$Id: krbhst.c,v 1.57 2006/10/06 17:11:02 lha Exp $");
+RCSID("$Id: krbhst.c,v 1.58 2006/11/12 20:05:20 lha Exp $");
static int
string_to_proto(const char *string)
@@ -147,6 +148,7 @@ struct krb5_krbhst_data {
#define KD_FALLBACK 16
#define KD_CONFIG_EXISTS 32
#define KD_LARGE_MSG 64
+#define KD_PLUGIN 128
krb5_error_code (*get_next)(krb5_context, struct krb5_krbhst_data *,
krb5_krbhst_info**);
@@ -460,8 +462,8 @@ fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
hi->proto = proto;
hi->port = hi->def_port = port;
hi->ai = ai;
- memmove(hi->hostname, host, hostlen - 1);
- hi->hostname[hostlen - 1] = '\0';
+ memmove(hi->hostname, host, hostlen);
+ hi->hostname[hostlen] = '\0';
free(host);
append_host_hostinfo(kd, hi);
kd->fallback_count++;
@@ -469,6 +471,88 @@ fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd,
return 0;
}
+/*
+ * Fetch hosts from plugin
+ */
+
+static krb5_error_code
+add_locate(void *ctx, int type, struct sockaddr *addr)
+{
+ struct krb5_krbhst_info *hi;
+ struct krb5_krbhst_data *kd = ctx;
+ char host[NI_MAXHOST], port[NI_MAXSERV];
+ struct addrinfo hints, *ai;
+ socklen_t socklen;
+ size_t hostlen;
+ int ret;
+
+ socklen = socket_sockaddr_size(addr);
+
+ ret = getnameinfo(addr, socklen, host, sizeof(host), port, sizeof(port),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ if (ret != 0)
+ return 0;
+
+ memset(&hints, 0, sizeof(hints));
+ ret = getaddrinfo(host, port, &hints, &ai);
+ if (ret)
+ return 0;
+
+ hostlen = strlen(host);
+
+ hi = calloc(1, sizeof(*hi) + hostlen);
+ if(hi == NULL) {
+ free(host);
+ return ENOMEM;
+ }
+
+ hi->proto = krbhst_get_default_proto(kd);
+ hi->port = hi->def_port = socket_get_port(addr);
+ hi->ai = ai;
+ memmove(hi->hostname, host, hostlen);
+ hi->hostname[hostlen] = '\0';
+ append_host_hostinfo(kd, hi);
+
+ return 0;
+}
+
+static void
+plugin_get_hosts(krb5_context context,
+ struct krb5_krbhst_data *kd,
+ enum locate_service_type type)
+{
+ struct krb5_plugin *list, *e;
+ krb5_error_code ret;
+
+ ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "resolve", &list);
+ if(ret != 0 || list == NULL)
+ return;
+
+ kd->flags |= KD_CONFIG_EXISTS;
+
+ for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) {
+ krb5plugin_service_locate_ftable *service;
+ void *ctx;
+
+ service = _krb5_plugin_get_symbol(e);
+ if (service->minor_version != 0)
+ continue;
+
+ (*service->init)(context, &ctx);
+ ret = (*service->lookup)(ctx, type, kd->realm, 0, 0, add_locate, kd);
+ (*service->fini)(ctx);
+ if (ret) {
+ krb5_set_error_string(context, "Plugin failed to lookup");
+ break;
+ }
+ }
+ _krb5_plugin_free(list);
+}
+
+/*
+ *
+ */
+
static krb5_error_code
kdc_get_next(krb5_context context,
struct krb5_krbhst_data *kd,
@@ -476,6 +560,13 @@ kdc_get_next(krb5_context context,
{
krb5_error_code ret;
+ if ((kd->flags & KD_PLUGIN) == 0) {
+ plugin_get_hosts(context, kd, locate_service_kdc);
+ kd->flags |= KD_PLUGIN;
+ if(get_next(kd, host))
+ return 0;
+ }
+
if((kd->flags & KD_CONFIG) == 0) {
config_get_hosts(context, kd, "kdc");
kd->flags |= KD_CONFIG;
diff --git a/source4/heimdal/lib/krb5/locate_plugin.h b/source4/heimdal/lib/krb5/locate_plugin.h
new file mode 100644
index 0000000000..ec06d362cf
--- /dev/null
+++ b/source4/heimdal/lib/krb5/locate_plugin.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* $Id: locate_plugin.h,v 1.1 2006/11/12 19:00:03 lha Exp $ */
+
+#ifndef HEIMDAL_KRB5_LOCATE_PLUGIN_H
+#define HEIMDAL_KRB5_LOCATE_PLUGIN_H 1
+
+#include <krb5.h>
+
+enum locate_service_type {
+ locate_service_kdc = 1,
+ locate_service_master_kdc,
+ locate_service_kadmin,
+ locate_service_krb524,
+ locate_service_kpasswd
+};
+
+typedef krb5_error_code
+(*krb5plugin_service_locate_lookup) (void *, enum locate_service_type,
+ const char *, int, int,
+ int (*)(void *,int,struct sockaddr *),
+ void *);
+
+
+typedef struct krb5plugin_service_locate_ftable {
+ int minor_version;
+ krb5_error_code (*init)(krb5_context, void **);
+ void (*fini)(void *);
+ krb5plugin_service_locate_lookup lookup;
+} krb5plugin_service_locate_ftable;
+
+#endif /* HEIMDAL_KRB5_LOCATE_PLUGIN_H */
+
diff --git a/source4/heimdal/lib/krb5/mit_glue.c b/source4/heimdal/lib/krb5/mit_glue.c
index b9075b3079..493c4cd845 100755
--- a/source4/heimdal/lib/krb5/mit_glue.c
+++ b/source4/heimdal/lib/krb5/mit_glue.c
@@ -32,7 +32,7 @@
*/
#include "krb5_locl.h"
-RCSID("$Id: mit_glue.c,v 1.8 2006/10/14 09:51:02 lha Exp $");
+RCSID("$Id: mit_glue.c,v 1.9 2006/11/09 21:24:16 lha Exp $");
/*
* Glue for MIT API
@@ -325,3 +325,11 @@ krb5_c_make_random_key(krb5_context context,
{
return krb5_generate_random_keyblock(context, enctype, random_key);
}
+
+krb5_error_code KRB5_LIB_FUNCTION
+krb5_c_keylength(krb5_context context,
+ krb5_enctype enctype,
+ size_t *len)
+{
+ return krb5_enctype_keysize(context, enctype, len);
+}
diff --git a/source4/heimdal/lib/krb5/plugin.c b/source4/heimdal/lib/krb5/plugin.c
new file mode 100644
index 0000000000..294807faab
--- /dev/null
+++ b/source4/heimdal/lib/krb5/plugin.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2006 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "krb5_locl.h"
+RCSID("$Id: plugin.c,v 1.2 2006/11/12 21:39:43 lha Exp $");
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#include <dirent.h>
+
+struct krb5_plugin {
+ void *symbol;
+ void *dsohandle;
+ struct krb5_plugin *next;
+};
+
+struct plugin {
+ enum plugin_type type;
+ void *name;
+ void *symbol;
+ struct plugin *next;
+};
+
+static HEIMDAL_MUTEX plugin_mutex = HEIMDAL_MUTEX_INITIALIZER;
+static struct plugin *registered = NULL;
+
+static const char *plugin_dir = LIBDIR "/plugin/krb5";
+
+/*
+ *
+ */
+
+void *
+_krb5_plugin_get_symbol(struct krb5_plugin *p)
+{
+ return p->symbol;
+}
+
+struct krb5_plugin *
+_krb5_plugin_get_next(struct krb5_plugin *p)
+{
+ return p->next;
+}
+
+/*
+ *
+ */
+
+static krb5_error_code
+loadlib(krb5_context context,
+ enum plugin_type type,
+ const char *name,
+ const char *lib,
+ struct krb5_plugin **e)
+{
+ *e = calloc(1, sizeof(**e));
+ if (*e == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+
+ (*e)->dsohandle = dlopen(lib, 0);
+ if ((*e)->dsohandle == NULL) {
+ free(*e);
+ krb5_set_error_string(context, "Failed to load %s: %s",
+ lib, dlerror());
+ return ENOMEM;
+ }
+
+ /* dlsym doesn't care about the type */
+ (*e)->symbol = dlsym((*e)->dsohandle, name);
+ if ((*e)->symbol == NULL) {
+ dlclose((*e)->dsohandle);
+ free(*e);
+ krb5_clear_error_string(context);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+krb5_error_code
+_krb5_plugin_register(krb5_context context,
+ enum plugin_type type,
+ const char *name,
+ void *symbol)
+{
+ struct plugin *e;
+
+ e = calloc(1, sizeof(*e));
+ if (e == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ e->type = type;
+ e->name = strdup(name);
+ if (e->name == NULL) {
+ free(e);
+ krb5_set_error_string(context, "out of memory");
+ return ENOMEM;
+ }
+ e->symbol = symbol;
+
+ HEIMDAL_MUTEX_lock(&plugin_mutex);
+ e->next = registered;
+ registered = e;
+ HEIMDAL_MUTEX_unlock(&plugin_mutex);
+
+ return 0;
+}
+
+krb5_error_code
+_krb5_plugin_find(krb5_context context,
+ enum plugin_type type,
+ const char *name,
+ struct krb5_plugin **list)
+{
+ struct krb5_plugin *e;
+ struct plugin *p;
+ krb5_error_code ret;
+ char *sysdirs[2] = { NULL, NULL };
+ char **dirs = NULL, **di;
+ struct dirent *entry;
+ char *path;
+ DIR *d = NULL;
+
+ *list = NULL;
+
+ HEIMDAL_MUTEX_lock(&plugin_mutex);
+
+ for (p = registered; p != NULL; p = p->next) {
+ if (p->type != type || strcmp(p->name, name) != 0)
+ continue;
+
+ e = calloc(1, sizeof(*e));
+ if (e == NULL) {
+ HEIMDAL_MUTEX_unlock(&plugin_mutex);
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ e->symbol = p->symbol;
+ e->dsohandle = NULL;
+ e->next = *list;
+ *list = e;
+ }
+ HEIMDAL_MUTEX_unlock(&plugin_mutex);
+
+ dirs = krb5_config_get_strings(context, NULL, "libdefaults",
+ "plugin_dir", NULL);
+ if (dirs == NULL) {
+ sysdirs[0] = rk_UNCONST(plugin_dir);
+ dirs = sysdirs;
+ }
+
+ for (di = dirs; *di != NULL; di++) {
+
+ d = opendir(*di);
+ if (d == NULL)
+ continue;
+
+ while ((entry = readdir(d)) != NULL) {
+ asprintf(&path, "%s/%s", *di, entry->d_name);
+ if (path == NULL) {
+ krb5_set_error_string(context, "out of memory");
+ ret = ENOMEM;
+ goto out;
+ }
+ ret = loadlib(context, type, name, path, &e);
+ free(path);
+ if (ret)
+ continue;
+
+ e->next = *list;
+ *list = e;
+ }
+ closedir(d);
+ }
+ if (dirs != sysdirs)
+ krb5_config_free_strings(dirs);
+
+ if (*list == NULL) {
+ krb5_set_error_string(context, "Did not find a plugin for %s", name);
+ return ENOENT;
+ }
+
+ return 0;
+
+out:
+ if (dirs && dirs != sysdirs)
+ krb5_config_free_strings(dirs);
+ if (d)
+ closedir(d);
+ _krb5_plugin_free(*list);
+ *list = NULL;
+
+ return ret;
+}
+
+void
+_krb5_plugin_free(struct krb5_plugin *list)
+{
+ struct krb5_plugin *next;
+ while (list) {
+ next = list->next;
+ if (list->dsohandle)
+ dlclose(list->dsohandle);
+ free(list);
+ list = next;
+ }
+}
+
diff --git a/source4/heimdal/lib/roken/socket.c b/source4/heimdal/lib/roken/socket.c
new file mode 100644
index 0000000000..5f77aacf43
--- /dev/null
+++ b/source4/heimdal/lib/roken/socket.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1999 - 2000 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+RCSID("$Id: socket.c,v 1.11 2005/09/01 18:48:17 lha Exp $");
+#endif
+
+#include <roken.h>
+#include <err.h>
+
+/*
+ * Set `sa' to the unitialized address of address family `af'
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_any (struct sockaddr *sa, int af)
+{
+ switch (af) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+
+ memset (sin4, 0, sizeof(*sin4));
+ sin4->sin_family = AF_INET;
+ sin4->sin_port = 0;
+ sin4->sin_addr.s_addr = INADDR_ANY;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ memset (sin6, 0, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_addr = in6addr_any;
+ break;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * set `sa' to (`ptr', `port')
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_address_and_port (struct sockaddr *sa, const void *ptr, int port)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+
+ memset (sin4, 0, sizeof(*sin4));
+ sin4->sin_family = AF_INET;
+ sin4->sin_port = port;
+ memcpy (&sin4->sin_addr, ptr, sizeof(struct in_addr));
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+ memset (sin6, 0, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = port;
+ memcpy (&sin6->sin6_addr, ptr, sizeof(struct in6_addr));
+ break;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Return the size of an address of the type in `sa'
+ */
+
+size_t ROKEN_LIB_FUNCTION
+socket_addr_size (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET :
+ return sizeof(struct in_addr);
+#ifdef HAVE_IPV6
+ case AF_INET6 :
+ return sizeof(struct in6_addr);
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Return the size of a `struct sockaddr' in `sa'.
+ */
+
+size_t ROKEN_LIB_FUNCTION
+socket_sockaddr_size (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET :
+ return sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+ case AF_INET6 :
+ return sizeof(struct sockaddr_in6);
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Return the binary address of `sa'.
+ */
+
+void * ROKEN_LIB_FUNCTION
+socket_get_address (struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+ return &sin4->sin_addr;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ return &sin6->sin6_addr;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Return the port number from `sa'.
+ */
+
+int ROKEN_LIB_FUNCTION
+socket_get_port (const struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ const struct sockaddr_in *sin4 = (const struct sockaddr_in *)sa;
+ return sin4->sin_port;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+ return sin6->sin6_port;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Set the port in `sa' to `port'.
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_port (struct sockaddr *sa, int port)
+{
+ switch (sa->sa_family) {
+ case AF_INET : {
+ struct sockaddr_in *sin4 = (struct sockaddr_in *)sa;
+ sin4->sin_port = port;
+ break;
+ }
+#ifdef HAVE_IPV6
+ case AF_INET6 : {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ sin6->sin6_port = port;
+ break;
+ }
+#endif
+ default :
+ errx (1, "unknown address family %d", sa->sa_family);
+ break;
+ }
+}
+
+/*
+ * Set the range of ports to use when binding with port = 0.
+ */
+void ROKEN_LIB_FUNCTION
+socket_set_portrange (int sock, int restr, int af)
+{
+#if defined(IP_PORTRANGE)
+ if (af == AF_INET) {
+ int on = restr ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
+ if (setsockopt (sock, IPPROTO_IP, IP_PORTRANGE, &on,
+ sizeof(on)) < 0)
+ warn ("setsockopt IP_PORTRANGE (ignored)");
+ }
+#endif
+#if defined(IPV6_PORTRANGE)
+ if (af == AF_INET6) {
+ int on = restr ? IPV6_PORTRANGE_HIGH :
+ IPV6_PORTRANGE_DEFAULT;
+ if (setsockopt (sock, IPPROTO_IPV6, IPV6_PORTRANGE, &on,
+ sizeof(on)) < 0)
+ warn ("setsockopt IPV6_PORTRANGE (ignored)");
+ }
+#endif
+}
+
+/*
+ * Enable debug on `sock'.
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_debug (int sock)
+{
+#if defined(SO_DEBUG) && defined(HAVE_SETSOCKOPT)
+ int on = 1;
+
+ if (setsockopt (sock, SOL_SOCKET, SO_DEBUG, (void *) &on, sizeof (on)) < 0)
+ warn ("setsockopt SO_DEBUG (ignored)");
+#endif
+}
+
+/*
+ * Set the type-of-service of `sock' to `tos'.
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_tos (int sock, int tos)
+{
+#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT)
+ if (setsockopt (sock, IPPROTO_IP, IP_TOS, (void *) &tos, sizeof (int)) < 0)
+ if (errno != EINVAL)
+ warn ("setsockopt TOS (ignored)");
+#endif
+}
+
+/*
+ * set the reuse of addresses on `sock' to `val'.
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_reuseaddr (int sock, int val)
+{
+#if defined(SO_REUSEADDR) && defined(HAVE_SETSOCKOPT)
+ if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val,
+ sizeof(val)) < 0)
+ err (1, "setsockopt SO_REUSEADDR");
+#endif
+}
+
+/*
+ * Set the that the `sock' should bind to only IPv6 addresses.
+ */
+
+void ROKEN_LIB_FUNCTION
+socket_set_ipv6only (int sock, int val)
+{
+#if defined(IPV6_V6ONLY) && defined(HAVE_SETSOCKOPT)
+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&val, sizeof(val));
+#endif
+}