freebsd/sys: Import RPC and XDR support

Update #4475
This commit is contained in:
Chris Johns 2021-07-28 16:13:46 +10:00
parent 6514d56158
commit 3da45ae4bc
44 changed files with 18090 additions and 0 deletions

View File

@ -0,0 +1,620 @@
/*
* Copyright (C) The Internet Society (2000). All Rights Reserved.
*
* This document and translations of it may be copied and furnished to
* others, and derivative works that comment on or otherwise explain it
* or assist in its implementation may be prepared, copied, published
* and distributed, in whole or in part, without restriction of any
* kind, provided that the above copyright notice and this paragraph are
* included on all such copies and derivative works. However, this
* document itself may not be modified in any way, such as by removing
* the copyright notice or references to the Internet Society or other
* Internet organizations, except as needed for the purpose of
* developing Internet standards in which case the procedures for
* copyrights defined in the Internet Standards process must be
* followed, or as required to translate it into languages other than
* English.
*
* The limited permissions granted above are perpetual and will not be
* revoked by the Internet Society or its successors or assigns.
*
* This document and the information contained herein is provided on an
* "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
* TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
* HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* $FreeBSD$
*/
#ifndef _KGSSAPI_GSSAPI_H_
#define _KGSSAPI_GSSAPI_H_
/*
* A cut-down version of the GSS-API for in-kernel use
*/
/*
* Now define the three implementation-dependent types.
*/
typedef struct _gss_ctx_id_t *gss_ctx_id_t;
typedef struct _gss_cred_id_t *gss_cred_id_t;
typedef struct _gss_name_t *gss_name_t;
/*
* We can't use X/Open definitions, so roll our own.
*/
typedef uint32_t OM_uint32;
typedef uint64_t OM_uint64;
typedef struct gss_OID_desc_struct {
OM_uint32 length;
void *elements;
} gss_OID_desc, *gss_OID;
typedef struct gss_OID_set_desc_struct {
size_t count;
gss_OID elements;
} gss_OID_set_desc, *gss_OID_set;
typedef struct gss_buffer_desc_struct {
size_t length;
void *value;
} gss_buffer_desc, *gss_buffer_t;
typedef struct gss_channel_bindings_struct {
OM_uint32 initiator_addrtype;
gss_buffer_desc initiator_address;
OM_uint32 acceptor_addrtype;
gss_buffer_desc acceptor_address;
gss_buffer_desc application_data;
} *gss_channel_bindings_t;
/*
* For now, define a QOP-type as an OM_uint32
*/
typedef OM_uint32 gss_qop_t;
typedef int gss_cred_usage_t;
/*
* Flag bits for context-level services.
*/
#define GSS_C_DELEG_FLAG 1
#define GSS_C_MUTUAL_FLAG 2
#define GSS_C_REPLAY_FLAG 4
#define GSS_C_SEQUENCE_FLAG 8
#define GSS_C_CONF_FLAG 16
#define GSS_C_INTEG_FLAG 32
#define GSS_C_ANON_FLAG 64
#define GSS_C_PROT_READY_FLAG 128
#define GSS_C_TRANS_FLAG 256
/*
* Credential usage options
*/
#define GSS_C_BOTH 0
#define GSS_C_INITIATE 1
#define GSS_C_ACCEPT 2
/*
* Status code types for gss_display_status
*/
#define GSS_C_GSS_CODE 1
#define GSS_C_MECH_CODE 2
/*
* The constant definitions for channel-bindings address families
*/
#define GSS_C_AF_UNSPEC 0
#define GSS_C_AF_LOCAL 1
#define GSS_C_AF_INET 2
#define GSS_C_AF_IMPLINK 3
#define GSS_C_AF_PUP 4
#define GSS_C_AF_CHAOS 5
#define GSS_C_AF_NS 6
#define GSS_C_AF_NBS 7
#define GSS_C_AF_ECMA 8
#define GSS_C_AF_DATAKIT 9
#define GSS_C_AF_CCITT 10
#define GSS_C_AF_SNA 11
#define GSS_C_AF_DECnet 12
#define GSS_C_AF_DLI 13
#define GSS_C_AF_LAT 14
#define GSS_C_AF_HYLINK 15
#define GSS_C_AF_APPLETALK 16
#define GSS_C_AF_BSC 17
#define GSS_C_AF_DSS 18
#define GSS_C_AF_OSI 19
#define GSS_C_AF_X25 21
#define GSS_C_AF_NULLADDR 255
/*
* Various Null values
*/
#define GSS_C_NO_NAME ((gss_name_t) 0)
#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
#define GSS_C_NO_OID ((gss_OID) 0)
#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
#define GSS_C_EMPTY_BUFFER {0, NULL}
/*
* Some alternate names for a couple of the above
* values. These are defined for V1 compatibility.
*/
#define GSS_C_NULL_OID GSS_C_NO_OID
#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
/*
* Define the default Quality of Protection for per-message
* services. Note that an implementation that offers multiple
* levels of QOP may define GSS_C_QOP_DEFAULT to be either zero
* (as done here) to mean "default protection", or to a specific
* explicit QOP value. However, a value of 0 should always be
* interpreted by a GSS-API implementation as a request for the
* default protection level.
*/
#define GSS_C_QOP_DEFAULT 0
/*
* Expiration time of 2^32-1 seconds means infinite lifetime for a
* credential or security context
*/
#define GSS_C_INDEFINITE 0xfffffffful
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x01"},
* corresponding to an object-identifier value of
* {iso(1) member-body(2) United States(840) mit(113554)
* infosys(1) gssapi(2) generic(1) user_name(1)}. The constant
* GSS_C_NT_USER_NAME should be initialized to point
* to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_USER_NAME;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x02"},
* corresponding to an object-identifier value of
* {iso(1) member-body(2) United States(840) mit(113554)
* infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
* The constant GSS_C_NT_MACHINE_UID_NAME should be
* initialized to point to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x03"},
* corresponding to an object-identifier value of
* {iso(1) member-body(2) United States(840) mit(113554)
* infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
* The constant GSS_C_NT_STRING_UID_NAME should be
* initialized to point to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_STRING_UID_NAME;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
* corresponding to an object-identifier value of
* {iso(1) org(3) dod(6) internet(1) security(5)
* nametypes(6) gss-host-based-services(2)). The constant
* GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
* to that gss_OID_desc. This is a deprecated OID value, and
* implementations wishing to support hostbased-service names
* should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
* defined below, to identify such names;
* GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
* for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
* parameter, but should not be emitted by GSS-API
* implementations
*/
extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
* "\x01\x02\x01\x04"}, corresponding to an
* object-identifier value of {iso(1) member-body(2)
* Unites States(840) mit(113554) infosys(1) gssapi(2)
* generic(1) service_name(4)}. The constant
* GSS_C_NT_HOSTBASED_SERVICE should be initialized
* to point to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {6, (void *)"\x2b\x06\01\x05\x06\x03"},
* corresponding to an object identifier value of
* {1(iso), 3(org), 6(dod), 1(internet), 5(security),
* 6(nametypes), 3(gss-anonymous-name)}. The constant
* and GSS_C_NT_ANONYMOUS should be initialized to point
* to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_ANONYMOUS;
/*
* The implementation must reserve static storage for a
* gss_OID_desc object containing the value
* {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
* corresponding to an object-identifier value of
* {1(iso), 3(org), 6(dod), 1(internet), 5(security),
* 6(nametypes), 4(gss-api-exported-name)}. The constant
* GSS_C_NT_EXPORT_NAME should be initialized to point
* to that gss_OID_desc.
*/
extern gss_OID GSS_C_NT_EXPORT_NAME;
/*
* This name form shall be represented by the Object Identifier {iso(1)
* member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
* krb5(2) krb5_name(1)}. The recommended symbolic name for this type
* is "GSS_KRB5_NT_PRINCIPAL_NAME".
*/
extern gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
/*
* This name form shall be represented by the Object Identifier {iso(1)
* member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
* generic(1) user_name(1)}. The recommended symbolic name for this
* type is "GSS_KRB5_NT_USER_NAME".
*/
extern gss_OID GSS_KRB5_NT_USER_NAME;
/*
* This name form shall be represented by the Object Identifier {iso(1)
* member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
* generic(1) machine_uid_name(2)}. The recommended symbolic name for
* this type is "GSS_KRB5_NT_MACHINE_UID_NAME".
*/
extern gss_OID GSS_KRB5_NT_MACHINE_UID_NAME;
/*
* This name form shall be represented by the Object Identifier {iso(1)
* member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
* generic(1) string_uid_name(3)}. The recommended symbolic name for
* this type is "GSS_KRB5_NT_STRING_UID_NAME".
*/
extern gss_OID GSS_KRB5_NT_STRING_UID_NAME;
/* Major status codes */
#define GSS_S_COMPLETE 0
/*
* Some "helper" definitions to make the status code macros obvious.
*/
#define GSS_C_CALLING_ERROR_OFFSET 24
#define GSS_C_ROUTINE_ERROR_OFFSET 16
#define GSS_C_SUPPLEMENTARY_OFFSET 0
#define GSS_C_CALLING_ERROR_MASK 0377ul
#define GSS_C_ROUTINE_ERROR_MASK 0377ul
#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
/*
* The macros that test status codes for error conditions.
* Note that the GSS_ERROR() macro has changed slightly from
* the V1 GSS-API so that it now evaluates its argument
* only once.
*/
#define GSS_CALLING_ERROR(x) \
(x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
#define GSS_ROUTINE_ERROR(x) \
(x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
#define GSS_SUPPLEMENTARY_INFO(x) \
(x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
#define GSS_ERROR(x) \
(x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
(GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
/*
* Now the actual status code definitions
*/
/*
* Calling errors:
*/
#define GSS_S_CALL_INACCESSIBLE_READ \
(1ul << GSS_C_CALLING_ERROR_OFFSET)
#define GSS_S_CALL_INACCESSIBLE_WRITE \
(2ul << GSS_C_CALLING_ERROR_OFFSET)
#define GSS_S_CALL_BAD_STRUCTURE \
(3ul << GSS_C_CALLING_ERROR_OFFSET)
/*
* Routine errors:
*/
#define GSS_S_BAD_MECH (1ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_NAME (2ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_NAMETYPE (3ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_BINDINGS (4ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_STATUS (5ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_SIG (6ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_MIC GSS_S_BAD_SIG
#define GSS_S_NO_CRED (7ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_NO_CONTEXT (8ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_DEFECTIVE_TOKEN (9ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_CREDENTIALS_EXPIRED (11ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_CONTEXT_EXPIRED (12ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_FAILURE (13ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_BAD_QOP (14ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_UNAUTHORIZED (15ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_UNAVAILABLE (16ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_DUPLICATE_ELEMENT (17ul << GSS_C_ROUTINE_ERROR_OFFSET)
#define GSS_S_NAME_NOT_MN (18ul << GSS_C_ROUTINE_ERROR_OFFSET)
/*
* Supplementary info bits:
*/
#define GSS_S_CONTINUE_NEEDED \
(1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
#define GSS_S_DUPLICATE_TOKEN \
(1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
#define GSS_S_OLD_TOKEN \
(1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
#define GSS_S_UNSEQ_TOKEN \
(1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
#define GSS_S_GAP_TOKEN \
(1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
__BEGIN_DECLS
/*
* Finally, function prototypes for the GSS-API routines.
*/
OM_uint32 gss_acquire_cred
(OM_uint32 *, /* minor_status */
const gss_name_t, /* desired_name */
OM_uint32, /* time_req */
const gss_OID_set, /* desired_mechs */
gss_cred_usage_t, /* cred_usage */
gss_cred_id_t *, /* output_cred_handle */
gss_OID_set *, /* actual_mechs */
OM_uint32 * /* time_rec */
);
OM_uint32 gss_release_cred
(OM_uint32 *, /* minor_status */
gss_cred_id_t * /* cred_handle */
);
OM_uint32 gss_init_sec_context
(OM_uint32 *, /* minor_status */
const gss_cred_id_t, /* initiator_cred_handle */
gss_ctx_id_t *, /* context_handle */
const gss_name_t, /* target_name */
const gss_OID, /* mech_type */
OM_uint32, /* req_flags */
OM_uint32, /* time_req */
const gss_channel_bindings_t,
/* input_chan_bindings */
const gss_buffer_t, /* input_token */
gss_OID *, /* actual_mech_type */
gss_buffer_t, /* output_token */
OM_uint32 *, /* ret_flags */
OM_uint32 * /* time_rec */
);
OM_uint32 gss_accept_sec_context
(OM_uint32 *, /* minor_status */
gss_ctx_id_t *, /* context_handle */
const gss_cred_id_t, /* acceptor_cred_handle */
const gss_buffer_t, /* input_token_buffer */
const gss_channel_bindings_t,
/* input_chan_bindings */
gss_name_t *, /* src_name */
gss_OID *, /* mech_type */
gss_buffer_t, /* output_token */
OM_uint32 *, /* ret_flags */
OM_uint32 *, /* time_rec */
gss_cred_id_t * /* delegated_cred_handle */
);
OM_uint32 gss_delete_sec_context
(OM_uint32 *, /* minor_status */
gss_ctx_id_t *, /* context_handle */
gss_buffer_t /* output_token */
);
OM_uint32 gss_get_mic
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
gss_qop_t, /* qop_req */
const gss_buffer_t, /* message_buffer */
gss_buffer_t /* message_token */
);
OM_uint32 gss_verify_mic
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
const gss_buffer_t, /* message_buffer */
const gss_buffer_t, /* token_buffer */
gss_qop_t * /* qop_state */
);
OM_uint32 gss_wrap
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
gss_qop_t, /* qop_req */
const gss_buffer_t, /* input_message_buffer */
int *, /* conf_state */
gss_buffer_t /* output_message_buffer */
);
OM_uint32 gss_unwrap
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
const gss_buffer_t, /* input_message_buffer */
gss_buffer_t, /* output_message_buffer */
int *, /* conf_state */
gss_qop_t * /* qop_state */
);
OM_uint32 gss_display_status
(OM_uint32 *, /* minor_status */
OM_uint32, /* status_value */
int, /* status_type */
const gss_OID, /* mech_type */
OM_uint32 *, /* message_context */
gss_buffer_t /* status_string */
);
OM_uint32 gss_import_name
(OM_uint32 *, /* minor_status */
const gss_buffer_t, /* input_name_buffer */
const gss_OID, /* input_name_type */
gss_name_t * /* output_name */
);
OM_uint32 gss_export_name
(OM_uint32 *, /* minor_status */
const gss_name_t, /* input_name */
gss_buffer_t /* exported_name */
);
OM_uint32 gss_release_name
(OM_uint32 *, /* minor_status */
gss_name_t * /* input_name */
);
OM_uint32 gss_release_buffer
(OM_uint32 *, /* minor_status */
gss_buffer_t /* buffer */
);
OM_uint32 gss_release_oid_set
(OM_uint32 *, /* minor_status */
gss_OID_set * /* set */
);
OM_uint32 gss_wrap_size_limit (
OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
gss_qop_t, /* qop_req */
OM_uint32, /* req_output_size */
OM_uint32 * /* max_input_size */
);
OM_uint32 gss_create_empty_oid_set (
OM_uint32 *, /* minor_status */
gss_OID_set * /* oid_set */
);
OM_uint32 gss_add_oid_set_member (
OM_uint32 *, /* minor_status */
const gss_OID, /* member_oid */
gss_OID_set * /* oid_set */
);
OM_uint32 gss_test_oid_set_member (
OM_uint32 *, /* minor_status */
const gss_OID, /* member */
const gss_OID_set, /* set */
int * /* present */
);
OM_uint32 gss_canonicalize_name (
OM_uint32 *, /* minor_status */
const gss_name_t, /* input_name */
const gss_OID, /* mech_type */
gss_name_t * /* output_name */
);
/*
* Other extensions and helper functions.
*/
OM_uint32 gss_set_cred_option
(OM_uint32 *, /* minor status */
gss_cred_id_t *, /* cred */
const gss_OID, /* option to set */
const gss_buffer_t /* option value */
);
OM_uint32 gss_pname_to_uid
(OM_uint32 *, /* minor status */
const gss_name_t pname, /* principal name */
const gss_OID mech, /* mechanism to query */
uid_t *uidp /* pointer to UID for result */
);
/*
* On entry, *numgroups is set to the maximum number of groups to return. On exit, *numgroups is set to the actual number of groups returned.
*/
OM_uint32 gss_pname_to_unix_cred
(OM_uint32 *, /* minor status */
const gss_name_t pname, /* principal name */
const gss_OID mech, /* mechanism to query */
uid_t *uidp, /* pointer to UID for result */
gid_t *gidp, /* pointer to GID for result */
int *numgroups, /* number of groups */
gid_t *groups /* pointer to group list */
);
/*
* Mbuf oriented message signing and encryption.
*
* Get_mic allocates an mbuf to hold the message checksum. Verify_mic
* may modify the passed-in mic but will not free it.
*
* Wrap and unwrap
* consume the message and generate a new mbuf chain with the
* result. The original message is freed on error.
*/
struct mbuf;
OM_uint32 gss_get_mic_mbuf
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
gss_qop_t, /* qop_req */
struct mbuf *, /* message_buffer */
struct mbuf ** /* message_token */
);
OM_uint32 gss_verify_mic_mbuf
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
struct mbuf *, /* message_buffer */
struct mbuf *, /* token_buffer */
gss_qop_t * /* qop_state */
);
OM_uint32 gss_wrap_mbuf
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
int, /* conf_req_flag */
gss_qop_t, /* qop_req */
struct mbuf **, /* message_buffer */
int * /* conf_state */
);
OM_uint32 gss_unwrap_mbuf
(OM_uint32 *, /* minor_status */
const gss_ctx_id_t, /* context_handle */
struct mbuf **, /* message_buffer */
int *, /* conf_state */
gss_qop_t * /* qop_state */
);
__END_DECLS
#endif /* _KGSSAPI_GSSAPI_H_ */

366
freebsd/sys/rpc/auth.h Normal file
View File

@ -0,0 +1,366 @@
/* $NetBSD: auth.h,v 1.15 2000/06/02 22:57:55 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)auth.h 1.17 88/02/08 SMI
* from: @(#)auth.h 2.3 88/08/07 4.0 RPCSRC
* from: @(#)auth.h 1.43 98/02/02 SMI
* $FreeBSD$
*/
/*
* auth.h, Authentication interface.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* The data structures are completely opaque to the client. The client
* is required to pass an AUTH * to routines that create rpc
* "sessions".
*/
#ifndef _RPC_AUTH_H
#define _RPC_AUTH_H
#include <rpc/xdr.h>
#include <rpc/clnt_stat.h>
#include <sys/cdefs.h>
#include <sys/socket.h>
#define MAX_AUTH_BYTES 400
#define MAXNETNAMELEN 255 /* maximum length of network user's name */
/*
* Client side authentication/security data
*/
typedef struct sec_data {
u_int secmod; /* security mode number e.g. in nfssec.conf */
u_int rpcflavor; /* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */
int flags; /* AUTH_F_xxx flags */
caddr_t data; /* opaque data per flavor */
} sec_data_t;
#ifdef _SYSCALL32_IMPL
struct sec_data32 {
uint32_t secmod; /* security mode number e.g. in nfssec.conf */
uint32_t rpcflavor; /* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */
int32_t flags; /* AUTH_F_xxx flags */
caddr32_t data; /* opaque data per flavor */
};
#endif /* _SYSCALL32_IMPL */
/*
* AUTH_DES flavor specific data from sec_data opaque data field.
* AUTH_KERB has the same structure.
*/
typedef struct des_clnt_data {
struct netbuf syncaddr; /* time sync addr */
struct knetconfig *knconf; /* knetconfig info that associated */
/* with the syncaddr. */
char *netname; /* server's netname */
int netnamelen; /* server's netname len */
} dh_k4_clntdata_t;
#ifdef _SYSCALL32_IMPL
struct des_clnt_data32 {
struct netbuf32 syncaddr; /* time sync addr */
caddr32_t knconf; /* knetconfig info that associated */
/* with the syncaddr. */
caddr32_t netname; /* server's netname */
int32_t netnamelen; /* server's netname len */
};
#endif /* _SYSCALL32_IMPL */
#ifdef KERBEROS
/*
* flavor specific data to hold the data for AUTH_DES/AUTH_KERB(v4)
* in sec_data->data opaque field.
*/
typedef struct krb4_svc_data {
int window; /* window option value */
} krb4_svcdata_t;
typedef struct krb4_svc_data des_svcdata_t;
#endif /* KERBEROS */
/*
* authentication/security specific flags
*/
#define AUTH_F_RPCTIMESYNC 0x001 /* use RPC to do time sync */
#define AUTH_F_TRYNONE 0x002 /* allow fall back to AUTH_NONE */
/*
* Status returned from authentication check
*/
enum auth_stat {
AUTH_OK=0,
/*
* failed at remote end
*/
AUTH_BADCRED=1, /* bogus credentials (seal broken) */
AUTH_REJECTEDCRED=2, /* client should begin new session */
AUTH_BADVERF=3, /* bogus verifier (seal broken) */
AUTH_REJECTEDVERF=4, /* verifier expired or was replayed */
AUTH_TOOWEAK=5, /* rejected due to security reasons */
/*
* failed locally
*/
AUTH_INVALIDRESP=6, /* bogus response verifier */
AUTH_FAILED=7, /* some unknown reason */
#ifdef KERBEROS
/*
* kerberos errors
*/
,
AUTH_KERB_GENERIC = 8, /* kerberos generic error */
AUTH_TIMEEXPIRE = 9, /* time of credential expired */
AUTH_TKT_FILE = 10, /* something wrong with ticket file */
AUTH_DECODE = 11, /* can't decode authenticator */
AUTH_NET_ADDR = 12, /* wrong net address in ticket */
#endif /* KERBEROS */
/*
* RPCSEC_GSS errors
*/
RPCSEC_GSS_CREDPROBLEM = 13,
RPCSEC_GSS_CTXPROBLEM = 14,
RPCSEC_GSS_NODISPATCH = 0x8000000
};
union des_block {
struct {
uint32_t high;
uint32_t low;
} key;
char c[8];
};
typedef union des_block des_block;
__BEGIN_DECLS
extern bool_t xdr_des_block(XDR *, des_block *);
__END_DECLS
/*
* Authentication info. Opaque to client.
*/
struct opaque_auth {
enum_t oa_flavor; /* flavor of auth */
caddr_t oa_base; /* address of more auth stuff */
u_int oa_length; /* not to exceed MAX_AUTH_BYTES */
};
/*
* Auth handle, interface to client side authenticators.
*/
struct rpc_err;
typedef struct __auth {
struct opaque_auth ah_cred;
struct opaque_auth ah_verf;
union des_block ah_key;
struct auth_ops {
void (*ah_nextverf) (struct __auth *);
/* nextverf & serialize */
int (*ah_marshal) (struct __auth *, uint32_t, XDR *,
struct mbuf *);
/* validate verifier */
int (*ah_validate) (struct __auth *, uint32_t,
struct opaque_auth *, struct mbuf **);
/* refresh credentials */
int (*ah_refresh) (struct __auth *, void *);
/* destroy this structure */
void (*ah_destroy) (struct __auth *);
} *ah_ops;
void *ah_private;
} AUTH;
/*
* Authentication ops.
* The ops and the auth handle provide the interface to the authenticators.
*
* AUTH *auth;
* XDR *xdrs;
* struct opaque_auth verf;
*/
#define AUTH_NEXTVERF(auth) \
((*((auth)->ah_ops->ah_nextverf))(auth))
#define AUTH_MARSHALL(auth, xid, xdrs, args) \
((*((auth)->ah_ops->ah_marshal))(auth, xid, xdrs, args))
#define AUTH_VALIDATE(auth, xid, verfp, resultsp) \
((*((auth)->ah_ops->ah_validate))((auth), xid, verfp, resultsp))
#define AUTH_REFRESH(auth, msg) \
((*((auth)->ah_ops->ah_refresh))(auth, msg))
#define AUTH_DESTROY(auth) \
((*((auth)->ah_ops->ah_destroy))(auth))
__BEGIN_DECLS
extern struct opaque_auth _null_auth;
__END_DECLS
/*
* These are the various implementations of client side authenticators.
*/
/*
* System style authentication
* AUTH *authunix_create(machname, uid, gid, len, aup_gids)
* char *machname;
* u_int uid;
* u_int gid;
* int len;
* u_int *aup_gids;
*/
__BEGIN_DECLS
#ifdef _KERNEL
struct ucred;
extern AUTH *authunix_create(struct ucred *);
#else
extern AUTH *authunix_create(char *, u_int, u_int, int, u_int *);
extern AUTH *authunix_create_default(void); /* takes no parameters */
#endif
extern AUTH *authnone_create(void); /* takes no parameters */
__END_DECLS
/*
* DES style authentication
* AUTH *authsecdes_create(servername, window, timehost, ckey)
* char *servername; - network name of server
* u_int window; - time to live
* const char *timehost; - optional hostname to sync with
* des_block *ckey; - optional conversation key to use
*/
__BEGIN_DECLS
extern AUTH *authdes_create (char *, u_int, struct sockaddr *, des_block *);
extern AUTH *authdes_seccreate (const char *, const u_int, const char *,
const des_block *);
__END_DECLS
__BEGIN_DECLS
extern bool_t xdr_opaque_auth (XDR *, struct opaque_auth *);
__END_DECLS
#define authsys_create(c,i1,i2,i3,ip) authunix_create((c),(i1),(i2),(i3),(ip))
#define authsys_create_default() authunix_create_default()
/*
* Netname manipulation routines.
*/
__BEGIN_DECLS
extern int getnetname(char *);
extern int host2netname(char *, const char *, const char *);
extern int user2netname(char *, const uid_t, const char *);
extern int netname2user(char *, uid_t *, gid_t *, int *, gid_t *);
extern int netname2host(char *, char *, const int);
extern void passwd2des ( char *, char * );
__END_DECLS
/*
*
* These routines interface to the keyserv daemon
*
*/
__BEGIN_DECLS
extern int key_decryptsession(const char *, des_block *);
extern int key_encryptsession(const char *, des_block *);
extern int key_gendes(des_block *);
extern int key_setsecret(const char *);
extern int key_secretkey_is_set(void);
__END_DECLS
/*
* Publickey routines.
*/
__BEGIN_DECLS
extern int getpublickey (const char *, char *);
extern int getpublicandprivatekey (const char *, char *);
extern int getsecretkey (char *, char *, char *);
__END_DECLS
#ifdef KERBEROS
/*
* Kerberos style authentication
* AUTH *authkerb_seccreate(service, srv_inst, realm, window, timehost, status)
* const char *service; - service name
* const char *srv_inst; - server instance
* const char *realm; - server realm
* const u_int window; - time to live
* const char *timehost; - optional hostname to sync with
* int *status; - kerberos status returned
*/
__BEGIN_DECLS
extern AUTH *authkerb_seccreate(const char *, const char *, const char *,
const u_int, const char *, int *);
__END_DECLS
/*
* Map a kerberos credential into a unix cred.
*
* authkerb_getucred(rqst, uid, gid, grouplen, groups)
* const struct svc_req *rqst; - request pointer
* uid_t *uid;
* gid_t *gid;
* short *grouplen;
* int *groups;
*
*/
__BEGIN_DECLS
extern int authkerb_getucred(/* struct svc_req *, uid_t *, gid_t *,
short *, int * */);
__END_DECLS
#endif /* KERBEROS */
__BEGIN_DECLS
struct svc_req;
struct rpc_msg;
enum auth_stat _svcauth_null (struct svc_req *, struct rpc_msg *);
enum auth_stat _svcauth_short (struct svc_req *, struct rpc_msg *);
enum auth_stat _svcauth_unix (struct svc_req *, struct rpc_msg *);
__END_DECLS
#define AUTH_NONE 0 /* no authentication */
#define AUTH_NULL 0 /* backward compatibility */
#define AUTH_SYS 1 /* unix style (uid, gids) */
#define AUTH_UNIX AUTH_SYS
#define AUTH_SHORT 2 /* short hand unix style */
#define AUTH_DH 3 /* for Diffie-Hellman mechanism */
#define AUTH_DES AUTH_DH /* for backward compatibility */
#define AUTH_KERB 4 /* kerberos style */
#define RPCSEC_GSS 6 /* RPCSEC_GSS */
/*
* Pseudo auth flavors for RPCSEC_GSS.
*/
#define RPCSEC_GSS_KRB5 390003
#define RPCSEC_GSS_KRB5I 390004
#define RPCSEC_GSS_KRB5P 390005
#endif /* !_RPC_AUTH_H */

157
freebsd/sys/rpc/auth_none.c Normal file
View File

@ -0,0 +1,157 @@
/* $NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* auth_none.c
* Creates a client authentication handle for passing "null"
* credentials and verifiers to remote systems.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#define MAX_MARSHAL_SIZE 20
/*
* Authenticator operations routines
*/
static bool_t authnone_marshal (AUTH *, uint32_t, XDR *, struct mbuf *);
static void authnone_verf (AUTH *);
static bool_t authnone_validate (AUTH *, uint32_t, struct opaque_auth *,
struct mbuf **);
static bool_t authnone_refresh (AUTH *, void *);
static void authnone_destroy (AUTH *);
static struct auth_ops authnone_ops = {
.ah_nextverf = authnone_verf,
.ah_marshal = authnone_marshal,
.ah_validate = authnone_validate,
.ah_refresh = authnone_refresh,
.ah_destroy = authnone_destroy,
};
struct authnone_private {
AUTH no_client;
char mclient[MAX_MARSHAL_SIZE];
u_int mcnt;
};
static struct authnone_private authnone_private;
static void
authnone_init(void *dummy)
{
struct authnone_private *ap = &authnone_private;
XDR xdrs;
ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth;
ap->no_client.ah_ops = &authnone_ops;
xdrmem_create(&xdrs, ap->mclient, MAX_MARSHAL_SIZE, XDR_ENCODE);
xdr_opaque_auth(&xdrs, &ap->no_client.ah_cred);
xdr_opaque_auth(&xdrs, &ap->no_client.ah_verf);
ap->mcnt = XDR_GETPOS(&xdrs);
XDR_DESTROY(&xdrs);
}
SYSINIT(authnone_init, SI_SUB_KMEM, SI_ORDER_ANY, authnone_init, NULL);
AUTH *
authnone_create()
{
struct authnone_private *ap = &authnone_private;
return (&ap->no_client);
}
/*ARGSUSED*/
static bool_t
authnone_marshal(AUTH *client, uint32_t xid, XDR *xdrs, struct mbuf *args)
{
struct authnone_private *ap = &authnone_private;
KASSERT(xdrs != NULL, ("authnone_marshal: xdrs is null"));
if (!XDR_PUTBYTES(xdrs, ap->mclient, ap->mcnt))
return (FALSE);
xdrmbuf_append(xdrs, args);
return (TRUE);
}
/* All these unused parameters are required to keep ANSI-C from grumbling */
/*ARGSUSED*/
static void
authnone_verf(AUTH *client)
{
}
/*ARGSUSED*/
static bool_t
authnone_validate(AUTH *client, uint32_t xid, struct opaque_auth *opaque,
struct mbuf **mrepp)
{
return (TRUE);
}
/*ARGSUSED*/
static bool_t
authnone_refresh(AUTH *client, void *dummy)
{
return (FALSE);
}
/*ARGSUSED*/
static void
authnone_destroy(AUTH *client)
{
}

380
freebsd/sys/rpc/auth_unix.c Normal file
View File

@ -0,0 +1,380 @@
/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* auth_unix.c, Implements UNIX style authentication parameters.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* The system is very weak. The client uses no encryption for it's
* credentials and only sends null verifiers. The server sends backs
* null verifiers or optionally a verifier that suggests a new short hand
* for the credentials.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/pcpu.h>
#include <sys/refcount.h>
#include <sys/sx.h>
#include <sys/ucred.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include <rpc/rpc_com.h>
/* auth_unix.c */
static void authunix_nextverf (AUTH *);
static bool_t authunix_marshal (AUTH *, uint32_t, XDR *, struct mbuf *);
static bool_t authunix_validate (AUTH *, uint32_t, struct opaque_auth *,
struct mbuf **);
static bool_t authunix_refresh (AUTH *, void *);
static void authunix_destroy (AUTH *);
static void marshal_new_auth (AUTH *);
static struct auth_ops authunix_ops = {
.ah_nextverf = authunix_nextverf,
.ah_marshal = authunix_marshal,
.ah_validate = authunix_validate,
.ah_refresh = authunix_refresh,
.ah_destroy = authunix_destroy,
};
/*
* This struct is pointed to by the ah_private field of an auth_handle.
*/
struct audata {
TAILQ_ENTRY(audata) au_link;
TAILQ_ENTRY(audata) au_alllink;
volatile u_int au_refs;
struct xucred au_xcred;
struct opaque_auth au_origcred; /* original credentials */
struct opaque_auth au_shcred; /* short hand cred */
u_long au_shfaults; /* short hand cache faults */
char au_marshed[MAX_AUTH_BYTES];
u_int au_mpos; /* xdr pos at end of marshed */
AUTH *au_auth; /* link back to AUTH */
};
TAILQ_HEAD(audata_list, audata);
#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
#define AUTH_UNIX_HASH_SIZE 16
#define AUTH_UNIX_MAX 256
static struct audata_list auth_unix_cache[AUTH_UNIX_HASH_SIZE];
static struct audata_list auth_unix_all;
static struct sx auth_unix_lock;
static int auth_unix_count;
static void
authunix_init(void *dummy)
{
int i;
for (i = 0; i < AUTH_UNIX_HASH_SIZE; i++)
TAILQ_INIT(&auth_unix_cache[i]);
TAILQ_INIT(&auth_unix_all);
sx_init(&auth_unix_lock, "auth_unix_lock");
}
SYSINIT(authunix_init, SI_SUB_KMEM, SI_ORDER_ANY, authunix_init, NULL);
/*
* Create a unix style authenticator.
* Returns an auth handle with the given stuff in it.
*/
AUTH *
authunix_create(struct ucred *cred)
{
uint32_t h, th;
struct xucred xcr;
char mymem[MAX_AUTH_BYTES];
XDR xdrs;
AUTH *auth;
struct audata *au, *tau;
struct timeval now;
uint32_t time;
int len;
if (auth_unix_count > AUTH_UNIX_MAX) {
while (auth_unix_count > AUTH_UNIX_MAX) {
sx_xlock(&auth_unix_lock);
tau = TAILQ_FIRST(&auth_unix_all);
th = HASHSTEP(HASHINIT, tau->au_xcred.cr_uid)
% AUTH_UNIX_HASH_SIZE;
TAILQ_REMOVE(&auth_unix_cache[th], tau, au_link);
TAILQ_REMOVE(&auth_unix_all, tau, au_alllink);
auth_unix_count--;
sx_xunlock(&auth_unix_lock);
AUTH_DESTROY(tau->au_auth);
}
}
/*
* Hash the uid to see if we already have an AUTH with this cred.
*/
h = HASHSTEP(HASHINIT, cred->cr_uid) % AUTH_UNIX_HASH_SIZE;
cru2x(cred, &xcr);
again:
sx_slock(&auth_unix_lock);
TAILQ_FOREACH(au, &auth_unix_cache[h], au_link) {
if (!memcmp(&xcr, &au->au_xcred, sizeof(xcr))) {
refcount_acquire(&au->au_refs);
if (sx_try_upgrade(&auth_unix_lock)) {
/*
* Keep auth_unix_all LRU sorted.
*/
TAILQ_REMOVE(&auth_unix_all, au, au_alllink);
TAILQ_INSERT_TAIL(&auth_unix_all, au,
au_alllink);
sx_xunlock(&auth_unix_lock);
} else {
sx_sunlock(&auth_unix_lock);
}
return (au->au_auth);
}
}
sx_sunlock(&auth_unix_lock);
/*
* Allocate and set up auth handle
*/
au = NULL;
auth = mem_alloc(sizeof(*auth));
au = mem_alloc(sizeof(*au));
auth->ah_ops = &authunix_ops;
auth->ah_private = (caddr_t)au;
auth->ah_verf = au->au_shcred = _null_auth;
refcount_init(&au->au_refs, 1);
au->au_xcred = xcr;
au->au_shfaults = 0;
au->au_origcred.oa_base = NULL;
au->au_auth = auth;
getmicrotime(&now);
time = now.tv_sec;
/*
* Serialize the parameters into origcred
*/
xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
cru2x(cred, &xcr);
if (! xdr_authunix_parms(&xdrs, &time, &xcr))
panic("authunix_create: failed to encode creds");
au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
au->au_origcred.oa_flavor = AUTH_UNIX;
au->au_origcred.oa_base = mem_alloc((u_int) len);
memcpy(au->au_origcred.oa_base, mymem, (size_t)len);
/*
* set auth handle to reflect new cred.
*/
auth->ah_cred = au->au_origcred;
marshal_new_auth(auth);
sx_xlock(&auth_unix_lock);
TAILQ_FOREACH(tau, &auth_unix_cache[h], au_link) {
if (!memcmp(&xcr, &tau->au_xcred, sizeof(xcr))) {
/*
* We lost a race to create the AUTH that
* matches this cred.
*/
sx_xunlock(&auth_unix_lock);
AUTH_DESTROY(auth);
goto again;
}
}
auth_unix_count++;
TAILQ_INSERT_TAIL(&auth_unix_cache[h], au, au_link);
TAILQ_INSERT_TAIL(&auth_unix_all, au, au_alllink);
refcount_acquire(&au->au_refs); /* one for the cache, one for user */
sx_xunlock(&auth_unix_lock);
return (auth);
}
/*
* authunix operations
*/
/* ARGSUSED */
static void
authunix_nextverf(AUTH *auth)
{
/* no action necessary */
}
static bool_t
authunix_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args)
{
struct audata *au;
au = AUTH_PRIVATE(auth);
if (!XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos))
return (FALSE);
xdrmbuf_append(xdrs, args);
return (TRUE);
}
static bool_t
authunix_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf,
struct mbuf **mrepp)
{
struct audata *au;
XDR txdrs;
if (!verf)
return (TRUE);
if (verf->oa_flavor == AUTH_SHORT) {
au = AUTH_PRIVATE(auth);
xdrmem_create(&txdrs, verf->oa_base, verf->oa_length,
XDR_DECODE);
if (au->au_shcred.oa_base != NULL) {
mem_free(au->au_shcred.oa_base,
au->au_shcred.oa_length);
au->au_shcred.oa_base = NULL;
}
if (xdr_opaque_auth(&txdrs, &au->au_shcred)) {
auth->ah_cred = au->au_shcred;
} else {
txdrs.x_op = XDR_FREE;
(void)xdr_opaque_auth(&txdrs, &au->au_shcred);
au->au_shcred.oa_base = NULL;
auth->ah_cred = au->au_origcred;
}
marshal_new_auth(auth);
}
return (TRUE);
}
static bool_t
authunix_refresh(AUTH *auth, void *dummy)
{
struct audata *au = AUTH_PRIVATE(auth);
struct xucred xcr;
uint32_t time;
struct timeval now;
XDR xdrs;
int stat;
if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
/* there is no hope. Punt */
return (FALSE);
}
au->au_shfaults ++;
/* first deserialize the creds back into a struct ucred */
xdrmem_create(&xdrs, au->au_origcred.oa_base,
au->au_origcred.oa_length, XDR_DECODE);
stat = xdr_authunix_parms(&xdrs, &time, &xcr);
if (! stat)
goto done;
/* update the time and serialize in place */
getmicrotime(&now);
time = now.tv_sec;
xdrs.x_op = XDR_ENCODE;
XDR_SETPOS(&xdrs, 0);
stat = xdr_authunix_parms(&xdrs, &time, &xcr);
if (! stat)
goto done;
auth->ah_cred = au->au_origcred;
marshal_new_auth(auth);
done:
XDR_DESTROY(&xdrs);
return (stat);
}
static void
authunix_destroy(AUTH *auth)
{
struct audata *au;
au = AUTH_PRIVATE(auth);
if (!refcount_release(&au->au_refs))
return;
mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
if (au->au_shcred.oa_base != NULL)
mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
mem_free(auth->ah_private, sizeof(struct audata));
if (auth->ah_verf.oa_base != NULL)
mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
mem_free(auth, sizeof(*auth));
}
/*
* Marshals (pre-serializes) an auth struct.
* sets private data, au_marshed and au_mpos
*/
static void
marshal_new_auth(AUTH *auth)
{
XDR xdr_stream;
XDR *xdrs = &xdr_stream;
struct audata *au;
au = AUTH_PRIVATE(auth);
xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
(! xdr_opaque_auth(xdrs, &(auth->ah_verf))))
printf("auth_none.c - Fatal marshalling problem");
else
au->au_mpos = XDR_GETPOS(xdrs);
XDR_DESTROY(xdrs);
}

View File

@ -0,0 +1,131 @@
/* $NetBSD: authunix_prot.c,v 1.12 2000/01/22 22:19:17 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* authunix_prot.c
* XDR for UNIX style authentication parameters for RPC
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/ucred.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/rpc_com.h>
/* gids compose part of a credential; there may not be more than 16 of them */
#define NGRPS 16
/*
* XDR for unix authentication parameters.
*/
bool_t
xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
{
uint32_t namelen;
uint32_t ngroups, i;
uint32_t junk;
char hostbuf[MAXHOSTNAMELEN];
if (xdrs->x_op == XDR_ENCODE) {
/*
* Restrict name length to 255 according to RFC 1057.
*/
getcredhostname(NULL, hostbuf, sizeof(hostbuf));
namelen = strlen(hostbuf);
if (namelen > 255)
namelen = 255;
} else {
namelen = 0;
}
junk = 0;
if (!xdr_uint32_t(xdrs, time)
|| !xdr_uint32_t(xdrs, &namelen))
return (FALSE);
/*
* Ignore the hostname on decode.
*/
if (xdrs->x_op == XDR_ENCODE) {
if (!xdr_opaque(xdrs, hostbuf, namelen))
return (FALSE);
} else {
xdr_setpos(xdrs, xdr_getpos(xdrs) + RNDUP(namelen));
}
if (!xdr_uint32_t(xdrs, &cred->cr_uid))
return (FALSE);
if (!xdr_uint32_t(xdrs, &cred->cr_groups[0]))
return (FALSE);
if (xdrs->x_op == XDR_ENCODE) {
ngroups = cred->cr_ngroups - 1;
if (ngroups > NGRPS)
ngroups = NGRPS;
}
if (!xdr_uint32_t(xdrs, &ngroups))
return (FALSE);
for (i = 0; i < ngroups; i++) {
if (i + 1 < ngroups_max + 1) {
if (!xdr_uint32_t(xdrs, &cred->cr_groups[i + 1]))
return (FALSE);
} else {
if (!xdr_uint32_t(xdrs, &junk))
return (FALSE);
}
}
if (xdrs->x_op == XDR_DECODE) {
if (ngroups + 1 > ngroups_max + 1)
cred->cr_ngroups = ngroups_max + 1;
else
cred->cr_ngroups = ngroups + 1;
}
return (TRUE);
}

716
freebsd/sys/rpc/clnt.h Normal file
View File

@ -0,0 +1,716 @@
/* $NetBSD: clnt.h,v 1.14 2000/06/02 22:57:55 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of the "Oracle America, Inc." 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)clnt.h 1.31 94/04/29 SMI
* from: @(#)clnt.h 2.1 88/07/29 4.0 RPCSRC
* $FreeBSD$
*/
/*
* clnt.h - Client side remote procedure call interface.
*
* Copyright (c) 1986-1991,1994-1999 by Sun Microsystems, Inc.
* All rights reserved.
*/
#ifndef _RPC_CLNT_H_
#define _RPC_CLNT_H_
#include <rpc/clnt_stat.h>
#include <sys/cdefs.h>
#ifdef _KERNEL
#include <sys/refcount.h>
#include <rpc/netconfig.h>
#else
#include <netconfig.h>
#endif
#include <sys/un.h>
/*
* Well-known IPV6 RPC broadcast address.
*/
#define RPCB_MULTICAST_ADDR "ff02::202"
/*
* the following errors are in general unrecoverable. The caller
* should give up rather than retry.
*/
#define IS_UNRECOVERABLE_RPC(s) (((s) == RPC_AUTHERROR) || \
((s) == RPC_CANTENCODEARGS) || \
((s) == RPC_CANTDECODERES) || \
((s) == RPC_VERSMISMATCH) || \
((s) == RPC_PROCUNAVAIL) || \
((s) == RPC_PROGUNAVAIL) || \
((s) == RPC_PROGVERSMISMATCH) || \
((s) == RPC_CANTDECODEARGS))
/*
* Error info.
*/
struct rpc_err {
enum clnt_stat re_status;
union {
int RE_errno; /* related system error */
enum auth_stat RE_why; /* why the auth error occurred */
struct {
rpcvers_t low; /* lowest version supported */
rpcvers_t high; /* highest version supported */
} RE_vers;
struct { /* maybe meaningful if RPC_FAILED */
int32_t s1;
int32_t s2;
} RE_lb; /* life boot & debugging only */
} ru;
#define re_errno ru.RE_errno
#define re_why ru.RE_why
#define re_vers ru.RE_vers
#define re_lb ru.RE_lb
};
#ifdef _KERNEL
/*
* Functions of this type may be used to receive notification when RPC
* calls have to be re-transmitted etc.
*/
typedef void rpc_feedback(int cmd, int procnum, void *);
/*
* Timers used for the pseudo-transport protocol when using datagrams
*/
struct rpc_timers {
u_short rt_srtt; /* smoothed round-trip time */
u_short rt_deviate; /* estimated deviation */
u_long rt_rtxcur; /* current (backed-off) rto */
};
/*
* A structure used with CLNT_CALL_EXT to pass extra information used
* while processing an RPC call.
*/
struct rpc_callextra {
AUTH *rc_auth; /* auth handle to use for this call */
rpc_feedback *rc_feedback; /* callback for retransmits etc. */
void *rc_feedback_arg; /* argument for callback */
struct rpc_timers *rc_timers; /* optional RTT timers */
struct rpc_err rc_err; /* detailed call status */
};
#endif
/*
* Client rpc handle.
* Created by individual implementations
* Client is responsible for initializing auth, see e.g. auth_none.c.
*/
typedef struct __rpc_client {
#ifdef _KERNEL
volatile u_int cl_refs; /* reference count */
AUTH *cl_auth; /* authenticator */
struct clnt_ops {
/* call remote procedure */
enum clnt_stat (*cl_call)(struct __rpc_client *,
struct rpc_callextra *, rpcproc_t,
struct mbuf *, struct mbuf **, struct timeval);
/* abort a call */
void (*cl_abort)(struct __rpc_client *);
/* get specific error code */
void (*cl_geterr)(struct __rpc_client *,
struct rpc_err *);
/* frees results */
bool_t (*cl_freeres)(struct __rpc_client *,
xdrproc_t, void *);
/* close the connection and terminate pending RPCs */
void (*cl_close)(struct __rpc_client *);
/* destroy this structure */
void (*cl_destroy)(struct __rpc_client *);
/* the ioctl() of rpc */
bool_t (*cl_control)(struct __rpc_client *, u_int,
void *);
} *cl_ops;
#else
AUTH *cl_auth; /* authenticator */
struct clnt_ops {
/* call remote procedure */
enum clnt_stat (*cl_call)(struct __rpc_client *,
rpcproc_t, xdrproc_t, void *, xdrproc_t,
void *, struct timeval);
/* abort a call */
void (*cl_abort)(struct __rpc_client *);
/* get specific error code */
void (*cl_geterr)(struct __rpc_client *,
struct rpc_err *);
/* frees results */
bool_t (*cl_freeres)(struct __rpc_client *,
xdrproc_t, void *);
/* destroy this structure */
void (*cl_destroy)(struct __rpc_client *);
/* the ioctl() of rpc */
bool_t (*cl_control)(struct __rpc_client *, u_int,
void *);
} *cl_ops;
#endif
void *cl_private; /* private stuff */
char *cl_netid; /* network token */
char *cl_tp; /* device name */
} CLIENT;
/*
* Feedback values used for possible congestion and rate control
*/
#define FEEDBACK_OK 1 /* no retransmits */
#define FEEDBACK_REXMIT1 2 /* first retransmit */
#define FEEDBACK_REXMIT2 3 /* second and subsequent retransmit */
#define FEEDBACK_RECONNECT 4 /* client reconnect */
/* Used to set version of portmapper used in broadcast */
#define CLCR_SET_LOWVERS 3
#define CLCR_GET_LOWVERS 4
#define RPCSMALLMSGSIZE 400 /* a more reasonable packet size */
/*
* client side rpc interface ops
*
* Parameter types are:
*
*/
#ifdef _KERNEL
#define CLNT_ACQUIRE(rh) \
refcount_acquire(&(rh)->cl_refs)
#define CLNT_RELEASE(rh) \
if (refcount_release(&(rh)->cl_refs)) \
CLNT_DESTROY(rh)
/*
* void
* CLNT_CLOSE(rh);
* CLIENT *rh;
*/
#define CLNT_CLOSE(rh) ((*(rh)->cl_ops->cl_close)(rh))
enum clnt_stat clnt_call_private(CLIENT *, struct rpc_callextra *, rpcproc_t,
xdrproc_t, void *, xdrproc_t, void *, struct timeval);
/*
* enum clnt_stat
* CLNT_CALL_MBUF(rh, ext, proc, mreq, mrepp, timeout)
* CLIENT *rh;
* struct rpc_callextra *ext;
* rpcproc_t proc;
* struct mbuf *mreq;
* struct mbuf **mrepp;
* struct timeval timeout;
*
* Call arguments in mreq which is consumed by the call (even if there
* is an error). Results returned in *mrepp.
*/
#define CLNT_CALL_MBUF(rh, ext, proc, mreq, mrepp, secs) \
((*(rh)->cl_ops->cl_call)(rh, ext, proc, mreq, mrepp, secs))
/*
* enum clnt_stat
* CLNT_CALL_EXT(rh, ext, proc, xargs, argsp, xres, resp, timeout)
* CLIENT *rh;
* struct rpc_callextra *ext;
* rpcproc_t proc;
* xdrproc_t xargs;
* void *argsp;
* xdrproc_t xres;
* void *resp;
* struct timeval timeout;
*/
#define CLNT_CALL_EXT(rh, ext, proc, xargs, argsp, xres, resp, secs) \
clnt_call_private(rh, ext, proc, xargs, \
argsp, xres, resp, secs)
#endif
/*
* enum clnt_stat
* CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout)
* CLIENT *rh;
* rpcproc_t proc;
* xdrproc_t xargs;
* void *argsp;
* xdrproc_t xres;
* void *resp;
* struct timeval timeout;
*/
#ifdef _KERNEL
#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \
clnt_call_private(rh, NULL, proc, xargs, \
argsp, xres, resp, secs)
#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \
clnt_call_private(rh, NULL, proc, xargs, \
argsp, xres, resp, secs)
#else
#define CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs) \
((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \
argsp, xres, resp, secs))
#define clnt_call(rh, proc, xargs, argsp, xres, resp, secs) \
((*(rh)->cl_ops->cl_call)(rh, proc, xargs, \
argsp, xres, resp, secs))
#endif
/*
* void
* CLNT_ABORT(rh);
* CLIENT *rh;
*/
#define CLNT_ABORT(rh) ((*(rh)->cl_ops->cl_abort)(rh))
#define clnt_abort(rh) ((*(rh)->cl_ops->cl_abort)(rh))
/*
* struct rpc_err
* CLNT_GETERR(rh);
* CLIENT *rh;
*/
#define CLNT_GETERR(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp))
#define clnt_geterr(rh,errp) ((*(rh)->cl_ops->cl_geterr)(rh, errp))
/*
* bool_t
* CLNT_FREERES(rh, xres, resp);
* CLIENT *rh;
* xdrproc_t xres;
* void *resp;
*/
#define CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
#define clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
/*
* bool_t
* CLNT_CONTROL(cl, request, info)
* CLIENT *cl;
* u_int request;
* char *info;
*/
#define CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
#define clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
/*
* control operations that apply to both udp and tcp transports
*/
#define CLSET_TIMEOUT 1 /* set timeout (timeval) */
#define CLGET_TIMEOUT 2 /* get timeout (timeval) */
#define CLGET_SERVER_ADDR 3 /* get server's address (sockaddr) */
#define CLGET_FD 6 /* get connections file descriptor */
#define CLGET_SVC_ADDR 7 /* get server's address (netbuf) */
#define CLSET_FD_CLOSE 8 /* close fd while clnt_destroy */
#define CLSET_FD_NCLOSE 9 /* Do not close fd while clnt_destroy */
#define CLGET_XID 10 /* Get xid */
#define CLSET_XID 11 /* Set xid */
#define CLGET_VERS 12 /* Get version number */
#define CLSET_VERS 13 /* Set version number */
#define CLGET_PROG 14 /* Get program number */
#define CLSET_PROG 15 /* Set program number */
#define CLSET_SVC_ADDR 16 /* get server's address (netbuf) */
#define CLSET_PUSH_TIMOD 17 /* push timod if not already present */
#define CLSET_POP_TIMOD 18 /* pop timod */
/*
* Connectionless only control operations
*/
#define CLSET_RETRY_TIMEOUT 4 /* set retry timeout (timeval) */
#define CLGET_RETRY_TIMEOUT 5 /* get retry timeout (timeval) */
#define CLSET_ASYNC 19
#define CLSET_CONNECT 20 /* Use connect() for UDP. (int) */
#ifdef _KERNEL
/*
* Kernel control operations. The default msleep string is "rpcrecv",
* and sleeps are non-interruptible by default.
*/
#define CLSET_WAITCHAN 21 /* set string to use in msleep call */
#define CLGET_WAITCHAN 22 /* get string used in msleep call */
#define CLSET_INTERRUPTIBLE 23 /* set interruptible flag */
#define CLGET_INTERRUPTIBLE 24 /* set interruptible flag */
#define CLSET_RETRIES 25 /* set retry count for reconnect */
#define CLGET_RETRIES 26 /* get retry count for reconnect */
#define CLSET_PRIVPORT 27 /* set privileged source port flag */
#define CLGET_PRIVPORT 28 /* get privileged source port flag */
#define CLSET_BACKCHANNEL 29 /* set backchannel for socket */
#endif
/*
* void
* CLNT_DESTROY(rh);
* CLIENT *rh;
*/
#define CLNT_DESTROY(rh) ((*(rh)->cl_ops->cl_destroy)(rh))
#define clnt_destroy(rh) ((*(rh)->cl_ops->cl_destroy)(rh))
/*
* RPCTEST is a test program which is accessible on every rpc
* transport/port. It is used for testing, performance evaluation,
* and network administration.
*/
#define RPCTEST_PROGRAM ((rpcprog_t)1)
#define RPCTEST_VERSION ((rpcvers_t)1)
#define RPCTEST_NULL_PROC ((rpcproc_t)2)
#define RPCTEST_NULL_BATCH_PROC ((rpcproc_t)3)
/*
* By convention, procedure 0 takes null arguments and returns them
*/
#define NULLPROC ((rpcproc_t)0)
/*
* Below are the client handle creation routines for the various
* implementations of client side rpc. They can return NULL if a
* creation failure occurs.
*/
/*
* Generic client creation routine. Supported protocols are those that
* belong to the nettype namespace (/etc/netconfig).
*/
__BEGIN_DECLS
#ifdef _KERNEL
/*
* struct socket *so; -- socket
* struct sockaddr *svcaddr; -- servers address
* rpcprog_t prog; -- program number
* rpcvers_t vers; -- version number
* size_t sendsz; -- buffer recv size
* size_t recvsz; -- buffer send size
*/
extern CLIENT *clnt_dg_create(struct socket *so,
struct sockaddr *svcaddr, rpcprog_t program, rpcvers_t version,
size_t sendsz, size_t recvsz);
/*
* struct socket *so; -- socket
* struct sockaddr *svcaddr; -- servers address
* rpcprog_t prog; -- program number
* rpcvers_t vers; -- version number
* size_t sendsz; -- buffer recv size
* size_t recvsz; -- buffer send size
* int intrflag; -- is it interruptible
*/
extern CLIENT *clnt_vc_create(struct socket *so,
struct sockaddr *svcaddr, rpcprog_t program, rpcvers_t version,
size_t sendsz, size_t recvsz, int intrflag);
/*
* struct netconfig *nconf; -- network type
* struct sockaddr *svcaddr; -- servers address
* rpcprog_t prog; -- program number
* rpcvers_t vers; -- version number
* size_t sendsz; -- buffer recv size
* size_t recvsz; -- buffer send size
*/
extern CLIENT *clnt_reconnect_create(struct netconfig *nconf,
struct sockaddr *svcaddr, rpcprog_t program, rpcvers_t version,
size_t sendsz, size_t recvsz);
#else
extern CLIENT *clnt_create(const char *, const rpcprog_t, const rpcvers_t,
const char *);
/*
*
* const char *hostname; -- hostname
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const char *nettype; -- network type
*/
/*
* Generic client creation routine. Just like clnt_create(), except
* it takes an additional timeout parameter.
*/
extern CLIENT * clnt_create_timed(const char *, const rpcprog_t,
const rpcvers_t, const char *, const struct timeval *);
/*
*
* const char *hostname; -- hostname
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const char *nettype; -- network type
* const struct timeval *tp; -- timeout
*/
/*
* Generic client creation routine. Supported protocols are which belong
* to the nettype name space.
*/
extern CLIENT *clnt_create_vers(const char *, const rpcprog_t, rpcvers_t *,
const rpcvers_t, const rpcvers_t,
const char *);
/*
* const char *host; -- hostname
* const rpcprog_t prog; -- program number
* rpcvers_t *vers_out; -- servers highest available version
* const rpcvers_t vers_low; -- low version number
* const rpcvers_t vers_high; -- high version number
* const char *nettype; -- network type
*/
/*
* Generic client creation routine. Supported protocols are which belong
* to the nettype name space.
*/
extern CLIENT * clnt_create_vers_timed(const char *, const rpcprog_t,
rpcvers_t *, const rpcvers_t, const rpcvers_t, const char *,
const struct timeval *);
/*
* const char *host; -- hostname
* const rpcprog_t prog; -- program number
* rpcvers_t *vers_out; -- servers highest available version
* const rpcvers_t vers_low; -- low version number
* const rpcvers_t vers_high; -- high version number
* const char *nettype; -- network type
* const struct timeval *tp -- timeout
*/
/*
* Generic client creation routine. It takes a netconfig structure
* instead of nettype
*/
extern CLIENT *clnt_tp_create(const char *, const rpcprog_t,
const rpcvers_t, const struct netconfig *);
/*
* const char *hostname; -- hostname
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const struct netconfig *netconf; -- network config structure
*/
/*
* Generic client creation routine. Just like clnt_tp_create(), except
* it takes an additional timeout parameter.
*/
extern CLIENT * clnt_tp_create_timed(const char *, const rpcprog_t,
const rpcvers_t, const struct netconfig *, const struct timeval *);
/*
* const char *hostname; -- hostname
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const struct netconfig *netconf; -- network config structure
* const struct timeval *tp -- timeout
*/
/*
* Generic TLI create routine. Only provided for compatibility.
*/
extern CLIENT *clnt_tli_create(const int, const struct netconfig *,
struct netbuf *, const rpcprog_t,
const rpcvers_t, const u_int, const u_int);
/*
* const int fd; -- fd
* const struct netconfig *nconf; -- netconfig structure
* struct netbuf *svcaddr; -- servers address
* const u_long prog; -- program number
* const u_long vers; -- version number
* const u_int sendsz; -- send size
* const u_int recvsz; -- recv size
*/
/*
* Low level clnt create routine for connectionful transports, e.g. tcp.
*/
extern CLIENT *clnt_vc_create(const int, const struct netbuf *,
const rpcprog_t, const rpcvers_t,
u_int, u_int);
/*
* Added for compatibility to old rpc 4.0. Obsoleted by clnt_vc_create().
*/
extern CLIENT *clntunix_create(struct sockaddr_un *,
u_long, u_long, int *, u_int, u_int);
/*
* const int fd; -- open file descriptor
* const struct netbuf *svcaddr; -- servers address
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const u_int sendsz; -- buffer recv size
* const u_int recvsz; -- buffer send size
*/
/*
* Low level clnt create routine for connectionless transports, e.g. udp.
*/
extern CLIENT *clnt_dg_create(const int, const struct netbuf *,
const rpcprog_t, const rpcvers_t,
const u_int, const u_int);
/*
* const int fd; -- open file descriptor
* const struct netbuf *svcaddr; -- servers address
* const rpcprog_t program; -- program number
* const rpcvers_t version; -- version number
* const u_int sendsz; -- buffer recv size
* const u_int recvsz; -- buffer send size
*/
/*
* Memory based rpc (for speed check and testing)
* CLIENT *
* clnt_raw_create(prog, vers)
* u_long prog;
* u_long vers;
*/
extern CLIENT *clnt_raw_create(rpcprog_t, rpcvers_t);
#endif
__END_DECLS
/*
* Print why creation failed
*/
__BEGIN_DECLS
extern void clnt_pcreateerror(const char *); /* stderr */
extern char *clnt_spcreateerror(const char *); /* string */
__END_DECLS
/*
* Like clnt_perror(), but is more verbose in its output
*/
__BEGIN_DECLS
extern void clnt_perrno(enum clnt_stat); /* stderr */
extern char *clnt_sperrno(enum clnt_stat); /* string */
__END_DECLS
/*
* Print an English error message, given the client error code
*/
__BEGIN_DECLS
extern void clnt_perror(CLIENT *, const char *); /* stderr */
extern char *clnt_sperror(CLIENT *, const char *); /* string */
__END_DECLS
/*
* If a creation fails, the following allows the user to figure out why.
*/
struct rpc_createerr {
enum clnt_stat cf_stat;
struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */
};
#ifdef _KERNEL
extern struct rpc_createerr rpc_createerr;
#else
__BEGIN_DECLS
extern struct rpc_createerr *__rpc_createerr(void);
__END_DECLS
#define rpc_createerr (*(__rpc_createerr()))
#endif
#ifndef _KERNEL
/*
* The simplified interface:
* enum clnt_stat
* rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype)
* const char *host;
* const rpcprog_t prognum;
* const rpcvers_t versnum;
* const rpcproc_t procnum;
* const xdrproc_t inproc, outproc;
* const char *in;
* char *out;
* const char *nettype;
*/
__BEGIN_DECLS
extern enum clnt_stat rpc_call(const char *, const rpcprog_t,
const rpcvers_t, const rpcproc_t,
const xdrproc_t, const char *,
const xdrproc_t, char *, const char *);
__END_DECLS
/*
* RPC broadcast interface
* The call is broadcasted to all locally connected nets.
*
* extern enum clnt_stat
* rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp,
* eachresult, nettype)
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const rpcproc_t proc; -- procedure number
* const xdrproc_t xargs; -- xdr routine for args
* caddr_t argsp; -- pointer to args
* const xdrproc_t xresults; -- xdr routine for results
* caddr_t resultsp; -- pointer to results
* const resultproc_t eachresult; -- call with each result
* const char *nettype; -- Transport type
*
* For each valid response received, the procedure eachresult is called.
* Its form is:
* done = eachresult(resp, raddr, nconf)
* bool_t done;
* caddr_t resp;
* struct netbuf *raddr;
* struct netconfig *nconf;
* where resp points to the results of the call and raddr is the
* address if the responder to the broadcast. nconf is the transport
* on which the response was received.
*
* extern enum clnt_stat
* rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp,
* eachresult, inittime, waittime, nettype)
* const rpcprog_t prog; -- program number
* const rpcvers_t vers; -- version number
* const rpcproc_t proc; -- procedure number
* const xdrproc_t xargs; -- xdr routine for args
* caddr_t argsp; -- pointer to args
* const xdrproc_t xresults; -- xdr routine for results
* caddr_t resultsp; -- pointer to results
* const resultproc_t eachresult; -- call with each result
* const int inittime; -- how long to wait initially
* const int waittime; -- maximum time to wait
* const char *nettype; -- Transport type
*/
typedef bool_t (*resultproc_t)(caddr_t, ...);
__BEGIN_DECLS
extern enum clnt_stat rpc_broadcast(const rpcprog_t, const rpcvers_t,
const rpcproc_t, const xdrproc_t,
caddr_t, const xdrproc_t, caddr_t,
const resultproc_t, const char *);
extern enum clnt_stat rpc_broadcast_exp(const rpcprog_t, const rpcvers_t,
const rpcproc_t, const xdrproc_t,
caddr_t, const xdrproc_t, caddr_t,
const resultproc_t, const int,
const int, const char *);
__END_DECLS
/* For backward compatibility */
#include <rpc/clnt_soc.h>
#endif
#endif /* !_RPC_CLNT_H_ */

588
freebsd/sys/rpc/clnt_bck.c Normal file
View File

@ -0,0 +1,588 @@
/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* clnt_tcp.c, Implements a TCP/IP based, client side RPC.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* TCP based RPC supports 'batched calls'.
* A sequence of calls may be batched-up in a send buffer. The rpc call
* return immediately to the client even though the call was not necessarily
* sent. The batching occurs if the results' xdr routine is NULL (0) AND
* the rpc timeout value is zero (see clnt.h, rpc).
*
* Clients should NOT casually batch calls that in fact return results; that is,
* the server side should be aware that a call is batched and not produce any
* return message. Batched calls that produce many result messages can
* deadlock (netlock) the client and the server....
*
* Now go hang yourself.
*/
/*
* This code handles the special case of a NFSv4.n backchannel for
* callback RPCs. It is similar to clnt_vc.c, but uses the TCP
* connection provided by the client to the server.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sx.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <net/vnet.h>
#include <netinet/tcp.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/krpc.h>
struct cmessage {
struct cmsghdr cmsg;
struct cmsgcred cmcred;
};
static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
static void clnt_bck_abort(CLIENT *);
static bool_t clnt_bck_control(CLIENT *, u_int, void *);
static void clnt_bck_close(CLIENT *);
static void clnt_bck_destroy(CLIENT *);
static struct clnt_ops clnt_bck_ops = {
.cl_abort = clnt_bck_abort,
.cl_geterr = clnt_bck_geterr,
.cl_freeres = clnt_bck_freeres,
.cl_close = clnt_bck_close,
.cl_destroy = clnt_bck_destroy,
.cl_control = clnt_bck_control
};
/*
* Create a client handle for a connection.
* Default options are set, which the user can change using clnt_control()'s.
* This code handles the special case of an NFSv4.1 session backchannel
* call, which is sent on a TCP connection created against the server
* by a client.
*/
void *
clnt_bck_create(
struct socket *so, /* Server transport socket. */
const rpcprog_t prog, /* program number */
const rpcvers_t vers) /* version number */
{
CLIENT *cl; /* client handle */
struct ct_data *ct = NULL; /* client handle */
struct timeval now;
struct rpc_msg call_msg;
static uint32_t disrupt;
XDR xdrs;
if (disrupt == 0)
disrupt = (uint32_t)(long)so;
cl = (CLIENT *)mem_alloc(sizeof (*cl));
ct = (struct ct_data *)mem_alloc(sizeof (*ct));
mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
ct->ct_threads = 0;
ct->ct_closing = FALSE;
ct->ct_closed = FALSE;
ct->ct_upcallrefs = 0;
ct->ct_closeit = FALSE;
/*
* Set up private data struct
*/
ct->ct_wait.tv_sec = -1;
ct->ct_wait.tv_usec = -1;
/*
* Initialize call message
*/
getmicrotime(&now);
ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
call_msg.rm_xid = ct->ct_xid;
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
call_msg.rm_call.cb_prog = (uint32_t)prog;
call_msg.rm_call.cb_vers = (uint32_t)vers;
/*
* pre-serialize the static part of the call msg and stash it away
*/
xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
XDR_ENCODE);
if (!xdr_callhdr(&xdrs, &call_msg))
goto err;
ct->ct_mpos = XDR_GETPOS(&xdrs);
XDR_DESTROY(&xdrs);
ct->ct_waitchan = "rpcbck";
ct->ct_waitflag = 0;
cl->cl_refs = 1;
cl->cl_ops = &clnt_bck_ops;
cl->cl_private = ct;
cl->cl_auth = authnone_create();
TAILQ_INIT(&ct->ct_pending);
return (cl);
err:
mtx_destroy(&ct->ct_lock);
mem_free(ct, sizeof (struct ct_data));
mem_free(cl, sizeof (CLIENT));
return (NULL);
}
enum clnt_stat
clnt_bck_call(
CLIENT *cl, /* client handle */
struct rpc_callextra *ext, /* call metadata */
rpcproc_t proc, /* procedure number */
struct mbuf *args, /* pointer to args */
struct mbuf **resultsp, /* pointer to results */
struct timeval utimeout,
SVCXPRT *xprt)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
AUTH *auth;
struct rpc_err *errp;
enum clnt_stat stat;
XDR xdrs;
struct rpc_msg reply_msg;
bool_t ok;
int nrefreshes = 2; /* number of times to refresh cred */
struct timeval timeout;
uint32_t xid;
struct mbuf *mreq = NULL, *results;
struct ct_request *cr;
int error;
cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
mtx_lock(&ct->ct_lock);
if (ct->ct_closing || ct->ct_closed) {
mtx_unlock(&ct->ct_lock);
free(cr, M_RPC);
return (RPC_CANTSEND);
}
ct->ct_threads++;
if (ext) {
auth = ext->rc_auth;
errp = &ext->rc_err;
} else {
auth = cl->cl_auth;
errp = &ct->ct_error;
}
cr->cr_mrep = NULL;
cr->cr_error = 0;
if (ct->ct_wait.tv_usec == -1)
timeout = utimeout; /* use supplied timeout */
else
timeout = ct->ct_wait; /* use default timeout */
call_again:
mtx_assert(&ct->ct_lock, MA_OWNED);
ct->ct_xid++;
xid = ct->ct_xid;
mtx_unlock(&ct->ct_lock);
/*
* Leave space to pre-pend the record mark.
*/
mreq = m_gethdr(M_WAITOK, MT_DATA);
mreq->m_data += sizeof(uint32_t);
KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
("RPC header too big"));
bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
mreq->m_len = ct->ct_mpos;
/*
* The XID is the first thing in the request.
*/
*mtod(mreq, uint32_t *) = htonl(xid);
xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
errp->re_status = stat = RPC_SUCCESS;
if ((!XDR_PUTINT32(&xdrs, &proc)) ||
(!AUTH_MARSHALL(auth, xid, &xdrs,
m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
errp->re_status = stat = RPC_CANTENCODEARGS;
mtx_lock(&ct->ct_lock);
goto out;
}
mreq->m_pkthdr.len = m_length(mreq, NULL);
/*
* Prepend a record marker containing the packet length.
*/
M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
*mtod(mreq, uint32_t *) =
htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
cr->cr_xid = xid;
mtx_lock(&ct->ct_lock);
/*
* Check to see if the client end has already started to close down
* the connection. The svc code will have set ct_error.re_status
* to RPC_CANTRECV if this is the case.
* If the client starts to close down the connection after this
* point, it will be detected later when cr_error is checked,
* since the request is in the ct_pending queue.
*/
if (ct->ct_error.re_status == RPC_CANTRECV) {
if (errp != &ct->ct_error) {
errp->re_errno = ct->ct_error.re_errno;
errp->re_status = RPC_CANTRECV;
}
stat = RPC_CANTRECV;
goto out;
}
TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
mtx_unlock(&ct->ct_lock);
/*
* sosend consumes mreq.
*/
sx_xlock(&xprt->xp_lock);
error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
if (error != 0) printf("sosend=%d\n", error);
mreq = NULL;
if (error == EMSGSIZE) {
printf("emsgsize\n");
SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
sbwait(&xprt->xp_socket->so_snd);
SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
sx_xunlock(&xprt->xp_lock);
AUTH_VALIDATE(auth, xid, NULL, NULL);
mtx_lock(&ct->ct_lock);
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
goto call_again;
}
sx_xunlock(&xprt->xp_lock);
reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
reply_msg.acpted_rply.ar_verf.oa_length = 0;
reply_msg.acpted_rply.ar_results.where = NULL;
reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
mtx_lock(&ct->ct_lock);
if (error) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
errp->re_errno = error;
errp->re_status = stat = RPC_CANTSEND;
goto out;
}
/*
* Check to see if we got an upcall while waiting for the
* lock. In both these cases, the request has been removed
* from ct->ct_pending.
*/
if (cr->cr_error) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
errp->re_errno = cr->cr_error;
errp->re_status = stat = RPC_CANTRECV;
goto out;
}
if (cr->cr_mrep) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
goto got_reply;
}
/*
* Hack to provide rpc-based message passing
*/
if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
errp->re_status = stat = RPC_TIMEDOUT;
goto out;
}
error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
tvtohz(&timeout));
TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
if (error) {
/*
* The sleep returned an error so our request is still
* on the list. Turn the error code into an
* appropriate client status.
*/
errp->re_errno = error;
switch (error) {
case EINTR:
stat = RPC_INTR;
break;
case EWOULDBLOCK:
stat = RPC_TIMEDOUT;
break;
default:
stat = RPC_CANTRECV;
}
errp->re_status = stat;
goto out;
} else {
/*
* We were woken up by the svc thread. If the
* upcall had a receive error, report that,
* otherwise we have a reply.
*/
if (cr->cr_error) {
errp->re_errno = cr->cr_error;
errp->re_status = stat = RPC_CANTRECV;
goto out;
}
}
got_reply:
/*
* Now decode and validate the response. We need to drop the
* lock since xdr_replymsg may end up sleeping in malloc.
*/
mtx_unlock(&ct->ct_lock);
if (ext && ext->rc_feedback)
ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
ok = xdr_replymsg(&xdrs, &reply_msg);
cr->cr_mrep = NULL;
if (ok) {
if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(reply_msg.acpted_rply.ar_stat == SUCCESS))
errp->re_status = stat = RPC_SUCCESS;
else
stat = _seterr_reply(&reply_msg, errp);
if (stat == RPC_SUCCESS) {
results = xdrmbuf_getall(&xdrs);
if (!AUTH_VALIDATE(auth, xid,
&reply_msg.acpted_rply.ar_verf, &results)) {
errp->re_status = stat = RPC_AUTHERROR;
errp->re_why = AUTH_INVALIDRESP;
} else {
KASSERT(results,
("auth validated but no result"));
*resultsp = results;
}
} /* end successful completion */
/*
* If unsuccessful AND error is an authentication error
* then refresh credentials and try again, else break
*/
else if (stat == RPC_AUTHERROR)
/* maybe our credentials need to be refreshed ... */
if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
nrefreshes--;
XDR_DESTROY(&xdrs);
mtx_lock(&ct->ct_lock);
goto call_again;
}
/* end of unsuccessful completion */
/* end of valid reply message */
} else
errp->re_status = stat = RPC_CANTDECODERES;
XDR_DESTROY(&xdrs);
mtx_lock(&ct->ct_lock);
out:
mtx_assert(&ct->ct_lock, MA_OWNED);
KASSERT(stat != RPC_SUCCESS || *resultsp,
("RPC_SUCCESS without reply"));
if (mreq != NULL)
m_freem(mreq);
if (cr->cr_mrep != NULL)
m_freem(cr->cr_mrep);
ct->ct_threads--;
if (ct->ct_closing)
wakeup(ct);
mtx_unlock(&ct->ct_lock);
if (auth && stat != RPC_SUCCESS)
AUTH_VALIDATE(auth, xid, NULL, NULL);
free(cr, M_RPC);
return (stat);
}
static void
clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
*errp = ct->ct_error;
}
static bool_t
clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
{
XDR xdrs;
bool_t dummy;
xdrs.x_op = XDR_FREE;
dummy = (*xdr_res)(&xdrs, res_ptr);
return (dummy);
}
/*ARGSUSED*/
static void
clnt_bck_abort(CLIENT *cl)
{
}
static bool_t
clnt_bck_control(CLIENT *cl, u_int request, void *info)
{
return (TRUE);
}
static void
clnt_bck_close(CLIENT *cl)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
mtx_lock(&ct->ct_lock);
if (ct->ct_closed) {
mtx_unlock(&ct->ct_lock);
return;
}
if (ct->ct_closing) {
while (ct->ct_closing)
msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
KASSERT(ct->ct_closed, ("client should be closed"));
mtx_unlock(&ct->ct_lock);
return;
}
ct->ct_closing = FALSE;
ct->ct_closed = TRUE;
mtx_unlock(&ct->ct_lock);
wakeup(ct);
}
static void
clnt_bck_destroy(CLIENT *cl)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
clnt_bck_close(cl);
mtx_destroy(&ct->ct_lock);
mem_free(ct, sizeof(struct ct_data));
if (cl->cl_netid && cl->cl_netid[0])
mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
if (cl->cl_tp && cl->cl_tp[0])
mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
mem_free(cl, sizeof(CLIENT));
}
/*
* This call is done by the svc code when a backchannel RPC reply is
* received.
*/
void
clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
{
struct ct_data *ct = (struct ct_data *)arg;
struct ct_request *cr;
int foundreq;
mtx_lock(&ct->ct_lock);
ct->ct_upcallrefs++;
/*
* See if we can match this reply to a request.
*/
foundreq = 0;
TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
if (cr->cr_xid == xid) {
/*
* This one matches. We leave the reply mbuf list in
* cr->cr_mrep. Set the XID to zero so that we will
* ignore any duplicated replies.
*/
cr->cr_xid = 0;
cr->cr_mrep = mrep;
cr->cr_error = 0;
foundreq = 1;
wakeup(cr);
break;
}
}
ct->ct_upcallrefs--;
if (ct->ct_upcallrefs < 0)
panic("rpcvc svccall refcnt");
if (ct->ct_upcallrefs == 0)
wakeup(&ct->ct_upcallrefs);
mtx_unlock(&ct->ct_lock);
if (foundreq == 0)
m_freem(mrep);
}

1151
freebsd/sys/rpc/clnt_dg.c Normal file

File diff suppressed because it is too large Load Diff

524
freebsd/sys/rpc/clnt_rc.c Normal file
View File

@ -0,0 +1,524 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/krpc.h>
static enum clnt_stat clnt_reconnect_call(CLIENT *, struct rpc_callextra *,
rpcproc_t, struct mbuf *, struct mbuf **, struct timeval);
static void clnt_reconnect_geterr(CLIENT *, struct rpc_err *);
static bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *);
static void clnt_reconnect_abort(CLIENT *);
static bool_t clnt_reconnect_control(CLIENT *, u_int, void *);
static void clnt_reconnect_close(CLIENT *);
static void clnt_reconnect_destroy(CLIENT *);
static struct clnt_ops clnt_reconnect_ops = {
.cl_call = clnt_reconnect_call,
.cl_abort = clnt_reconnect_abort,
.cl_geterr = clnt_reconnect_geterr,
.cl_freeres = clnt_reconnect_freeres,
.cl_close = clnt_reconnect_close,
.cl_destroy = clnt_reconnect_destroy,
.cl_control = clnt_reconnect_control
};
static int fake_wchan;
CLIENT *
clnt_reconnect_create(
struct netconfig *nconf, /* network type */
struct sockaddr *svcaddr, /* servers address */
rpcprog_t program, /* program number */
rpcvers_t version, /* version number */
size_t sendsz, /* buffer recv size */
size_t recvsz) /* buffer send size */
{
CLIENT *cl = NULL; /* client handle */
struct rc_data *rc = NULL; /* private data */
if (svcaddr == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
return (NULL);
}
cl = mem_alloc(sizeof (CLIENT));
rc = mem_alloc(sizeof (*rc));
mtx_init(&rc->rc_lock, "rc->rc_lock", NULL, MTX_DEF);
(void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len);
rc->rc_nconf = nconf;
rc->rc_prog = program;
rc->rc_vers = version;
rc->rc_sendsz = sendsz;
rc->rc_recvsz = recvsz;
rc->rc_timeout.tv_sec = -1;
rc->rc_timeout.tv_usec = -1;
rc->rc_retry.tv_sec = 3;
rc->rc_retry.tv_usec = 0;
rc->rc_retries = INT_MAX;
rc->rc_privport = FALSE;
rc->rc_waitchan = "rpcrecv";
rc->rc_intr = 0;
rc->rc_connecting = FALSE;
rc->rc_closed = FALSE;
rc->rc_ucred = crdup(curthread->td_ucred);
rc->rc_client = NULL;
cl->cl_refs = 1;
cl->cl_ops = &clnt_reconnect_ops;
cl->cl_private = (caddr_t)(void *)rc;
cl->cl_auth = authnone_create();
cl->cl_tp = NULL;
cl->cl_netid = NULL;
return (cl);
}
static enum clnt_stat
clnt_reconnect_connect(CLIENT *cl)
{
struct thread *td = curthread;
struct rc_data *rc = (struct rc_data *)cl->cl_private;
struct socket *so;
enum clnt_stat stat;
int error;
int one = 1;
struct ucred *oldcred;
CLIENT *newclient = NULL;
mtx_lock(&rc->rc_lock);
while (rc->rc_connecting) {
error = msleep(rc, &rc->rc_lock,
rc->rc_intr ? PCATCH : 0, "rpcrecon", 0);
if (error) {
mtx_unlock(&rc->rc_lock);
return (RPC_INTR);
}
}
if (rc->rc_closed) {
mtx_unlock(&rc->rc_lock);
return (RPC_CANTSEND);
}
if (rc->rc_client) {
mtx_unlock(&rc->rc_lock);
return (RPC_SUCCESS);
}
/*
* My turn to attempt a connect. The rc_connecting variable
* serializes the following code sequence, so it is guaranteed
* that rc_client will still be NULL after it is re-locked below,
* since that is the only place it is set non-NULL.
*/
rc->rc_connecting = TRUE;
mtx_unlock(&rc->rc_lock);
oldcred = td->td_ucred;
td->td_ucred = rc->rc_ucred;
so = __rpc_nconf2socket(rc->rc_nconf);
if (!so) {
stat = rpc_createerr.cf_stat = RPC_TLIERROR;
rpc_createerr.cf_error.re_errno = 0;
td->td_ucred = oldcred;
goto out;
}
if (rc->rc_privport)
bindresvport(so, NULL);
if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS)
newclient = clnt_dg_create(so,
(struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
rc->rc_sendsz, rc->rc_recvsz);
else {
/*
* I do not believe a timeout of less than 1sec would make
* sense here since short delays can occur when a server is
* temporarily overloaded.
*/
if (rc->rc_timeout.tv_sec > 0 && rc->rc_timeout.tv_usec >= 0) {
error = so_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
&rc->rc_timeout, sizeof(struct timeval));
if (error != 0) {
stat = rpc_createerr.cf_stat = RPC_CANTSEND;
rpc_createerr.cf_error.re_errno = error;
td->td_ucred = oldcred;
goto out;
}
}
newclient = clnt_vc_create(so,
(struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr);
}
td->td_ucred = oldcred;
if (!newclient) {
soclose(so);
rc->rc_err = rpc_createerr.cf_error;
stat = rpc_createerr.cf_stat;
goto out;
}
CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
CLNT_CONTROL(newclient, CLSET_CONNECT, &one);
CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout);
CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
CLNT_CONTROL(newclient, CLSET_WAITCHAN, rc->rc_waitchan);
CLNT_CONTROL(newclient, CLSET_INTERRUPTIBLE, &rc->rc_intr);
if (rc->rc_backchannel != NULL)
CLNT_CONTROL(newclient, CLSET_BACKCHANNEL, rc->rc_backchannel);
stat = RPC_SUCCESS;
out:
mtx_lock(&rc->rc_lock);
KASSERT(rc->rc_client == NULL, ("rc_client not null"));
if (!rc->rc_closed) {
rc->rc_client = newclient;
newclient = NULL;
}
rc->rc_connecting = FALSE;
wakeup(rc);
mtx_unlock(&rc->rc_lock);
if (newclient) {
/*
* It has been closed, so discard the new client.
* nb: clnt_[dg|vc]_close()/clnt_[dg|vc]_destroy() cannot
* be called with the rc_lock mutex held, since they may
* msleep() while holding a different mutex.
*/
CLNT_CLOSE(newclient);
CLNT_RELEASE(newclient);
}
return (stat);
}
static enum clnt_stat
clnt_reconnect_call(
CLIENT *cl, /* client handle */
struct rpc_callextra *ext, /* call metadata */
rpcproc_t proc, /* procedure number */
struct mbuf *args, /* pointer to args */
struct mbuf **resultsp, /* pointer to results */
struct timeval utimeout)
{
struct rc_data *rc = (struct rc_data *)cl->cl_private;
CLIENT *client;
enum clnt_stat stat;
int tries, error;
tries = 0;
do {
mtx_lock(&rc->rc_lock);
if (rc->rc_closed) {
mtx_unlock(&rc->rc_lock);
return (RPC_CANTSEND);
}
if (!rc->rc_client) {
mtx_unlock(&rc->rc_lock);
stat = clnt_reconnect_connect(cl);
if (stat == RPC_SYSTEMERROR) {
error = tsleep(&fake_wchan,
rc->rc_intr ? PCATCH : 0, "rpccon", hz);
if (error == EINTR || error == ERESTART)
return (RPC_INTR);
tries++;
if (tries >= rc->rc_retries)
return (stat);
continue;
}
if (stat != RPC_SUCCESS)
return (stat);
mtx_lock(&rc->rc_lock);
}
if (!rc->rc_client) {
mtx_unlock(&rc->rc_lock);
stat = RPC_FAILED;
continue;
}
CLNT_ACQUIRE(rc->rc_client);
client = rc->rc_client;
mtx_unlock(&rc->rc_lock);
stat = CLNT_CALL_MBUF(client, ext, proc, args,
resultsp, utimeout);
if (stat != RPC_SUCCESS) {
if (!ext)
CLNT_GETERR(client, &rc->rc_err);
}
if (stat == RPC_TIMEDOUT) {
/*
* Check for async send misfeature for NLM
* protocol.
*/
if ((rc->rc_timeout.tv_sec == 0
&& rc->rc_timeout.tv_usec == 0)
|| (rc->rc_timeout.tv_sec == -1
&& utimeout.tv_sec == 0
&& utimeout.tv_usec == 0)) {
CLNT_RELEASE(client);
break;
}
}
if (stat == RPC_TIMEDOUT || stat == RPC_CANTSEND
|| stat == RPC_CANTRECV) {
tries++;
if (tries >= rc->rc_retries) {
CLNT_RELEASE(client);
break;
}
if (ext && ext->rc_feedback)
ext->rc_feedback(FEEDBACK_RECONNECT, proc,
ext->rc_feedback_arg);
mtx_lock(&rc->rc_lock);
/*
* Make sure that someone else hasn't already
* reconnected by checking if rc_client has changed.
* If not, we are done with the client and must
* do CLNT_RELEASE(client) twice to dispose of it,
* because there is both an initial refcnt and one
* acquired by CLNT_ACQUIRE() above.
*/
if (rc->rc_client == client) {
rc->rc_client = NULL;
mtx_unlock(&rc->rc_lock);
CLNT_RELEASE(client);
} else {
mtx_unlock(&rc->rc_lock);
}
CLNT_RELEASE(client);
} else {
CLNT_RELEASE(client);
break;
}
} while (stat != RPC_SUCCESS);
KASSERT(stat != RPC_SUCCESS || *resultsp,
("RPC_SUCCESS without reply"));
return (stat);
}
static void
clnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp)
{
struct rc_data *rc = (struct rc_data *)cl->cl_private;
*errp = rc->rc_err;
}
/*
* Since this function requires that rc_client be valid, it can
* only be called when that is guaranteed to be the case.
*/
static bool_t
clnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
{
struct rc_data *rc = (struct rc_data *)cl->cl_private;
return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr));
}
/*ARGSUSED*/
static void
clnt_reconnect_abort(CLIENT *h)
{
}
/*
* CLNT_CONTROL() on the client returned by clnt_reconnect_create() must
* always be called before CLNT_CALL_MBUF() by a single thread only.
*/
static bool_t
clnt_reconnect_control(CLIENT *cl, u_int request, void *info)
{
struct rc_data *rc = (struct rc_data *)cl->cl_private;
SVCXPRT *xprt;
if (info == NULL) {
return (FALSE);
}
switch (request) {
case CLSET_TIMEOUT:
rc->rc_timeout = *(struct timeval *)info;
if (rc->rc_client)
CLNT_CONTROL(rc->rc_client, request, info);
break;
case CLGET_TIMEOUT:
*(struct timeval *)info = rc->rc_timeout;
break;
case CLSET_RETRY_TIMEOUT:
rc->rc_retry = *(struct timeval *)info;
if (rc->rc_client)
CLNT_CONTROL(rc->rc_client, request, info);
break;
case CLGET_RETRY_TIMEOUT:
*(struct timeval *)info = rc->rc_retry;
break;
case CLGET_VERS:
*(uint32_t *)info = rc->rc_vers;
break;
case CLSET_VERS:
rc->rc_vers = *(uint32_t *) info;
if (rc->rc_client)
CLNT_CONTROL(rc->rc_client, CLSET_VERS, info);
break;
case CLGET_PROG:
*(uint32_t *)info = rc->rc_prog;
break;
case CLSET_PROG:
rc->rc_prog = *(uint32_t *) info;
if (rc->rc_client)
CLNT_CONTROL(rc->rc_client, request, info);
break;
case CLSET_WAITCHAN:
rc->rc_waitchan = (char *)info;
if (rc->rc_client)
CLNT_CONTROL(rc->rc_client, request, info);
break;
case CLGET_WAITCHAN:
*(const char **) info = rc->rc_waitchan;
break;
case CLSET_INTERRUPTIBLE:
rc->rc_intr = *(int *) info;
if (rc->rc_client)
CLNT_CONTROL(rc->rc_client, request, info);
break;
case CLGET_INTERRUPTIBLE:
*(int *) info = rc->rc_intr;
break;
case CLSET_RETRIES:
rc->rc_retries = *(int *) info;
break;
case CLGET_RETRIES:
*(int *) info = rc->rc_retries;
break;
case CLSET_PRIVPORT:
rc->rc_privport = *(int *) info;
break;
case CLGET_PRIVPORT:
*(int *) info = rc->rc_privport;
break;
case CLSET_BACKCHANNEL:
xprt = (SVCXPRT *)info;
xprt_register(xprt);
rc->rc_backchannel = info;
break;
default:
return (FALSE);
}
return (TRUE);
}
static void
clnt_reconnect_close(CLIENT *cl)
{
struct rc_data *rc = (struct rc_data *)cl->cl_private;
CLIENT *client;
mtx_lock(&rc->rc_lock);
if (rc->rc_closed) {
mtx_unlock(&rc->rc_lock);
return;
}
rc->rc_closed = TRUE;
client = rc->rc_client;
rc->rc_client = NULL;
mtx_unlock(&rc->rc_lock);
if (client) {
CLNT_CLOSE(client);
CLNT_RELEASE(client);
}
}
static void
clnt_reconnect_destroy(CLIENT *cl)
{
struct rc_data *rc = (struct rc_data *)cl->cl_private;
SVCXPRT *xprt;
if (rc->rc_client)
CLNT_DESTROY(rc->rc_client);
if (rc->rc_backchannel) {
xprt = (SVCXPRT *)rc->rc_backchannel;
xprt_unregister(xprt);
SVC_RELEASE(xprt);
}
crfree(rc->rc_ucred);
mtx_destroy(&rc->rc_lock);
mem_free(rc, sizeof(*rc));
mem_free(cl, sizeof (CLIENT));
}

View File

@ -0,0 +1,83 @@
/* $FreeBSD$ */
/*
* Copyright (c) 1986 - 1991, 1994, 1996, 1997 by Sun Microsystems, Inc.
* All rights reserved.
*/
/*
* clnt_stat.h - Client side remote procedure call enum
*
*/
#ifndef _RPC_CLNT_STAT_H
#define _RPC_CLNT_STAT_H
/* #pragma ident "@(#)clnt_stat.h 1.2 97/04/28 SMI" */
#ifdef __cplusplus
extern "C" {
#endif
enum clnt_stat {
RPC_SUCCESS = 0, /* call succeeded */
/*
* local errors
*/
RPC_CANTENCODEARGS = 1, /* can't encode arguments */
RPC_CANTDECODERES = 2, /* can't decode results */
RPC_CANTSEND = 3, /* failure in sending call */
RPC_CANTRECV = 4,
/* failure in receiving result */
RPC_TIMEDOUT = 5, /* call timed out */
RPC_INTR = 18, /* call interrupted */
RPC_UDERROR = 23, /* recv got uderr indication */
/*
* remote errors
*/
RPC_VERSMISMATCH = 6, /* rpc versions not compatible */
RPC_AUTHERROR = 7, /* authentication error */
RPC_PROGUNAVAIL = 8, /* program not available */
RPC_PROGVERSMISMATCH = 9, /* program version mismatched */
RPC_PROCUNAVAIL = 10, /* procedure unavailable */
RPC_CANTDECODEARGS = 11, /* decode arguments error */
RPC_SYSTEMERROR = 12, /* generic "other problem" */
/*
* rpc_call & clnt_create errors
*/
RPC_UNKNOWNHOST = 13, /* unknown host name */
RPC_UNKNOWNPROTO = 17, /* unknown protocol */
RPC_UNKNOWNADDR = 19, /* Remote address unknown */
RPC_NOBROADCAST = 21, /* Broadcasting not supported */
/*
* rpcbind errors
*/
RPC_RPCBFAILURE = 14, /* the pmapper failed in its call */
#define RPC_PMAPFAILURE RPC_RPCBFAILURE
RPC_PROGNOTREGISTERED = 15, /* remote program is not registered */
RPC_N2AXLATEFAILURE = 22,
/* Name to address translation failed */
/*
* Misc error in the TLI library
*/
RPC_TLIERROR = 20,
/*
* unspecified error
*/
RPC_FAILED = 16,
/*
* asynchronous errors
*/
RPC_INPROGRESS = 24,
RPC_STALERACHANDLE = 25,
RPC_CANTCONNECT = 26, /* couldn't make connection (cots) */
RPC_XPRTFAILED = 27, /* received discon from remote (cots) */
RPC_CANTCREATESTREAM = 28 /* can't push rpc module (cots) */
};
#ifdef __cplusplus
}
#endif
#endif /* !_RPC_CLNT_STAT_H */

1081
freebsd/sys/rpc/clnt_vc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,140 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 "opt_inet6.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <rpc/types.h>
/*
* For in-kernel use, we use a simple compiled-in configuration.
*/
static struct netconfig netconfigs[] = {
#ifdef INET6
{
.nc_netid = "udp6",
.nc_semantics = NC_TPI_CLTS,
.nc_flag = NC_VISIBLE,
.nc_protofmly = "inet6",
.nc_proto = "udp",
},
{
.nc_netid = "tcp6",
.nc_semantics = NC_TPI_COTS_ORD,
.nc_flag = NC_VISIBLE,
.nc_protofmly = "inet6",
.nc_proto = "tcp",
},
#endif
{
.nc_netid = "udp",
.nc_semantics = NC_TPI_CLTS,
.nc_flag = NC_VISIBLE,
.nc_protofmly = "inet",
.nc_proto = "udp",
},
{
.nc_netid = "tcp",
.nc_semantics = NC_TPI_COTS_ORD,
.nc_flag = NC_VISIBLE,
.nc_protofmly = "inet",
.nc_proto = "tcp",
},
{
.nc_netid = "local",
.nc_semantics = NC_TPI_COTS_ORD,
.nc_flag = 0,
.nc_protofmly = "loopback",
.nc_proto = "",
},
{
.nc_netid = NULL,
}
};
void *
setnetconfig(void)
{
struct netconfig **nconfp;
nconfp = malloc(sizeof(struct netconfig *), M_RPC, M_WAITOK);
*nconfp = netconfigs;
return ((void *) nconfp);
}
struct netconfig *
getnetconfig(void *handle)
{
struct netconfig **nconfp = (struct netconfig **) handle;
struct netconfig *nconf;
nconf = *nconfp;
if (nconf->nc_netid == NULL)
return (NULL);
(*nconfp)++;
return (nconf);
}
struct netconfig *
getnetconfigent(const char *netid)
{
struct netconfig *nconf;
for (nconf = netconfigs; nconf->nc_netid; nconf++) {
if (!strcmp(netid, nconf->nc_netid))
return (nconf);
}
return (NULL);
}
void
freenetconfigent(struct netconfig *nconf)
{
}
int
endnetconfig(void * handle)
{
struct netconfig **nconfp = (struct netconfig **) handle;
free(nconfp, M_RPC);
return (0);
}

116
freebsd/sys/rpc/krpc.h Normal file
View File

@ -0,0 +1,116 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* $FreeBSD$
*/
#ifndef _RPC_KRPC_H_
#define _RPC_KRPC_H_
#ifdef _KERNEL
/*
* Definitions now shared between client and server RPC for backchannels.
*/
#define MCALL_MSG_SIZE 24
void clnt_bck_svccall(void *, struct mbuf *, uint32_t);
enum clnt_stat clnt_bck_call(CLIENT *, struct rpc_callextra *, rpcproc_t,
struct mbuf *, struct mbuf **, struct timeval, SVCXPRT *);
/*
* A pending RPC request which awaits a reply. Requests which have
* received their reply will have cr_xid set to zero and cr_mrep to
* the mbuf chain of the reply.
*/
struct ct_request {
TAILQ_ENTRY(ct_request) cr_link;
uint32_t cr_xid; /* XID of request */
struct mbuf *cr_mrep; /* reply received by upcall */
int cr_error; /* any error from upcall */
char cr_verf[MAX_AUTH_BYTES]; /* reply verf */
};
TAILQ_HEAD(ct_request_list, ct_request);
struct rc_data {
struct mtx rc_lock;
struct sockaddr_storage rc_addr; /* server address */
struct netconfig* rc_nconf; /* network type */
rpcprog_t rc_prog; /* program number */
rpcvers_t rc_vers; /* version number */
size_t rc_sendsz;
size_t rc_recvsz;
struct timeval rc_timeout;
struct timeval rc_retry;
int rc_retries;
int rc_privport;
char *rc_waitchan;
int rc_intr;
int rc_connecting;
int rc_closed;
struct ucred *rc_ucred;
CLIENT* rc_client; /* underlying RPC client */
struct rpc_err rc_err;
void *rc_backchannel;
};
struct ct_data {
struct mtx ct_lock;
int ct_threads; /* number of threads in clnt_vc_call */
bool_t ct_closing; /* TRUE if we are closing */
bool_t ct_closed; /* TRUE if we are closed */
struct socket *ct_socket; /* connection socket */
bool_t ct_closeit; /* close it on destroy */
struct timeval ct_wait; /* wait interval in milliseconds */
struct sockaddr_storage ct_addr; /* remote addr */
struct rpc_err ct_error;
uint32_t ct_xid;
char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
size_t ct_mpos; /* pos after marshal */
const char *ct_waitchan;
int ct_waitflag;
struct mbuf *ct_record; /* current reply record */
size_t ct_record_resid; /* how much left of reply to read */
bool_t ct_record_eor; /* true if reading last fragment */
struct ct_request_list ct_pending;
int ct_upcallrefs; /* Ref cnt of upcalls in prog. */
SVCXPRT *ct_backchannelxprt; /* xprt for backchannel */
};
struct cf_conn { /* kept in xprt->xp_p1 for actual connection */
enum xprt_stat strm_stat;
struct mbuf *mpending; /* unparsed data read from the socket */
struct mbuf *mreq; /* current record being built from mpending */
uint32_t resid; /* number of bytes needed for fragment */
bool_t eor; /* reading last fragment of current record */
};
#endif /* _KERNEL */
#endif /* _RPC_KRPC_H_ */

69
freebsd/sys/rpc/nettype.h Normal file
View File

@ -0,0 +1,69 @@
/* $NetBSD: nettype.h,v 1.2 2000/07/06 03:17:19 christos Exp $ */
/* $FreeBSD$ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
*/
/*
* nettype.h, Nettype definitions.
* All for the topmost layer of rpc
*
*/
#ifndef _RPC_NETTYPE_H
#define _RPC_NETTYPE_H
#ifdef _KERNEL
#include <rpc/netconfig.h>
#else
#include <netconfig.h>
#endif
#define _RPC_NONE 0
#define _RPC_NETPATH 1
#define _RPC_VISIBLE 2
#define _RPC_CIRCUIT_V 3
#define _RPC_DATAGRAM_V 4
#define _RPC_CIRCUIT_N 5
#define _RPC_DATAGRAM_N 6
#define _RPC_TCP 7
#define _RPC_UDP 8
__BEGIN_DECLS
extern void *__rpc_setconf(const char *);
extern void __rpc_endconf(void *);
extern struct netconfig *__rpc_getconf(void *);
extern struct netconfig *__rpc_getconfip(const char *);
__END_DECLS
#endif /* !_RPC_NETTYPE_H */

108
freebsd/sys/rpc/pmap_prot.h Normal file
View File

@ -0,0 +1,108 @@
/* $NetBSD: pmap_prot.h,v 1.8 2000/06/02 22:57:55 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)pmap_prot.h 1.14 88/02/08 SMI
* from: @(#)pmap_prot.h 2.1 88/07/29 4.0 RPCSRC
* $FreeBSD$
*/
/*
* pmap_prot.h
* Protocol for the local binder service, or pmap.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* The following procedures are supported by the protocol:
*
* PMAPPROC_NULL() returns ()
* takes nothing, returns nothing
*
* PMAPPROC_SET(struct portmap) returns (bool_t)
* TRUE is success, FALSE is failure. Registers the tuple
* [prog, vers, prot, port].
*
* PMAPPROC_UNSET(struct portmap) returns (bool_t)
* TRUE is success, FALSE is failure. Un-registers pair
* [prog, vers]. prot and port are ignored.
*
* PMAPPROC_GETPORT(struct portmap) returns (long unsigned).
* 0 is failure. Otherwise returns the port number where the pair
* [prog, vers] is registered. It may lie!
*
* PMAPPROC_DUMP() RETURNS (struct pmaplist *)
*
* PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>)
* RETURNS (port, string<>);
* usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs);
* Calls the procedure on the local machine. If it is not registered,
* this procedure is quite; ie it does not return error information!!!
* This procedure only is supported on rpc/udp and calls via
* rpc/udp. This routine only passes null authentication parameters.
* This file has no interface to xdr routines for PMAPPROC_CALLIT.
*
* The service supports remote procedure calls on udp/ip or tcp/ip socket 111.
*/
#ifndef _RPC_PMAP_PROT_H
#define _RPC_PMAP_PROT_H
#include <sys/cdefs.h>
#define PMAPPORT ((u_short)111)
#define PMAPPROG ((u_long)100000)
#define PMAPVERS ((u_long)2)
#define PMAPVERS_PROTO ((u_long)2)
#define PMAPVERS_ORIG ((u_long)1)
#define PMAPPROC_NULL ((u_long)0)
#define PMAPPROC_SET ((u_long)1)
#define PMAPPROC_UNSET ((u_long)2)
#define PMAPPROC_GETPORT ((u_long)3)
#define PMAPPROC_DUMP ((u_long)4)
#define PMAPPROC_CALLIT ((u_long)5)
struct portmap {
long unsigned pm_prog;
long unsigned pm_vers;
long unsigned pm_prot;
long unsigned pm_port;
};
struct pmaplist {
struct portmap pml_map;
struct pmaplist *pml_next;
};
__BEGIN_DECLS
extern bool_t xdr_portmap(XDR *, struct portmap *);
extern bool_t xdr_pmaplist(XDR *, struct pmaplist **);
extern bool_t xdr_pmaplist_ptr(XDR *, struct pmaplist *);
__END_DECLS
#endif /* !_RPC_PMAP_PROT_H */

258
freebsd/sys/rpc/replay.c Normal file
View File

@ -0,0 +1,258 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/queue.h>
#include <rpc/rpc.h>
#include <rpc/replay.h>
struct replay_cache_entry {
int rce_hash;
struct rpc_msg rce_msg;
struct sockaddr_storage rce_addr;
struct rpc_msg rce_repmsg;
struct mbuf *rce_repbody;
TAILQ_ENTRY(replay_cache_entry) rce_link;
TAILQ_ENTRY(replay_cache_entry) rce_alllink;
};
TAILQ_HEAD(replay_cache_list, replay_cache_entry);
static struct replay_cache_entry *
replay_alloc(struct replay_cache *rc, struct rpc_msg *msg,
struct sockaddr *addr, int h);
static void replay_free(struct replay_cache *rc,
struct replay_cache_entry *rce);
static void replay_prune(struct replay_cache *rc);
#define REPLAY_HASH_SIZE 256
#define REPLAY_MAX 1024
struct replay_cache {
struct replay_cache_list rc_cache[REPLAY_HASH_SIZE];
struct replay_cache_list rc_all;
struct mtx rc_lock;
int rc_count;
size_t rc_size;
size_t rc_maxsize;
};
struct replay_cache *
replay_newcache(size_t maxsize)
{
struct replay_cache *rc;
int i;
rc = malloc(sizeof(*rc), M_RPC, M_WAITOK|M_ZERO);
for (i = 0; i < REPLAY_HASH_SIZE; i++)
TAILQ_INIT(&rc->rc_cache[i]);
TAILQ_INIT(&rc->rc_all);
mtx_init(&rc->rc_lock, "rc_lock", NULL, MTX_DEF);
rc->rc_maxsize = maxsize;
return (rc);
}
void
replay_setsize(struct replay_cache *rc, size_t newmaxsize)
{
mtx_lock(&rc->rc_lock);
rc->rc_maxsize = newmaxsize;
replay_prune(rc);
mtx_unlock(&rc->rc_lock);
}
void
replay_freecache(struct replay_cache *rc)
{
mtx_lock(&rc->rc_lock);
while (TAILQ_FIRST(&rc->rc_all))
replay_free(rc, TAILQ_FIRST(&rc->rc_all));
mtx_destroy(&rc->rc_lock);
free(rc, M_RPC);
}
static struct replay_cache_entry *
replay_alloc(struct replay_cache *rc,
struct rpc_msg *msg, struct sockaddr *addr, int h)
{
struct replay_cache_entry *rce;
mtx_assert(&rc->rc_lock, MA_OWNED);
rc->rc_count++;
rce = malloc(sizeof(*rce), M_RPC, M_NOWAIT|M_ZERO);
if (!rce)
return (NULL);
rce->rce_hash = h;
rce->rce_msg = *msg;
bcopy(addr, &rce->rce_addr, addr->sa_len);
TAILQ_INSERT_HEAD(&rc->rc_cache[h], rce, rce_link);
TAILQ_INSERT_HEAD(&rc->rc_all, rce, rce_alllink);
return (rce);
}
static void
replay_free(struct replay_cache *rc, struct replay_cache_entry *rce)
{
mtx_assert(&rc->rc_lock, MA_OWNED);
rc->rc_count--;
TAILQ_REMOVE(&rc->rc_cache[rce->rce_hash], rce, rce_link);
TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink);
if (rce->rce_repbody) {
rc->rc_size -= m_length(rce->rce_repbody, NULL);
m_freem(rce->rce_repbody);
}
free(rce, M_RPC);
}
static void
replay_prune(struct replay_cache *rc)
{
struct replay_cache_entry *rce;
mtx_assert(&rc->rc_lock, MA_OWNED);
if (rc->rc_count < REPLAY_MAX && rc->rc_size <= rc->rc_maxsize)
return;
do {
/*
* Try to free an entry. Don't free in-progress entries.
*/
TAILQ_FOREACH_REVERSE(rce, &rc->rc_all, replay_cache_list,
rce_alllink) {
if (rce->rce_repmsg.rm_xid)
break;
}
if (rce)
replay_free(rc, rce);
} while (rce && (rc->rc_count >= REPLAY_MAX
|| rc->rc_size > rc->rc_maxsize));
}
enum replay_state
replay_find(struct replay_cache *rc, struct rpc_msg *msg,
struct sockaddr *addr, struct rpc_msg *repmsg, struct mbuf **mp)
{
int h = HASHSTEP(HASHINIT, msg->rm_xid) % REPLAY_HASH_SIZE;
struct replay_cache_entry *rce;
mtx_lock(&rc->rc_lock);
TAILQ_FOREACH(rce, &rc->rc_cache[h], rce_link) {
if (rce->rce_msg.rm_xid == msg->rm_xid
&& rce->rce_msg.rm_call.cb_prog == msg->rm_call.cb_prog
&& rce->rce_msg.rm_call.cb_vers == msg->rm_call.cb_vers
&& rce->rce_msg.rm_call.cb_proc == msg->rm_call.cb_proc
&& rce->rce_addr.ss_len == addr->sa_len
&& bcmp(&rce->rce_addr, addr, addr->sa_len) == 0) {
if (rce->rce_repmsg.rm_xid) {
/*
* We have a reply for this
* message. Copy it and return. Keep
* replay_all LRU sorted
*/
TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink);
TAILQ_INSERT_HEAD(&rc->rc_all, rce,
rce_alllink);
*repmsg = rce->rce_repmsg;
if (rce->rce_repbody) {
*mp = m_copym(rce->rce_repbody,
0, M_COPYALL, M_NOWAIT);
mtx_unlock(&rc->rc_lock);
if (!*mp)
return (RS_ERROR);
} else {
mtx_unlock(&rc->rc_lock);
}
return (RS_DONE);
} else {
mtx_unlock(&rc->rc_lock);
return (RS_INPROGRESS);
}
}
}
replay_prune(rc);
rce = replay_alloc(rc, msg, addr, h);
mtx_unlock(&rc->rc_lock);
if (!rce)
return (RS_ERROR);
else
return (RS_NEW);
}
void
replay_setreply(struct replay_cache *rc,
struct rpc_msg *repmsg, struct sockaddr *addr, struct mbuf *m)
{
int h = HASHSTEP(HASHINIT, repmsg->rm_xid) % REPLAY_HASH_SIZE;
struct replay_cache_entry *rce;
/*
* Copy the reply before the lock so we can sleep.
*/
if (m)
m = m_copym(m, 0, M_COPYALL, M_WAITOK);
mtx_lock(&rc->rc_lock);
TAILQ_FOREACH(rce, &rc->rc_cache[h], rce_link) {
if (rce->rce_msg.rm_xid == repmsg->rm_xid
&& rce->rce_addr.ss_len == addr->sa_len
&& bcmp(&rce->rce_addr, addr, addr->sa_len) == 0) {
break;
}
}
if (rce) {
rce->rce_repmsg = *repmsg;
rce->rce_repbody = m;
if (m)
rc->rc_size += m_length(m, NULL);
}
mtx_unlock(&rc->rc_lock);
}

87
freebsd/sys/rpc/replay.h Normal file
View File

@ -0,0 +1,87 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _RPC_REPLAY_H
#define _RPC_REPLAY_H
enum replay_state {
RS_NEW, /* new request - caller should execute */
RS_DONE, /* request was executed and reply sent */
RS_INPROGRESS, /* request is being executed now */
RS_ERROR /* allocation or other failure */
};
struct replay_cache;
/*
* Create a new replay cache.
*/
struct replay_cache *replay_newcache(size_t);
/*
* Set the replay cache size.
*/
void replay_setsize(struct replay_cache *, size_t);
/*
* Free a replay cache. Caller must ensure that no cache entries are
* in-progress.
*/
void replay_freecache(struct replay_cache *rc);
/*
* Check a replay cache for a message from a given address.
*
* If this is a new request, RS_NEW is returned. Caller should call
* replay_setreply with the results of the request.
*
* If this is a request which is currently executing
* (i.e. replay_setreply hasn't been called for it yet), RS_INPROGRESS
* is returned. The caller should silently drop the request.
*
* If a reply to this message already exists, *repmsg and *mp are set
* to point at the reply and, RS_DONE is returned. The caller should
* re-send this reply.
*
* If the attempt to update the replay cache or copy a replay failed
* for some reason (typically memory shortage), RS_ERROR is returned.
*/
enum replay_state replay_find(struct replay_cache *rc,
struct rpc_msg *msg, struct sockaddr *addr,
struct rpc_msg *repmsg, struct mbuf **mp);
/*
* Call this after executing a request to record the reply.
*/
void replay_setreply(struct replay_cache *rc,
struct rpc_msg *repmsg, struct sockaddr *addr, struct mbuf *m);
#endif /* !_RPC_REPLAY_H */

126
freebsd/sys/rpc/rpc.h Normal file
View File

@ -0,0 +1,126 @@
/* $NetBSD: rpc.h,v 1.13 2000/06/02 22:57:56 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)rpc.h 1.9 88/02/08 SMI
* from: @(#)rpc.h 2.4 89/07/11 4.0 RPCSRC
* $FreeBSD$
*/
/*
* rpc.h, Just includes the billions of rpc header files necessary to
* do remote procedure calling.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#ifndef _RPC_RPC_H
#define _RPC_RPC_H
#include <rpc/types.h> /* some typedefs */
#include <sys/socket.h>
#include <netinet/in.h>
/* external data representation interfaces */
#include <rpc/xdr.h> /* generic (de)serializer */
/* Client side only authentication */
#include <rpc/auth.h> /* generic authenticator (client side) */
/* Client side (mostly) remote procedure call */
#include <rpc/clnt.h> /* generic rpc stuff */
/* semi-private protocol headers */
#include <rpc/rpc_msg.h> /* protocol for rpc messages */
#ifndef _KERNEL
#include <rpc/auth_unix.h> /* protocol for unix style cred */
/*
* Uncomment-out the next line if you are building the rpc library with
* DES Authentication (see the README file in the secure_rpc/ directory).
*/
#include <rpc/auth_des.h> /* protocol for des style cred */
#endif
/* Server side only remote procedure callee */
#include <rpc/svc.h> /* service manager and multiplexer */
#include <rpc/svc_auth.h> /* service side authenticator */
#ifndef _KERNEL
/* Portmapper client, server, and protocol headers */
#include <rpc/pmap_clnt.h>
#endif
#include <rpc/pmap_prot.h>
#include <rpc/rpcb_clnt.h> /* rpcbind interface functions */
#ifndef _KERNEL
#include <rpc/rpcent.h>
#endif
#ifndef UDPMSGSIZE
#define UDPMSGSIZE 8800
#endif
__BEGIN_DECLS
extern int get_myaddress(struct sockaddr_in *);
#ifndef _KERNEL
extern int bindresvport(int, struct sockaddr_in *);
#endif
extern int registerrpc(int, int, int, char *(*)(char [UDPMSGSIZE]),
xdrproc_t, xdrproc_t);
extern int callrpc(const char *, int, int, int, xdrproc_t, void *,
xdrproc_t , void *);
extern int getrpcport(char *, int, int, int);
char *taddr2uaddr(const struct netconfig *, const struct netbuf *);
struct netbuf *uaddr2taddr(const struct netconfig *, const char *);
struct sockaddr;
extern int bindresvport_sa(int, struct sockaddr *);
__END_DECLS
/*
* The following are not exported interfaces, they are for internal library
* and rpcbind use only. Do not use, they may change without notice.
*/
__BEGIN_DECLS
#ifndef _KERNEL
int __rpc_nconf2fd(const struct netconfig *);
int __rpc_nconf2sockinfo(const struct netconfig *, struct __rpc_sockinfo *);
int __rpc_fd2sockinfo(int, struct __rpc_sockinfo *);
#else
struct socket *__rpc_nconf2socket(const struct netconfig *);
int __rpc_nconf2sockinfo(const struct netconfig *, struct __rpc_sockinfo *);
int __rpc_socket2sockinfo(struct socket *, struct __rpc_sockinfo *);
#endif
u_int __rpc_get_t_size(int, int, int);
__END_DECLS
#endif /* !_RPC_RPC_H */

View File

@ -0,0 +1,201 @@
/* $NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* rpc_callmsg.c
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <rpc/rpc.h>
/*
* XDR a call message
*/
bool_t
xdr_callmsg(XDR *xdrs, struct rpc_msg *cmsg)
{
enum msg_type *prm_direction;
int32_t *buf;
struct opaque_auth *oa;
if (xdrs->x_op == XDR_ENCODE) {
if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
+ RNDUP(cmsg->rm_call.cb_cred.oa_length)
+ 2 * BYTES_PER_XDR_UNIT
+ RNDUP(cmsg->rm_call.cb_verf.oa_length));
if (buf != NULL) {
IXDR_PUT_INT32(buf, cmsg->rm_xid);
IXDR_PUT_ENUM(buf, cmsg->rm_direction);
if (cmsg->rm_direction != CALL) {
return (FALSE);
}
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers);
if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
return (FALSE);
}
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog);
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers);
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc);
oa = &cmsg->rm_call.cb_cred;
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_INT32(buf, oa->oa_length);
if (oa->oa_length) {
memcpy(buf, oa->oa_base, oa->oa_length);
buf += RNDUP(oa->oa_length) / sizeof (int32_t);
}
oa = &cmsg->rm_call.cb_verf;
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_INT32(buf, oa->oa_length);
if (oa->oa_length) {
memcpy(buf, oa->oa_base, oa->oa_length);
/* no real need....
buf += RNDUP(oa->oa_length) / sizeof (int32_t);
*/
}
return (TRUE);
}
}
if (xdrs->x_op == XDR_DECODE) {
buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
if (buf != NULL) {
cmsg->rm_xid = IXDR_GET_UINT32(buf);
cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
if (cmsg->rm_direction != CALL) {
return (FALSE);
}
cmsg->rm_call.cb_rpcvers = IXDR_GET_UINT32(buf);
if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
return (FALSE);
}
cmsg->rm_call.cb_prog = IXDR_GET_UINT32(buf);
cmsg->rm_call.cb_vers = IXDR_GET_UINT32(buf);
cmsg->rm_call.cb_proc = IXDR_GET_UINT32(buf);
oa = &cmsg->rm_call.cb_cred;
oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
oa->oa_length = (u_int)IXDR_GET_UINT32(buf);
if (oa->oa_length) {
if (oa->oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
if (oa->oa_base == NULL) {
oa->oa_base = (caddr_t)
mem_alloc(oa->oa_length);
if (oa->oa_base == NULL)
return (FALSE);
}
buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
if (buf == NULL) {
if (xdr_opaque(xdrs, oa->oa_base,
oa->oa_length) == FALSE) {
return (FALSE);
}
} else {
memcpy(oa->oa_base, buf,
oa->oa_length);
/* no real need....
buf += RNDUP(oa->oa_length) /
sizeof (int32_t);
*/
}
}
oa = &cmsg->rm_call.cb_verf;
buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
return (FALSE);
}
} else {
oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
oa->oa_length = (u_int)IXDR_GET_UINT32(buf);
}
if (oa->oa_length) {
if (oa->oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
if (oa->oa_base == NULL) {
oa->oa_base = (caddr_t)
mem_alloc(oa->oa_length);
if (oa->oa_base == NULL)
return (FALSE);
}
buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
if (buf == NULL) {
if (xdr_opaque(xdrs, oa->oa_base,
oa->oa_length) == FALSE) {
return (FALSE);
}
} else {
memcpy(oa->oa_base, buf,
oa->oa_length);
/* no real need...
buf += RNDUP(oa->oa_length) /
sizeof (int32_t);
*/
}
}
return (TRUE);
}
}
prm_direction = &cmsg->rm_direction;
if (
xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
xdr_enum(xdrs, (enum_t *) prm_direction) &&
(cmsg->rm_direction == CALL) &&
xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
(cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) &&
xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)) &&
xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_proc)) &&
xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
return (FALSE);
}

124
freebsd/sys/rpc/rpc_com.h Normal file
View File

@ -0,0 +1,124 @@
/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* $FreeBSD$
*/
/*
* Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
*/
/*
* rpc_com.h, Common definitions for both the server and client side.
* All for the topmost layer of rpc
*
* In Sun's tirpc distribution, this was installed as <rpc/rpc_com.h>,
* but as it contains only non-exported interfaces, it was moved here.
*/
#ifndef _RPC_RPCCOM_H
#define _RPC_RPCCOM_H
#include <sys/cdefs.h>
/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */
/*
* The max size of the transport, if the size cannot be determined
* by other means.
*/
#define RPC_MAXDATASIZE 9000
#define RPC_MAXADDRSIZE 1024
#ifdef _KERNEL
#define __RPC_GETXID(now) ((uint32_t)curproc->p_pid ^ (uint32_t)(now)->tv_sec ^ \
(uint32_t)(now)->tv_usec)
#else
#define __RPC_GETXID(now) ((uint32_t)getpid() ^ (uint32_t)(now)->tv_sec ^ \
(uint32_t)(now)->tv_usec)
#endif
__BEGIN_DECLS
#ifndef _KERNEL
extern u_int __rpc_get_a_size(int);
extern int __rpc_dtbsize(void);
extern struct netconfig * __rpcgettp(int);
extern int __rpc_get_default_domain(char **);
char *__rpc_taddr2uaddr_af(int, const struct netbuf *);
struct netbuf *__rpc_uaddr2taddr_af(int, const char *);
int __rpc_fixup_addr(struct netbuf *, const struct netbuf *);
int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **);
int __rpc_seman2socktype(int);
int __rpc_socktype2seman(int);
void *rpc_nullproc(CLIENT *);
int __rpc_sockisbound(int);
struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t,
const struct netconfig *, const char *host, CLIENT **clpp,
struct timeval *tp);
bool_t __rpc_control(int,void *);
char *_get_next_token(char *, int);
bool_t __svc_clean_idle(fd_set *, int, bool_t);
bool_t __xdrrec_setnonblock(XDR *, int);
bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
void __xprt_unregister_unlocked(SVCXPRT *);
SVCXPRT **__svc_xports;
int __svc_maxrec;
#else
#define SUN_LEN(su) \
(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
extern u_int __rpc_get_a_size(int);
extern char *__rpc_taddr2uaddr_af(int, const struct netbuf *);
extern struct netbuf *__rpc_uaddr2taddr_af(int, const char *);
extern int __rpc_seman2socktype(int);
extern int __rpc_socktype2seman(int);
extern int __rpc_sockisbound(struct socket*);
extern int bindresvport(struct socket *so, struct sockaddr *sa);
struct xucred;
struct XDR;
bool_t xdr_authunix_parms(struct XDR *xdrs, uint32_t *time, struct xucred *cred);
#endif
__END_DECLS
#endif /* _RPC_RPCCOM_H */

View File

@ -0,0 +1,888 @@
/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* rpc_generic.c, Miscl routines for RPC.
*
*/
#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/sbuf.h>
#include <sys/systm.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/syslog.h>
#include <net/vnet.h>
#include <rpc/rpc.h>
#include <rpc/nettype.h>
#include <rpc/rpcsec_gss.h>
#include <rpc/rpc_com.h>
extern u_long sb_max_adj; /* not defined in socketvar.h */
#if __FreeBSD_version < 700000
#define strrchr rindex
#endif
/* Provide an entry point hook for the rpcsec_gss module. */
struct rpc_gss_entries rpc_gss_entries;
struct handle {
NCONF_HANDLE *nhandle;
int nflag; /* Whether NETPATH or NETCONFIG */
int nettype;
};
static const struct _rpcnettype {
const char *name;
const int type;
} _rpctypelist[] = {
{ "netpath", _RPC_NETPATH },
{ "visible", _RPC_VISIBLE },
{ "circuit_v", _RPC_CIRCUIT_V },
{ "datagram_v", _RPC_DATAGRAM_V },
{ "circuit_n", _RPC_CIRCUIT_N },
{ "datagram_n", _RPC_DATAGRAM_N },
{ "tcp", _RPC_TCP },
{ "udp", _RPC_UDP },
{ 0, _RPC_NONE }
};
struct netid_af {
const char *netid;
int af;
int protocol;
};
static const struct netid_af na_cvt[] = {
{ "udp", AF_INET, IPPROTO_UDP },
{ "tcp", AF_INET, IPPROTO_TCP },
#ifdef INET6
{ "udp6", AF_INET6, IPPROTO_UDP },
{ "tcp6", AF_INET6, IPPROTO_TCP },
#endif
{ "local", AF_LOCAL, 0 }
};
struct rpc_createerr rpc_createerr;
/*
* Find the appropriate buffer size
*/
u_int
/*ARGSUSED*/
__rpc_get_t_size(int af, int proto, int size)
{
int defsize;
switch (proto) {
case IPPROTO_TCP:
defsize = 64 * 1024; /* XXX */
break;
case IPPROTO_UDP:
defsize = UDPMSGSIZE;
break;
default:
defsize = RPC_MAXDATASIZE;
break;
}
if (size == 0)
return defsize;
/* Check whether the value is within the upper max limit */
return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
}
/*
* Find the appropriate address buffer size
*/
u_int
__rpc_get_a_size(af)
int af;
{
switch (af) {
case AF_INET:
return sizeof (struct sockaddr_in);
#ifdef INET6
case AF_INET6:
return sizeof (struct sockaddr_in6);
#endif
case AF_LOCAL:
return sizeof (struct sockaddr_un);
default:
break;
}
return ((u_int)RPC_MAXADDRSIZE);
}
#if 0
/*
* Used to ping the NULL procedure for clnt handle.
* Returns NULL if fails, else a non-NULL pointer.
*/
void *
rpc_nullproc(clnt)
CLIENT *clnt;
{
struct timeval TIMEOUT = {25, 0};
if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return ((void *) clnt);
}
#endif
int
__rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
{
int type, proto;
struct sockaddr *sa;
sa_family_t family;
struct sockopt opt;
int error;
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
CURVNET_RESTORE();
if (error)
return 0;
sip->si_alen = sa->sa_len;
family = sa->sa_family;
free(sa, M_SONAME);
opt.sopt_dir = SOPT_GET;
opt.sopt_level = SOL_SOCKET;
opt.sopt_name = SO_TYPE;
opt.sopt_val = &type;
opt.sopt_valsize = sizeof type;
opt.sopt_td = NULL;
error = sogetopt(so, &opt);
if (error)
return 0;
/* XXX */
if (family != AF_LOCAL) {
if (type == SOCK_STREAM)
proto = IPPROTO_TCP;
else if (type == SOCK_DGRAM)
proto = IPPROTO_UDP;
else
return 0;
} else
proto = 0;
sip->si_af = family;
sip->si_proto = proto;
sip->si_socktype = type;
return 1;
}
/*
* Linear search, but the number of entries is small.
*/
int
__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
{
int i;
for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
strcmp(nconf->nc_netid, "unix") == 0 &&
strcmp(na_cvt[i].netid, "local") == 0)) {
sip->si_af = na_cvt[i].af;
sip->si_proto = na_cvt[i].protocol;
sip->si_socktype =
__rpc_seman2socktype((int)nconf->nc_semantics);
if (sip->si_socktype == -1)
return 0;
sip->si_alen = __rpc_get_a_size(sip->si_af);
return 1;
}
return 0;
}
struct socket *
__rpc_nconf2socket(const struct netconfig *nconf)
{
struct __rpc_sockinfo si;
struct socket *so;
int error;
if (!__rpc_nconf2sockinfo(nconf, &si))
return 0;
so = NULL;
error = socreate(si.si_af, &so, si.si_socktype, si.si_proto,
curthread->td_ucred, curthread);
if (error)
return NULL;
else
return so;
}
char *
taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return NULL;
return __rpc_taddr2uaddr_af(si.si_af, nbuf);
}
struct netbuf *
uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return NULL;
return __rpc_uaddr2taddr_af(si.si_af, uaddr);
}
char *
__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
{
char *ret;
struct sbuf sb;
struct sockaddr_in *sin;
struct sockaddr_un *sun;
char namebuf[INET_ADDRSTRLEN];
#ifdef INET6
struct sockaddr_in6 *sin6;
char namebuf6[INET6_ADDRSTRLEN];
#endif
u_int16_t port;
sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
switch (af) {
case AF_INET:
if (nbuf->len < sizeof(*sin))
return NULL;
sin = nbuf->buf;
if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
== NULL)
return NULL;
port = ntohs(sin->sin_port);
if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
((uint32_t)port) >> 8,
port & 0xff) < 0)
return NULL;
break;
#ifdef INET6
case AF_INET6:
if (nbuf->len < sizeof(*sin6))
return NULL;
sin6 = nbuf->buf;
if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
== NULL)
return NULL;
port = ntohs(sin6->sin6_port);
if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
((uint32_t)port) >> 8,
port & 0xff) < 0)
return NULL;
break;
#endif
case AF_LOCAL:
sun = nbuf->buf;
if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
offsetof(struct sockaddr_un, sun_path)),
sun->sun_path) < 0)
return (NULL);
break;
default:
return NULL;
}
sbuf_finish(&sb);
ret = strdup(sbuf_data(&sb), M_RPC);
sbuf_delete(&sb);
return ret;
}
struct netbuf *
__rpc_uaddr2taddr_af(int af, const char *uaddr)
{
struct netbuf *ret = NULL;
char *addrstr, *p;
unsigned port, portlo, porthi;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sockaddr_un *sun;
port = 0;
sin = NULL;
if (uaddr == NULL)
return NULL;
addrstr = strdup(uaddr, M_RPC);
if (addrstr == NULL)
return NULL;
/*
* AF_LOCAL addresses are expected to be absolute
* pathnames, anything else will be AF_INET or AF_INET6.
*/
if (*addrstr != '/') {
p = strrchr(addrstr, '.');
if (p == NULL)
goto out;
portlo = (unsigned)strtol(p + 1, NULL, 10);
*p = '\0';
p = strrchr(addrstr, '.');
if (p == NULL)
goto out;
porthi = (unsigned)strtol(p + 1, NULL, 10);
*p = '\0';
port = (porthi << 8) | portlo;
}
ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
switch (af) {
case AF_INET:
sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
M_WAITOK);
memset(sin, 0, sizeof *sin);
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
free(sin, M_RPC);
free(ret, M_RPC);
ret = NULL;
goto out;
}
sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
ret->buf = sin;
break;
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
M_WAITOK);
memset(sin6, 0, sizeof *sin6);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
free(sin6, M_RPC);
free(ret, M_RPC);
ret = NULL;
goto out;
}
sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
ret->buf = sin6;
break;
#endif
case AF_LOCAL:
sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
M_WAITOK);
memset(sun, 0, sizeof *sun);
sun->sun_family = AF_LOCAL;
strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
ret->buf = sun;
break;
default:
break;
}
out:
free(addrstr, M_RPC);
return ret;
}
int
__rpc_seman2socktype(int semantics)
{
switch (semantics) {
case NC_TPI_CLTS:
return SOCK_DGRAM;
case NC_TPI_COTS_ORD:
return SOCK_STREAM;
case NC_TPI_RAW:
return SOCK_RAW;
default:
break;
}
return -1;
}
int
__rpc_socktype2seman(int socktype)
{
switch (socktype) {
case SOCK_DGRAM:
return NC_TPI_CLTS;
case SOCK_STREAM:
return NC_TPI_COTS_ORD;
case SOCK_RAW:
return NC_TPI_RAW;
default:
break;
}
return -1;
}
/*
* Returns the type of the network as defined in <rpc/nettype.h>
* If nettype is NULL, it defaults to NETPATH.
*/
static int
getnettype(const char *nettype)
{
int i;
if ((nettype == NULL) || (nettype[0] == 0)) {
return (_RPC_NETPATH); /* Default */
}
#if 0
nettype = strlocase(nettype);
#endif
for (i = 0; _rpctypelist[i].name; i++)
if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
return (_rpctypelist[i].type);
}
return (_rpctypelist[i].type);
}
/*
* For the given nettype (tcp or udp only), return the first structure found.
* This should be freed by calling freenetconfigent()
*/
struct netconfig *
__rpc_getconfip(const char *nettype)
{
char *netid;
static char *netid_tcp = (char *) NULL;
static char *netid_udp = (char *) NULL;
struct netconfig *dummy;
if (!netid_udp && !netid_tcp) {
struct netconfig *nconf;
void *confighandle;
if (!(confighandle = setnetconfig())) {
log(LOG_ERR, "rpc: failed to open " NETCONFIG);
return (NULL);
}
while ((nconf = getnetconfig(confighandle)) != NULL) {
if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
netid_tcp = strdup(nconf->nc_netid,
M_RPC);
} else
if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
netid_udp = strdup(nconf->nc_netid,
M_RPC);
}
}
}
endnetconfig(confighandle);
}
if (strcmp(nettype, "udp") == 0)
netid = netid_udp;
else if (strcmp(nettype, "tcp") == 0)
netid = netid_tcp;
else {
return (NULL);
}
if ((netid == NULL) || (netid[0] == 0)) {
return (NULL);
}
dummy = getnetconfigent(netid);
return (dummy);
}
/*
* Returns the type of the nettype, which should then be used with
* __rpc_getconf().
*
* For simplicity in the kernel, we don't support the NETPATH
* environment variable. We behave as userland would then NETPATH is
* unset, i.e. iterate over all visible entries in netconfig.
*/
void *
__rpc_setconf(nettype)
const char *nettype;
{
struct handle *handle;
handle = (struct handle *) malloc(sizeof (struct handle),
M_RPC, M_WAITOK);
switch (handle->nettype = getnettype(nettype)) {
case _RPC_NETPATH:
case _RPC_CIRCUIT_N:
case _RPC_DATAGRAM_N:
if (!(handle->nhandle = setnetconfig()))
goto failed;
handle->nflag = TRUE;
break;
case _RPC_VISIBLE:
case _RPC_CIRCUIT_V:
case _RPC_DATAGRAM_V:
case _RPC_TCP:
case _RPC_UDP:
if (!(handle->nhandle = setnetconfig())) {
log(LOG_ERR, "rpc: failed to open " NETCONFIG);
goto failed;
}
handle->nflag = FALSE;
break;
default:
goto failed;
}
return (handle);
failed:
free(handle, M_RPC);
return (NULL);
}
/*
* Returns the next netconfig struct for the given "net" type.
* __rpc_setconf() should have been called previously.
*/
struct netconfig *
__rpc_getconf(void *vhandle)
{
struct handle *handle;
struct netconfig *nconf;
handle = (struct handle *)vhandle;
if (handle == NULL) {
return (NULL);
}
for (;;) {
if (handle->nflag) {
nconf = getnetconfig(handle->nhandle);
if (nconf && !(nconf->nc_flag & NC_VISIBLE))
continue;
} else {
nconf = getnetconfig(handle->nhandle);
}
if (nconf == NULL)
break;
if ((nconf->nc_semantics != NC_TPI_CLTS) &&
(nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
continue;
switch (handle->nettype) {
case _RPC_VISIBLE:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_NETPATH: /* Be happy */
break;
case _RPC_CIRCUIT_V:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_CIRCUIT_N:
if ((nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
continue;
break;
case _RPC_DATAGRAM_V:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_DATAGRAM_N:
if (nconf->nc_semantics != NC_TPI_CLTS)
continue;
break;
case _RPC_TCP:
if (((nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
(strcmp(nconf->nc_protofmly, NC_INET)
#ifdef INET6
&& strcmp(nconf->nc_protofmly, NC_INET6))
#else
)
#endif
||
strcmp(nconf->nc_proto, NC_TCP))
continue;
break;
case _RPC_UDP:
if ((nconf->nc_semantics != NC_TPI_CLTS) ||
(strcmp(nconf->nc_protofmly, NC_INET)
#ifdef INET6
&& strcmp(nconf->nc_protofmly, NC_INET6))
#else
)
#endif
||
strcmp(nconf->nc_proto, NC_UDP))
continue;
break;
}
break;
}
return (nconf);
}
void
__rpc_endconf(vhandle)
void * vhandle;
{
struct handle *handle;
handle = (struct handle *) vhandle;
if (handle == NULL) {
return;
}
endnetconfig(handle->nhandle);
free(handle, M_RPC);
}
int
__rpc_sockisbound(struct socket *so)
{
struct sockaddr *sa;
int error, bound;
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
CURVNET_RESTORE();
if (error)
return (0);
switch (sa->sa_family) {
case AF_INET:
bound = (((struct sockaddr_in *) sa)->sin_port != 0);
break;
#ifdef INET6
case AF_INET6:
bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
break;
#endif
case AF_LOCAL:
/* XXX check this */
bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
break;
default:
bound = FALSE;
break;
}
free(sa, M_SONAME);
return bound;
}
/*
* Implement XDR-style API for RPC call.
*/
enum clnt_stat
clnt_call_private(
CLIENT *cl, /* client handle */
struct rpc_callextra *ext, /* call metadata */
rpcproc_t proc, /* procedure number */
xdrproc_t xargs, /* xdr routine for args */
void *argsp, /* pointer to args */
xdrproc_t xresults, /* xdr routine for results */
void *resultsp, /* pointer to results */
struct timeval utimeout) /* seconds to wait before giving up */
{
XDR xdrs;
struct mbuf *mreq;
struct mbuf *mrep;
enum clnt_stat stat;
mreq = m_getcl(M_WAITOK, MT_DATA, 0);
xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
if (!xargs(&xdrs, argsp)) {
m_freem(mreq);
return (RPC_CANTENCODEARGS);
}
XDR_DESTROY(&xdrs);
stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout);
m_freem(mreq);
if (stat == RPC_SUCCESS) {
xdrmbuf_create(&xdrs, mrep, XDR_DECODE);
if (!xresults(&xdrs, resultsp)) {
XDR_DESTROY(&xdrs);
return (RPC_CANTDECODERES);
}
XDR_DESTROY(&xdrs);
}
return (stat);
}
/*
* Bind a socket to a privileged IP port
*/
int
bindresvport(struct socket *so, struct sockaddr *sa)
{
int old, error, af;
bool_t freesa = FALSE;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sockopt opt;
int proto, portrange, portlow;
u_int16_t *portp;
socklen_t salen;
if (sa == NULL) {
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
CURVNET_RESTORE();
if (error)
return (error);
freesa = TRUE;
af = sa->sa_family;
salen = sa->sa_len;
memset(sa, 0, sa->sa_len);
} else {
af = sa->sa_family;
salen = sa->sa_len;
}
switch (af) {
case AF_INET:
proto = IPPROTO_IP;
portrange = IP_PORTRANGE;
portlow = IP_PORTRANGE_LOW;
sin = (struct sockaddr_in *)sa;
portp = &sin->sin_port;
break;
#ifdef INET6
case AF_INET6:
proto = IPPROTO_IPV6;
portrange = IPV6_PORTRANGE;
portlow = IPV6_PORTRANGE_LOW;
sin6 = (struct sockaddr_in6 *)sa;
portp = &sin6->sin6_port;
break;
#endif
default:
return (EPFNOSUPPORT);
}
sa->sa_family = af;
sa->sa_len = salen;
if (*portp == 0) {
bzero(&opt, sizeof(opt));
opt.sopt_dir = SOPT_GET;
opt.sopt_level = proto;
opt.sopt_name = portrange;
opt.sopt_val = &old;
opt.sopt_valsize = sizeof(old);
error = sogetopt(so, &opt);
if (error) {
goto out;
}
opt.sopt_dir = SOPT_SET;
opt.sopt_val = &portlow;
error = sosetopt(so, &opt);
if (error)
goto out;
}
error = sobind(so, sa, curthread);
if (*portp == 0) {
if (error) {
opt.sopt_dir = SOPT_SET;
opt.sopt_val = &old;
sosetopt(so, &opt);
}
}
out:
if (freesa)
free(sa, M_SONAME);
return (error);
}
/*
* Kernel module glue
*/
static int
krpc_modevent(module_t mod, int type, void *data)
{
return (0);
}
static moduledata_t krpc_mod = {
"krpc",
krpc_modevent,
NULL,
};
DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
/* So that loader and kldload(2) can find us, wherever we are.. */
MODULE_VERSION(krpc, 1);

215
freebsd/sys/rpc/rpc_msg.h Normal file
View File

@ -0,0 +1,215 @@
/* $NetBSD: rpc_msg.h,v 1.11 2000/06/02 22:57:56 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)rpc_msg.h 1.7 86/07/16 SMI
* from: @(#)rpc_msg.h 2.1 88/07/29 4.0 RPCSRC
* $FreeBSD$
*/
/*
* rpc_msg.h
* rpc message definition
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#ifndef _RPC_RPC_MSG_H
#define _RPC_RPC_MSG_H
#define RPC_MSG_VERSION ((uint32_t) 2)
#define RPC_SERVICE_PORT ((u_short) 2048)
/*
* Bottom up definition of an rpc message.
* NOTE: call and reply use the same overall stuct but
* different parts of unions within it.
*/
enum msg_type {
CALL=0,
REPLY=1
};
enum reply_stat {
MSG_ACCEPTED=0,
MSG_DENIED=1
};
enum accept_stat {
SUCCESS=0,
PROG_UNAVAIL=1,
PROG_MISMATCH=2,
PROC_UNAVAIL=3,
GARBAGE_ARGS=4,
SYSTEM_ERR=5
};
enum reject_stat {
RPC_MISMATCH=0,
AUTH_ERROR=1
};
/*
* Reply part of an rpc exchange
*/
/*
* Reply to an rpc request that was accepted by the server.
* Note: there could be an error even though the request was
* accepted.
*/
struct accepted_reply {
struct opaque_auth ar_verf;
enum accept_stat ar_stat;
union {
struct {
rpcvers_t low;
rpcvers_t high;
} AR_versions;
struct {
caddr_t where;
xdrproc_t proc;
} AR_results;
/* and many other null cases */
} ru;
#define ar_results ru.AR_results
#define ar_vers ru.AR_versions
};
/*
* Reply to an rpc request that was rejected by the server.
*/
struct rejected_reply {
enum reject_stat rj_stat;
union {
struct {
rpcvers_t low;
rpcvers_t high;
} RJ_versions;
enum auth_stat RJ_why; /* why authentication did not work */
} ru;
#define rj_vers ru.RJ_versions
#define rj_why ru.RJ_why
};
/*
* Body of a reply to an rpc request.
*/
struct reply_body {
enum reply_stat rp_stat;
union {
struct accepted_reply RP_ar;
struct rejected_reply RP_dr;
} ru;
#define rp_acpt ru.RP_ar
#define rp_rjct ru.RP_dr
};
/*
* Body of an rpc request call.
*/
struct call_body {
rpcvers_t cb_rpcvers; /* must be equal to two */
rpcprog_t cb_prog;
rpcvers_t cb_vers;
rpcproc_t cb_proc;
struct opaque_auth cb_cred;
struct opaque_auth cb_verf; /* protocol specific - provided by client */
};
/*
* The rpc message
*/
struct rpc_msg {
uint32_t rm_xid;
enum msg_type rm_direction;
union {
struct call_body RM_cmb;
struct reply_body RM_rmb;
} ru;
#define rm_call ru.RM_cmb
#define rm_reply ru.RM_rmb
};
#define acpted_rply ru.RM_rmb.ru.RP_ar
#define rjcted_rply ru.RM_rmb.ru.RP_dr
__BEGIN_DECLS
/*
* XDR routine to handle a rpc message.
* xdr_callmsg(xdrs, cmsg)
* XDR *xdrs;
* struct rpc_msg *cmsg;
*/
extern bool_t xdr_callmsg(XDR *, struct rpc_msg *);
/*
* XDR routine to pre-serialize the static part of a rpc message.
* xdr_callhdr(xdrs, cmsg)
* XDR *xdrs;
* struct rpc_msg *cmsg;
*/
extern bool_t xdr_callhdr(XDR *, struct rpc_msg *);
/*
* XDR routine to handle a rpc reply.
* xdr_replymsg(xdrs, rmsg)
* XDR *xdrs;
* struct rpc_msg *rmsg;
*/
extern bool_t xdr_replymsg(XDR *, struct rpc_msg *);
/*
* XDR routine to handle an accepted rpc reply.
* xdr_accepted_reply(xdrs, rej)
* XDR *xdrs;
* struct accepted_reply *rej;
*/
extern bool_t xdr_accepted_reply(XDR *, struct accepted_reply *);
/*
* XDR routine to handle a rejected rpc reply.
* xdr_rejected_reply(xdrs, rej)
* XDR *xdrs;
* struct rejected_reply *rej;
*/
extern bool_t xdr_rejected_reply(XDR *, struct rejected_reply *);
/*
* Fills in the error part of a reply message.
* _seterr_reply(msg, error)
* struct rpc_msg *msg;
* struct rpc_err *error;
*/
extern enum clnt_stat _seterr_reply(struct rpc_msg *, struct rpc_err *);
__END_DECLS
#endif /* !_RPC_RPC_MSG_H */

374
freebsd/sys/rpc/rpc_prot.c Normal file
View File

@ -0,0 +1,374 @@
/* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* rpc_prot.c
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* This set of routines implements the rpc message definition,
* its serializer and some common rpc utility routines.
* The routines are meant for various implementations of rpc -
* they are NOT for the rpc client or rpc service implementations!
* Because authentication stuff is easy and is part of rpc, the opaque
* routines are also in this program.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include <rpc/rpc_msg.h>
MALLOC_DEFINE(M_RPC, "rpc", "Remote Procedure Call");
#define assert(exp) KASSERT(exp, ("bad arguments"))
static enum clnt_stat accepted(enum accept_stat, struct rpc_err *);
static enum clnt_stat rejected(enum reject_stat, struct rpc_err *);
/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
struct opaque_auth _null_auth;
/*
* XDR an opaque authentication struct
* (see auth.h)
*/
bool_t
xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
{
assert(xdrs != NULL);
assert(ap != NULL);
if (xdr_enum(xdrs, &(ap->oa_flavor)))
return (xdr_bytes(xdrs, &ap->oa_base,
&ap->oa_length, MAX_AUTH_BYTES));
return (FALSE);
}
/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
/*
* XDR the MSG_ACCEPTED part of a reply message union
*/
bool_t
xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
{
enum accept_stat *par_stat;
assert(xdrs != NULL);
assert(ar != NULL);
par_stat = &ar->ar_stat;
/* personalized union, rather than calling xdr_union */
if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
return (FALSE);
if (! xdr_enum(xdrs, (enum_t *) par_stat))
return (FALSE);
switch (ar->ar_stat) {
case SUCCESS:
if (ar->ar_results.proc != (xdrproc_t) xdr_void)
return ((*(ar->ar_results.proc))(xdrs,
ar->ar_results.where));
else
return (TRUE);
case PROG_MISMATCH:
if (! xdr_uint32_t(xdrs, &(ar->ar_vers.low)))
return (FALSE);
return (xdr_uint32_t(xdrs, &(ar->ar_vers.high)));
case GARBAGE_ARGS:
case SYSTEM_ERR:
case PROC_UNAVAIL:
case PROG_UNAVAIL:
break;
}
return (TRUE); /* TRUE => open ended set of problems */
}
/*
* XDR the MSG_DENIED part of a reply message union
*/
bool_t
xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
{
enum reject_stat *prj_stat;
enum auth_stat *prj_why;
assert(xdrs != NULL);
assert(rr != NULL);
prj_stat = &rr->rj_stat;
/* personalized union, rather than calling xdr_union */
if (! xdr_enum(xdrs, (enum_t *) prj_stat))
return (FALSE);
switch (rr->rj_stat) {
case RPC_MISMATCH:
if (! xdr_uint32_t(xdrs, &(rr->rj_vers.low)))
return (FALSE);
return (xdr_uint32_t(xdrs, &(rr->rj_vers.high)));
case AUTH_ERROR:
prj_why = &rr->rj_why;
return (xdr_enum(xdrs, (enum_t *) prj_why));
}
/* NOTREACHED */
assert(0);
return (FALSE);
}
static const struct xdr_discrim reply_dscrm[3] = {
{ (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply },
{ (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply },
{ __dontcare__, NULL_xdrproc_t } };
/*
* XDR a reply message
*/
bool_t
xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
{
int32_t *buf;
enum msg_type *prm_direction;
enum reply_stat *prp_stat;
assert(xdrs != NULL);
assert(rmsg != NULL);
if (xdrs->x_op == XDR_DECODE) {
buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT);
if (buf != NULL) {
rmsg->rm_xid = IXDR_GET_UINT32(buf);
rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
if (rmsg->rm_direction != REPLY) {
return (FALSE);
}
rmsg->rm_reply.rp_stat =
IXDR_GET_ENUM(buf, enum reply_stat);
if (rmsg->rm_reply.rp_stat == MSG_ACCEPTED)
return (xdr_accepted_reply(xdrs,
&rmsg->acpted_rply));
else if (rmsg->rm_reply.rp_stat == MSG_DENIED)
return (xdr_rejected_reply(xdrs,
&rmsg->rjcted_rply));
else
return (FALSE);
}
}
prm_direction = &rmsg->rm_direction;
prp_stat = &rmsg->rm_reply.rp_stat;
if (
xdr_uint32_t(xdrs, &(rmsg->rm_xid)) &&
xdr_enum(xdrs, (enum_t *) prm_direction) &&
(rmsg->rm_direction == REPLY) )
return (xdr_union(xdrs, (enum_t *) prp_stat,
(caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm,
NULL_xdrproc_t));
return (FALSE);
}
/*
* Serializes the "static part" of a call message header.
* The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
* The rm_xid is not really static, but the user can easily munge on the fly.
*/
bool_t
xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
{
enum msg_type *prm_direction;
assert(xdrs != NULL);
assert(cmsg != NULL);
prm_direction = &cmsg->rm_direction;
cmsg->rm_direction = CALL;
cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
if (
(xdrs->x_op == XDR_ENCODE) &&
xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
xdr_enum(xdrs, (enum_t *) prm_direction) &&
xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) )
return (xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)));
return (FALSE);
}
/* ************************** Client utility routine ************* */
static enum clnt_stat
accepted(enum accept_stat acpt_stat, struct rpc_err *error)
{
assert(error != NULL);
switch (acpt_stat) {
case PROG_UNAVAIL:
error->re_status = RPC_PROGUNAVAIL;
return (RPC_PROGUNAVAIL);
case PROG_MISMATCH:
error->re_status = RPC_PROGVERSMISMATCH;
return (RPC_PROGVERSMISMATCH);
case PROC_UNAVAIL:
return (RPC_PROCUNAVAIL);
case GARBAGE_ARGS:
return (RPC_CANTDECODEARGS);
case SYSTEM_ERR:
return (RPC_SYSTEMERROR);
case SUCCESS:
return (RPC_SUCCESS);
}
/* NOTREACHED */
/* something's wrong, but we don't know what ... */
error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
error->re_lb.s2 = (int32_t)acpt_stat;
return (RPC_FAILED);
}
static enum clnt_stat
rejected(enum reject_stat rjct_stat, struct rpc_err *error)
{
assert(error != NULL);
switch (rjct_stat) {
case RPC_MISMATCH:
return (RPC_VERSMISMATCH);
case AUTH_ERROR:
return (RPC_AUTHERROR);
}
/* something's wrong, but we don't know what ... */
/* NOTREACHED */
error->re_lb.s1 = (int32_t)MSG_DENIED;
error->re_lb.s2 = (int32_t)rjct_stat;
return (RPC_FAILED);
}
/*
* given a reply message, fills in the error
*/
enum clnt_stat
_seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
{
enum clnt_stat stat;
assert(msg != NULL);
assert(error != NULL);
/* optimized for normal, SUCCESSful case */
switch (msg->rm_reply.rp_stat) {
case MSG_ACCEPTED:
if (msg->acpted_rply.ar_stat == SUCCESS) {
stat = RPC_SUCCESS;
return (stat);
}
stat = accepted(msg->acpted_rply.ar_stat, error);
break;
case MSG_DENIED:
stat = rejected(msg->rjcted_rply.rj_stat, error);
break;
default:
stat = RPC_FAILED;
error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
break;
}
error->re_status = stat;
switch (stat) {
case RPC_VERSMISMATCH:
error->re_vers.low = msg->rjcted_rply.rj_vers.low;
error->re_vers.high = msg->rjcted_rply.rj_vers.high;
break;
case RPC_AUTHERROR:
error->re_why = msg->rjcted_rply.rj_why;
break;
case RPC_PROGVERSMISMATCH:
error->re_vers.low = msg->acpted_rply.ar_vers.low;
error->re_vers.high = msg->acpted_rply.ar_vers.high;
break;
case RPC_FAILED:
case RPC_SUCCESS:
case RPC_PROGNOTREGISTERED:
case RPC_PMAPFAILURE:
case RPC_UNKNOWNPROTO:
case RPC_UNKNOWNHOST:
case RPC_SYSTEMERROR:
case RPC_CANTDECODEARGS:
case RPC_PROCUNAVAIL:
case RPC_PROGUNAVAIL:
case RPC_TIMEDOUT:
case RPC_CANTRECV:
case RPC_CANTSEND:
case RPC_CANTDECODERES:
case RPC_CANTENCODEARGS:
default:
break;
}
return (stat);
}

1371
freebsd/sys/rpc/rpcb_clnt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,90 @@
/* $NetBSD: rpcb_clnt.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $ */
/* $FreeBSD$ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
*/
/*
* rpcb_clnt.h
* Supplies C routines to get to rpcbid services.
*
*/
/*
* Usage:
* success = rpcb_set(program, version, nconf, address);
* success = rpcb_unset(program, version, nconf);
* success = rpcb_getaddr(program, version, nconf, host);
* head = rpcb_getmaps(nconf, host);
* clnt_stat = rpcb_rmtcall(nconf, host, program, version, procedure,
* xdrargs, argsp, xdrres, resp, tout, addr_ptr)
* success = rpcb_gettime(host, timep)
* uaddr = rpcb_taddr2uaddr(nconf, taddr);
* taddr = rpcb_uaddr2uaddr(nconf, uaddr);
*/
#ifndef _RPC_RPCB_CLNT_H
#define _RPC_RPCB_CLNT_H
/* #pragma ident "@(#)rpcb_clnt.h 1.13 94/04/25 SMI" */
/* rpcb_clnt.h 1.3 88/12/05 SMI */
#include <rpc/types.h>
#ifndef _KERNEL
#include <rpc/rpcb_prot.h>
#endif
__BEGIN_DECLS
extern bool_t rpcb_set(const rpcprog_t, const rpcvers_t,
const struct netconfig *, const struct netbuf *);
extern bool_t rpcb_unset(const rpcprog_t, const rpcvers_t,
const struct netconfig *);
#ifndef _KERNEL
extern rpcblist *rpcb_getmaps(const struct netconfig *, const char *);
extern enum clnt_stat rpcb_rmtcall(const struct netconfig *,
const char *, const rpcprog_t,
const rpcvers_t, const rpcproc_t,
const xdrproc_t, const caddr_t,
const xdrproc_t, const caddr_t,
const struct timeval,
const struct netbuf *);
extern bool_t rpcb_getaddr(const rpcprog_t, const rpcvers_t,
const struct netconfig *, struct netbuf *,
const char *);
extern bool_t rpcb_gettime(const char *, time_t *);
extern char *rpcb_taddr2uaddr(struct netconfig *, struct netbuf *);
extern struct netbuf *rpcb_uaddr2taddr(struct netconfig *, char *);
#endif
__END_DECLS
#endif /* !_RPC_RPCB_CLNT_H */

246
freebsd/sys/rpc/rpcb_prot.c Normal file
View File

@ -0,0 +1,246 @@
/* $NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/* #ident "@(#)rpcb_prot.c 1.13 94/04/24 SMI" */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rpcb_prot.c 1.9 89/04/21 Copyr 1984 Sun Micro";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* rpcb_prot.c
* XDR routines for the rpcbinder version 3.
*
* Copyright (C) 1984, 1988, Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/rpcb_prot.h>
bool_t
xdr_portmap(XDR *xdrs, struct portmap *regs)
{
if (xdr_u_long(xdrs, &regs->pm_prog) &&
xdr_u_long(xdrs, &regs->pm_vers) &&
xdr_u_long(xdrs, &regs->pm_prot))
return (xdr_u_long(xdrs, &regs->pm_port));
return (FALSE);
}
bool_t
xdr_rpcb(XDR *xdrs, RPCB *objp)
{
if (!xdr_uint32_t(xdrs, &objp->r_prog)) {
return (FALSE);
}
if (!xdr_uint32_t(xdrs, &objp->r_vers)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_addr, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_owner, RPC_MAXDATASIZE)) {
return (FALSE);
}
return (TRUE);
}
/*
* rpcblist_ptr implements a linked list. The RPCL definition from
* rpcb_prot.x is:
*
* struct rpcblist {
* rpcb rpcb_map;
* struct rpcblist *rpcb_next;
* };
* typedef rpcblist *rpcblist_ptr;
*
* Recall that "pointers" in XDR are encoded as a boolean, indicating whether
* there's any data behind the pointer, followed by the data (if any exists).
* The boolean can be interpreted as ``more data follows me''; if FALSE then
* nothing follows the boolean; if TRUE then the boolean is followed by an
* actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct
* rpcblist *").
*
* This could be implemented via the xdr_pointer type, though this would
* result in one recursive call per element in the list. Rather than do that
* we can ``unwind'' the recursion into a while loop and use xdr_reference to
* serialize the rpcb elements.
*/
bool_t
xdr_rpcblist_ptr(XDR *xdrs, rpcblist_ptr *rp)
{
/*
* more_elements is pre-computed in case the direction is
* XDR_ENCODE or XDR_FREE. more_elements is overwritten by
* xdr_bool when the direction is XDR_DECODE.
*/
bool_t more_elements;
int freeing = (xdrs->x_op == XDR_FREE);
rpcblist_ptr next;
rpcblist_ptr next_copy;
next = NULL;
for (;;) {
more_elements = (bool_t)(*rp != NULL);
if (! xdr_bool(xdrs, &more_elements)) {
return (FALSE);
}
if (! more_elements) {
return (TRUE); /* we are done */
}
/*
* the unfortunate side effect of non-recursion is that in
* the case of freeing we must remember the next object
* before we free the current object ...
*/
if (freeing && *rp)
next = (*rp)->rpcb_next;
if (! xdr_reference(xdrs, (caddr_t *)rp,
(u_int)sizeof (RPCBLIST), (xdrproc_t)xdr_rpcb)) {
return (FALSE);
}
if (freeing) {
next_copy = next;
rp = &next_copy;
/*
* Note that in the subsequent iteration, next_copy
* gets nulled out by the xdr_reference
* but next itself survives.
*/
} else if (*rp) {
rp = &((*rp)->rpcb_next);
}
}
/*NOTREACHED*/
}
#if 0
/*
* xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in
* functionality to xdr_rpcblist_ptr().
*/
bool_t
xdr_rpcblist(XDR *xdrs, RPCBLIST **rp)
{
bool_t dummy;
dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp);
return (dummy);
}
#endif
bool_t
xdr_rpcb_entry(XDR *xdrs, rpcb_entry *objp)
{
if (!xdr_string(xdrs, &objp->r_maddr, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_nc_netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_uint32_t(xdrs, &objp->r_nc_semantics)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_nc_protofmly, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_nc_proto, RPC_MAXDATASIZE)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_rpcb_entry_list_ptr(XDR *xdrs, rpcb_entry_list_ptr *rp)
{
/*
* more_elements is pre-computed in case the direction is
* XDR_ENCODE or XDR_FREE. more_elements is overwritten by
* xdr_bool when the direction is XDR_DECODE.
*/
bool_t more_elements;
int freeing = (xdrs->x_op == XDR_FREE);
rpcb_entry_list_ptr next;
rpcb_entry_list_ptr next_copy;
next = NULL;
for (;;) {
more_elements = (bool_t)(*rp != NULL);
if (! xdr_bool(xdrs, &more_elements)) {
return (FALSE);
}
if (! more_elements) {
return (TRUE); /* we are done */
}
/*
* the unfortunate side effect of non-recursion is that in
* the case of freeing we must remember the next object
* before we free the current object ...
*/
if (freeing)
next = (*rp)->rpcb_entry_next;
if (! xdr_reference(xdrs, (caddr_t *)rp,
(u_int)sizeof (rpcb_entry_list),
(xdrproc_t)xdr_rpcb_entry)) {
return (FALSE);
}
if (freeing && *rp) {
next_copy = next;
rp = &next_copy;
/*
* Note that in the subsequent iteration, next_copy
* gets nulled out by the xdr_reference
* but next itself survives.
*/
} else if (*rp) {
rp = &((*rp)->rpcb_entry_next);
}
}
/*NOTREACHED*/
}

580
freebsd/sys/rpc/rpcb_prot.h Normal file
View File

@ -0,0 +1,580 @@
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _RPCB_PROT_H_RPCGEN
#define _RPCB_PROT_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* $FreeBSD$
*/
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/* from rpcb_prot.x */
/* #pragma ident "@(#)rpcb_prot.x 1.5 94/04/29 SMI" */
#ifndef _KERNEL
/*
* The following procedures are supported by the protocol in version 3:
*
* RPCBPROC_NULL() returns ()
* takes nothing, returns nothing
*
* RPCBPROC_SET(rpcb) returns (bool_t)
* TRUE is success, FALSE is failure. Registers the tuple
* [prog, vers, address, owner, netid].
* Finds out owner and netid information on its own.
*
* RPCBPROC_UNSET(rpcb) returns (bool_t)
* TRUE is success, FALSE is failure. Un-registers tuple
* [prog, vers, netid]. addresses is ignored.
* If netid is NULL, unregister all.
*
* RPCBPROC_GETADDR(rpcb) returns (string).
* 0 is failure. Otherwise returns the universal address where the
* triple [prog, vers, netid] is registered. Ignore address and owner.
*
* RPCBPROC_DUMP() RETURNS (rpcblist_ptr)
* used to dump the entire rpcbind maps
*
* RPCBPROC_CALLIT(rpcb_rmtcallargs)
* RETURNS (rpcb_rmtcallres);
* Calls the procedure on the remote machine. If it is not registered,
* this procedure is quiet; i.e. it does not return error information!!!
* This routine only passes null authentication parameters.
* It has no interface to xdr routines for RPCBPROC_CALLIT.
*
* RPCBPROC_GETTIME() returns (int).
* Gets the remote machines time
*
* RPCBPROC_UADDR2TADDR(strint) RETURNS (struct netbuf)
* Returns the netbuf address from universal address.
*
* RPCBPROC_TADDR2UADDR(struct netbuf) RETURNS (string)
* Returns the universal address from netbuf address.
*
* END OF RPCBIND VERSION 3 PROCEDURES
*/
/*
* Except for RPCBPROC_CALLIT, the procedures above are carried over to
* rpcbind version 4. Those below are added or modified for version 4.
* NOTE: RPCBPROC_BCAST HAS THE SAME FUNCTIONALITY AND PROCEDURE NUMBER
* AS RPCBPROC_CALLIT.
*
* RPCBPROC_BCAST(rpcb_rmtcallargs)
* RETURNS (rpcb_rmtcallres);
* Calls the procedure on the remote machine. If it is not registered,
* this procedure IS quiet; i.e. it DOES NOT return error information!!!
* This routine should be used for broadcasting and nothing else.
*
* RPCBPROC_GETVERSADDR(rpcb) returns (string).
* 0 is failure. Otherwise returns the universal address where the
* triple [prog, vers, netid] is registered. Ignore address and owner.
* Same as RPCBPROC_GETADDR except that if the given version number
* is not available, the address is not returned.
*
* RPCBPROC_INDIRECT(rpcb_rmtcallargs)
* RETURNS (rpcb_rmtcallres);
* Calls the procedure on the remote machine. If it is not registered,
* this procedure is NOT quiet; i.e. it DOES return error information!!!
* as any normal application would expect.
*
* RPCBPROC_GETADDRLIST(rpcb) returns (rpcb_entry_list_ptr).
* Same as RPCBPROC_GETADDR except that it returns a list of all the
* addresses registered for the combination (prog, vers) (for all
* transports).
*
* RPCBPROC_GETSTAT(void) returns (rpcb_stat_byvers)
* Returns the statistics about the kind of requests received by rpcbind.
*/
/*
* A mapping of (program, version, network ID) to address
*/
struct rpcb {
rpcprog_t r_prog;
rpcvers_t r_vers;
char *r_netid;
char *r_addr;
char *r_owner;
};
typedef struct rpcb rpcb;
typedef rpcb RPCB;
/*
* A list of mappings
*
* Below are two definitions for the rpcblist structure. This is done because
* xdr_rpcblist() is specified to take a struct rpcblist **, rather than a
* struct rpcblist * that rpcgen would produce. One version of the rpcblist
* structure (actually called rp__list) is used with rpcgen, and the other is
* defined only in the header file for compatibility with the specified
* interface.
*/
struct rp__list {
rpcb rpcb_map;
struct rp__list *rpcb_next;
};
typedef struct rp__list rp__list;
typedef rp__list *rpcblist_ptr;
typedef struct rp__list rpcblist;
typedef struct rp__list RPCBLIST;
#ifndef __cplusplus
struct rpcblist {
RPCB rpcb_map;
struct rpcblist *rpcb_next;
};
#endif
#ifdef __cplusplus
extern "C" {
#endif
extern bool_t xdr_rpcblist(XDR *, rpcblist**);
#ifdef __cplusplus
}
#endif
/*
* Arguments of remote calls
*/
struct rpcb_rmtcallargs {
rpcprog_t prog;
rpcvers_t vers;
rpcproc_t proc;
struct {
u_int args_len;
char *args_val;
} args;
};
typedef struct rpcb_rmtcallargs rpcb_rmtcallargs;
/*
* Client-side only representation of rpcb_rmtcallargs structure.
*
* The routine that XDRs the rpcb_rmtcallargs structure must deal with the
* opaque arguments in the "args" structure. xdr_rpcb_rmtcallargs() needs to
* be passed the XDR routine that knows the args' structure. This routine
* doesn't need to go over-the-wire (and it wouldn't make sense anyway) since
* the application being called already knows the args structure. So we use a
* different "XDR" structure on the client side, r_rpcb_rmtcallargs, which
* includes the args' XDR routine.
*/
struct r_rpcb_rmtcallargs {
rpcprog_t prog;
rpcvers_t vers;
rpcproc_t proc;
struct {
u_int args_len;
char *args_val;
} args;
xdrproc_t xdr_args; /* encodes args */
};
/*
* Results of the remote call
*/
struct rpcb_rmtcallres {
char *addr;
struct {
u_int results_len;
char *results_val;
} results;
};
typedef struct rpcb_rmtcallres rpcb_rmtcallres;
/*
* Client-side only representation of rpcb_rmtcallres structure.
*/
struct r_rpcb_rmtcallres {
char *addr;
struct {
uint32_t results_len;
char *results_val;
} results;
xdrproc_t xdr_res; /* decodes results */
};
/*
* rpcb_entry contains a merged address of a service on a particular
* transport, plus associated netconfig information. A list of rpcb_entrys
* is returned by RPCBPROC_GETADDRLIST. See netconfig.h for values used
* in r_nc_* fields.
*/
struct rpcb_entry {
char *r_maddr;
char *r_nc_netid;
u_int r_nc_semantics;
char *r_nc_protofmly;
char *r_nc_proto;
};
typedef struct rpcb_entry rpcb_entry;
/*
* A list of addresses supported by a service.
*/
struct rpcb_entry_list {
rpcb_entry rpcb_entry_map;
struct rpcb_entry_list *rpcb_entry_next;
};
typedef struct rpcb_entry_list rpcb_entry_list;
typedef rpcb_entry_list *rpcb_entry_list_ptr;
/*
* rpcbind statistics
*/
#define rpcb_highproc_2 RPCBPROC_CALLIT
#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR
#define rpcb_highproc_4 RPCBPROC_GETSTAT
#define RPCBSTAT_HIGHPROC 13
#define RPCBVERS_STAT 3
#define RPCBVERS_4_STAT 2
#define RPCBVERS_3_STAT 1
#define RPCBVERS_2_STAT 0
/* Link list of all the stats about getport and getaddr */
struct rpcbs_addrlist {
rpcprog_t prog;
rpcvers_t vers;
int success;
int failure;
char *netid;
struct rpcbs_addrlist *next;
};
typedef struct rpcbs_addrlist rpcbs_addrlist;
/* Link list of all the stats about rmtcall */
struct rpcbs_rmtcalllist {
rpcprog_t prog;
rpcvers_t vers;
rpcproc_t proc;
int success;
int failure;
int indirect;
char *netid;
struct rpcbs_rmtcalllist *next;
};
typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist;
typedef int rpcbs_proc[RPCBSTAT_HIGHPROC];
typedef rpcbs_addrlist *rpcbs_addrlist_ptr;
typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr;
struct rpcb_stat {
rpcbs_proc info;
int setinfo;
int unsetinfo;
rpcbs_addrlist_ptr addrinfo;
rpcbs_rmtcalllist_ptr rmtinfo;
};
typedef struct rpcb_stat rpcb_stat;
/*
* One rpcb_stat structure is returned for each version of rpcbind
* being monitored.
*/
typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT];
/*
* We don't define netbuf in RPCL, since it would contain structure member
* names that would conflict with the definition of struct netbuf in
* <tiuser.h>. Instead we merely declare the XDR routine xdr_netbuf() here,
* and implement it ourselves in rpc/rpcb_prot.c.
*/
#ifdef __cplusplus
extern "C" bool_t xdr_netbuf(XDR *, struct netbuf *);
#else /* __STDC__ */
extern bool_t xdr_netbuf(XDR *, struct netbuf *);
#endif
#define RPCBVERS_3 RPCBVERS
#define RPCBVERS_4 RPCBVERS4
#else /* ndef _KERNEL */
#ifdef __cplusplus
extern "C" {
#endif
/*
* A mapping of (program, version, network ID) to address
*/
struct rpcb {
rpcprog_t r_prog; /* program number */
rpcvers_t r_vers; /* version number */
char *r_netid; /* network id */
char *r_addr; /* universal address */
char *r_owner; /* owner of the mapping */
};
typedef struct rpcb RPCB;
/*
* A list of mappings
*/
struct rpcblist {
RPCB rpcb_map;
struct rpcblist *rpcb_next;
};
typedef struct rpcblist RPCBLIST;
typedef struct rpcblist *rpcblist_ptr;
/*
* Remote calls arguments
*/
struct rpcb_rmtcallargs {
rpcprog_t prog; /* program number */
rpcvers_t vers; /* version number */
rpcproc_t proc; /* procedure number */
uint32_t arglen; /* arg len */
caddr_t args_ptr; /* argument */
xdrproc_t xdr_args; /* XDR routine for argument */
};
typedef struct rpcb_rmtcallargs rpcb_rmtcallargs;
/*
* Remote calls results
*/
struct rpcb_rmtcallres {
char *addr_ptr; /* remote universal address */
uint32_t resultslen; /* results length */
caddr_t results_ptr; /* results */
xdrproc_t xdr_results; /* XDR routine for result */
};
typedef struct rpcb_rmtcallres rpcb_rmtcallres;
struct rpcb_entry {
char *r_maddr;
char *r_nc_netid;
unsigned int r_nc_semantics;
char *r_nc_protofmly;
char *r_nc_proto;
};
typedef struct rpcb_entry rpcb_entry;
/*
* A list of addresses supported by a service.
*/
struct rpcb_entry_list {
rpcb_entry rpcb_entry_map;
struct rpcb_entry_list *rpcb_entry_next;
};
typedef struct rpcb_entry_list rpcb_entry_list;
typedef rpcb_entry_list *rpcb_entry_list_ptr;
/*
* rpcbind statistics
*/
#define rpcb_highproc_2 RPCBPROC_CALLIT
#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR
#define rpcb_highproc_4 RPCBPROC_GETSTAT
#define RPCBSTAT_HIGHPROC 13
#define RPCBVERS_STAT 3
#define RPCBVERS_4_STAT 2
#define RPCBVERS_3_STAT 1
#define RPCBVERS_2_STAT 0
/* Link list of all the stats about getport and getaddr */
struct rpcbs_addrlist {
rpcprog_t prog;
rpcvers_t vers;
int success;
int failure;
char *netid;
struct rpcbs_addrlist *next;
};
typedef struct rpcbs_addrlist rpcbs_addrlist;
/* Link list of all the stats about rmtcall */
struct rpcbs_rmtcalllist {
rpcprog_t prog;
rpcvers_t vers;
rpcproc_t proc;
int success;
int failure;
int indirect;
char *netid;
struct rpcbs_rmtcalllist *next;
};
typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist;
typedef int rpcbs_proc[RPCBSTAT_HIGHPROC];
typedef rpcbs_addrlist *rpcbs_addrlist_ptr;
typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr;
struct rpcb_stat {
rpcbs_proc info;
int setinfo;
int unsetinfo;
rpcbs_addrlist_ptr addrinfo;
rpcbs_rmtcalllist_ptr rmtinfo;
};
typedef struct rpcb_stat rpcb_stat;
/*
* One rpcb_stat structure is returned for each version of rpcbind
* being monitored.
*/
typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT];
#ifdef __cplusplus
}
#endif
#endif /* ndef _KERNEL */
#define _PATH_RPCBINDSOCK "/var/run/rpcbind.sock"
#define RPCBPROG ((unsigned long)(100000))
#define RPCBVERS ((unsigned long)(3))
extern void rpcbprog_3(struct svc_req *rqstp, SVCXPRT *transp);
#define RPCBPROC_SET ((unsigned long)(1))
extern bool_t * rpcbproc_set_3(RPCB *, CLIENT *);
extern bool_t * rpcbproc_set_3_svc(RPCB *, struct svc_req *);
#define RPCBPROC_UNSET ((unsigned long)(2))
extern bool_t * rpcbproc_unset_3(RPCB *, CLIENT *);
extern bool_t * rpcbproc_unset_3_svc(RPCB *, struct svc_req *);
#define RPCBPROC_GETADDR ((unsigned long)(3))
extern char ** rpcbproc_getaddr_3(RPCB *, CLIENT *);
extern char ** rpcbproc_getaddr_3_svc(RPCB *, struct svc_req *);
#define RPCBPROC_DUMP ((unsigned long)(4))
extern rpcblist_ptr * rpcbproc_dump_3(void *, CLIENT *);
extern rpcblist_ptr * rpcbproc_dump_3_svc(void *, struct svc_req *);
#define RPCBPROC_CALLIT ((unsigned long)(5))
extern rpcb_rmtcallres * rpcbproc_callit_3(rpcb_rmtcallargs *, CLIENT *);
extern rpcb_rmtcallres * rpcbproc_callit_3_svc(rpcb_rmtcallargs *, struct svc_req *);
#define RPCBPROC_GETTIME ((unsigned long)(6))
extern u_int * rpcbproc_gettime_3(void *, CLIENT *);
extern u_int * rpcbproc_gettime_3_svc(void *, struct svc_req *);
#define RPCBPROC_UADDR2TADDR ((unsigned long)(7))
extern struct netbuf * rpcbproc_uaddr2taddr_3(char **, CLIENT *);
extern struct netbuf * rpcbproc_uaddr2taddr_3_svc(char **, struct svc_req *);
#define RPCBPROC_TADDR2UADDR ((unsigned long)(8))
extern char ** rpcbproc_taddr2uaddr_3(struct netbuf *, CLIENT *);
extern char ** rpcbproc_taddr2uaddr_3_svc(struct netbuf *, struct svc_req *);
extern int rpcbprog_3_freeresult(SVCXPRT *, xdrproc_t, caddr_t);
#define RPCBVERS4 ((unsigned long)(4))
extern void rpcbprog_4(struct svc_req *rqstp, SVCXPRT *transp);
extern bool_t * rpcbproc_set_4(RPCB *, CLIENT *);
extern bool_t * rpcbproc_set_4_svc(RPCB *, struct svc_req *);
extern bool_t * rpcbproc_unset_4(RPCB *, CLIENT *);
extern bool_t * rpcbproc_unset_4_svc(RPCB *, struct svc_req *);
extern char ** rpcbproc_getaddr_4(RPCB *, CLIENT *);
extern char ** rpcbproc_getaddr_4_svc(RPCB *, struct svc_req *);
extern rpcblist_ptr * rpcbproc_dump_4(void *, CLIENT *);
extern rpcblist_ptr * rpcbproc_dump_4_svc(void *, struct svc_req *);
#define RPCBPROC_BCAST ((unsigned long)(RPCBPROC_CALLIT))
extern rpcb_rmtcallres * rpcbproc_bcast_4(rpcb_rmtcallargs *, CLIENT *);
extern rpcb_rmtcallres * rpcbproc_bcast_4_svc(rpcb_rmtcallargs *, struct svc_req *);
extern u_int * rpcbproc_gettime_4(void *, CLIENT *);
extern u_int * rpcbproc_gettime_4_svc(void *, struct svc_req *);
extern struct netbuf * rpcbproc_uaddr2taddr_4(char **, CLIENT *);
extern struct netbuf * rpcbproc_uaddr2taddr_4_svc(char **, struct svc_req *);
extern char ** rpcbproc_taddr2uaddr_4(struct netbuf *, CLIENT *);
extern char ** rpcbproc_taddr2uaddr_4_svc(struct netbuf *, struct svc_req *);
#define RPCBPROC_GETVERSADDR ((unsigned long)(9))
extern char ** rpcbproc_getversaddr_4(RPCB *, CLIENT *);
extern char ** rpcbproc_getversaddr_4_svc(RPCB *, struct svc_req *);
#define RPCBPROC_INDIRECT ((unsigned long)(10))
extern rpcb_rmtcallres * rpcbproc_indirect_4(rpcb_rmtcallargs *, CLIENT *);
extern rpcb_rmtcallres * rpcbproc_indirect_4_svc(rpcb_rmtcallargs *, struct svc_req *);
#define RPCBPROC_GETADDRLIST ((unsigned long)(11))
extern rpcb_entry_list_ptr * rpcbproc_getaddrlist_4(RPCB *, CLIENT *);
extern rpcb_entry_list_ptr * rpcbproc_getaddrlist_4_svc(RPCB *, struct svc_req *);
#define RPCBPROC_GETSTAT ((unsigned long)(12))
extern rpcb_stat * rpcbproc_getstat_4(void *, CLIENT *);
extern rpcb_stat * rpcbproc_getstat_4_svc(void *, struct svc_req *);
extern int rpcbprog_4_freeresult(SVCXPRT *, xdrproc_t, caddr_t);
/* the xdr functions */
extern bool_t xdr_rpcb(XDR *, RPCB *);
#ifndef _KERNEL
extern bool_t xdr_rp__list(XDR *, rp__list*);
#endif
extern bool_t xdr_rpcblist_ptr(XDR *, rpcblist_ptr*);
extern bool_t xdr_rpcb_rmtcallargs(XDR *, rpcb_rmtcallargs*);
extern bool_t xdr_rpcb_rmtcallres(XDR *, rpcb_rmtcallres*);
extern bool_t xdr_rpcb_entry(XDR *, rpcb_entry*);
extern bool_t xdr_rpcb_entry_list(XDR *, rpcb_entry_list*);
extern bool_t xdr_rpcb_entry_list_ptr(XDR *, rpcb_entry_list_ptr*);
extern bool_t xdr_rpcbs_addrlist(XDR *, rpcbs_addrlist*);
extern bool_t xdr_rpcbs_rmtcalllist(XDR *, rpcbs_rmtcalllist*);
extern bool_t xdr_rpcbs_proc(XDR *, rpcbs_proc);
extern bool_t xdr_rpcbs_addrlist_ptr(XDR *, rpcbs_addrlist_ptr*);
extern bool_t xdr_rpcbs_rmtcalllist_ptr(XDR *, rpcbs_rmtcalllist_ptr*);
extern bool_t xdr_rpcb_stat(XDR *, rpcb_stat*);
extern bool_t xdr_rpcb_stat_byvers(XDR *, rpcb_stat_byvers);
#ifdef __cplusplus
}
#endif
#endif /* !_RPCB_PROT_H_RPCGEN */

131
freebsd/sys/rpc/rpcm_subs.h Normal file
View File

@ -0,0 +1,131 @@
/* $FreeBSD$ */
/* $OpenBSD: nfsm_subs.h,v 1.11 2000/01/05 20:50:52 millert Exp $ */
/* $NetBSD: nfsm_subs.h,v 1.10 1996/03/20 21:59:56 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* copyright (c) 2003
* the regents of the university of michigan
* all rights reserved
*
* permission is granted to use, copy, create derivative works and redistribute
* this software and such derivative works for any purpose, so long as the name
* of the university of michigan is not used in any advertising or publicity
* pertaining to the use or distribution of this software without specific,
* written prior authorization. if the above copyright notice or any other
* identification of the university of michigan is included in any copy of any
* portion of this software, then the disclaimer below must also be included.
*
* this software is provided as is, without representation from the university
* of michigan as to its fitness for any purpose, and without warranty by the
* university of michigan of any kind, either express or implied, including
* without limitation the implied warranties of merchantability and fitness for
* a particular purpose. the regents of the university of michigan shall not be
* liable for any damages, including special, indirect, incidental, or
* consequential damages, with respect to any claim arising out of or in
* connection with the use of the software, even if it has been or is hereafter
* advised of the possibility of such damages.
*/
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rick Macklem at The University of Guelph.
*
* 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 University 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 REGENTS 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 REGENTS 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.
*
* @(#)nfsm_subs.h 8.2 (Berkeley) 3/30/95
*/
#ifndef _RPC_RPCM_SUBS_H_
#define _RPC_RPCM_SUBS_H_
/*
* Now for the macros that do the simple stuff and call the functions
* for the hard stuff.
* These macros use several vars. declared in rpcm_reqhead and these
* vars. must not be used elsewhere unless you are careful not to corrupt
* them. The vars. starting with pN and tN (N=1,2,3,..) are temporaries
* that may be used so long as the value is not expected to retained
* after a macro.
* I know, this is kind of dorkey, but it makes the actual op functions
* fairly clean and deals with the mess caused by the xdr discriminating
* unions.
*/
#define rpcm_build(a,c,s) \
{ if ((s) > M_TRAILINGSPACE(mb)) { \
mb2 = m_get(M_WAITOK, MT_DATA); \
if ((s) > MLEN) \
panic("build > MLEN"); \
mb->m_next = mb2; \
mb = mb2; \
mb->m_len = 0; \
bpos = mtod(mb, caddr_t); \
} \
(a) = (c)(bpos); \
mb->m_len += (s); \
bpos += (s); }
#define rpcm_dissect(a, c, s) \
{ t1 = mtod(md, caddr_t)+md->m_len-dpos; \
if (t1 >= (s)) { \
(a) = (c)(dpos); \
dpos += (s); \
} else if ((t1 = rpcm_disct(&md, &dpos, (s), t1, &cp2)) != 0){ \
error = t1; \
goto rpcmout; \
} else { \
(a) = (c)cp2; \
} }
#if 0
#define rpcm_mtouio(p,s) \
if ((s) > 0 && \
(t1 = rpcm_mbuftouio(&md,(p),(s),&dpos)) != 0) { \
error = t1; \
goto rpcmout; \
}
#endif
#define rpcm_rndup(a) (((a)+3)&(~0x3))
#define rpcm_adv(s) \
{ t1 = mtod(md, caddr_t)+md->m_len-dpos; \
if (t1 >= (s)) { \
dpos += (s); \
} else if ((t1 = rpc_adv(&md, &dpos, (s), t1)) != 0) { \
error = t1; \
goto rpcmout; \
} }
#define RPCMADV(m, s) (m)->m_data += (s)
#endif /* _RPC_RPCM_SUBS_H_ */

View File

@ -0,0 +1,474 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2008 Doug Rabson
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _RPCSEC_GSS_H
#define _RPCSEC_GSS_H
#include <kgssapi/gssapi.h>
#ifndef MAX_GSS_MECH
#define MAX_GSS_MECH 64
#endif
/*
* Define the types of security service required for rpc_gss_seccreate().
*/
typedef enum {
rpc_gss_svc_default = 0,
rpc_gss_svc_none = 1,
rpc_gss_svc_integrity = 2,
rpc_gss_svc_privacy = 3
} rpc_gss_service_t;
/*
* Structure containing options for rpc_gss_seccreate().
*/
typedef struct {
int req_flags; /* GSS request bits */
int time_req; /* requested credential lifetime */
gss_cred_id_t my_cred; /* GSS credential */
gss_channel_bindings_t input_channel_bindings;
} rpc_gss_options_req_t;
/*
* Structure containing options returned by rpc_gss_seccreate().
*/
typedef struct {
int major_status;
int minor_status;
u_int rpcsec_version;
int ret_flags;
int time_req;
gss_ctx_id_t gss_context;
char actual_mechanism[MAX_GSS_MECH];
} rpc_gss_options_ret_t;
/*
* Client principal type. Used as an argument to
* rpc_gss_get_principal_name(). Also referenced by the
* rpc_gss_rawcred_t structure.
*/
typedef struct {
int len;
char name[1];
} *rpc_gss_principal_t;
/*
* Structure for raw credentials used by rpc_gss_getcred() and
* rpc_gss_set_callback().
*/
typedef struct {
u_int version; /* RPC version number */
const char *mechanism; /* security mechanism */
const char *qop; /* quality of protection */
rpc_gss_principal_t client_principal; /* client name */
const char *svc_principal; /* server name */
rpc_gss_service_t service; /* service type */
} rpc_gss_rawcred_t;
/*
* Unix credentials derived from raw credentials. Returned by
* rpc_gss_getcred().
*/
typedef struct {
uid_t uid; /* user ID */
gid_t gid; /* group ID */
short gidlen;
gid_t *gidlist; /* list of groups */
} rpc_gss_ucred_t;
/*
* Structure used to enforce a particular QOP and service.
*/
typedef struct {
bool_t locked;
rpc_gss_rawcred_t *raw_cred;
} rpc_gss_lock_t;
/*
* Callback structure used by rpc_gss_set_callback().
*/
typedef struct {
u_int program; /* RPC program number */
u_int version; /* RPC version number */
/* user defined callback */
bool_t (*callback)(struct svc_req *req,
gss_cred_id_t deleg,
gss_ctx_id_t gss_context,
rpc_gss_lock_t *lock,
void **cookie);
} rpc_gss_callback_t;
/*
* Structure used to return error information by rpc_gss_get_error()
*/
typedef struct {
int rpc_gss_error;
int system_error; /* same as errno */
} rpc_gss_error_t;
/*
* Values for rpc_gss_error
*/
#define RPC_GSS_ER_SUCCESS 0 /* no error */
#define RPC_GSS_ER_SYSTEMERROR 1 /* system error */
__BEGIN_DECLS
#ifdef _KERNEL
/*
* Set up a structure of entry points for the kgssapi module and inline
* functions named rpc_gss_XXX_call() to use them, so that the kgssapi
* module doesn't need to be loaded for the NFS modules to work using
* AUTH_SYS. The kgssapi modules will be loaded by the gssd(8) daemon
* when it is started up and the entry points will then be filled in.
*/
typedef AUTH *rpc_gss_secfind_ftype(CLIENT *clnt, struct ucred *cred,
const char *principal, gss_OID mech_oid,
rpc_gss_service_t service);
typedef void rpc_gss_secpurge_ftype(CLIENT *clnt);
typedef AUTH *rpc_gss_seccreate_ftype(CLIENT *clnt, struct ucred *cred,
const char *clnt_principal, const char *principal,
const char *mechanism, rpc_gss_service_t service,
const char *qop, rpc_gss_options_req_t *options_req,
rpc_gss_options_ret_t *options_ret);
typedef bool_t rpc_gss_set_defaults_ftype(AUTH *auth,
rpc_gss_service_t service, const char *qop);
typedef int rpc_gss_max_data_length_ftype(AUTH *handle,
int max_tp_unit_len);
typedef void rpc_gss_get_error_ftype(rpc_gss_error_t *error);
typedef bool_t rpc_gss_mech_to_oid_ftype(const char *mech, gss_OID *oid_ret);
typedef bool_t rpc_gss_oid_to_mech_ftype(gss_OID oid, const char **mech_ret);
typedef bool_t rpc_gss_qop_to_num_ftype(const char *qop, const char *mech,
u_int *num_ret);
typedef const char **rpc_gss_get_mechanisms_ftype(void);
typedef bool_t rpc_gss_get_versions_ftype(u_int *vers_hi, u_int *vers_lo);
typedef bool_t rpc_gss_is_installed_ftype(const char *mech);
typedef bool_t rpc_gss_set_svc_name_ftype(const char *principal,
const char *mechanism, u_int req_time, u_int program,
u_int version);
typedef void rpc_gss_clear_svc_name_ftype(u_int program, u_int version);
typedef bool_t rpc_gss_getcred_ftype(struct svc_req *req,
rpc_gss_rawcred_t **rcred,
rpc_gss_ucred_t **ucred, void **cookie);
typedef bool_t rpc_gss_set_callback_ftype(rpc_gss_callback_t *cb);
typedef void rpc_gss_clear_callback_ftype(rpc_gss_callback_t *cb);
typedef bool_t rpc_gss_get_principal_name_ftype(rpc_gss_principal_t *principal,
const char *mech, const char *name, const char *node,
const char *domain);
typedef int rpc_gss_svc_max_data_length_ftype(struct svc_req *req,
int max_tp_unit_len);
typedef void rpc_gss_refresh_auth_ftype(AUTH *auth);
struct rpc_gss_entries {
rpc_gss_secfind_ftype *rpc_gss_secfind;
rpc_gss_secpurge_ftype *rpc_gss_secpurge;
rpc_gss_seccreate_ftype *rpc_gss_seccreate;
rpc_gss_set_defaults_ftype *rpc_gss_set_defaults;
rpc_gss_max_data_length_ftype *rpc_gss_max_data_length;
rpc_gss_get_error_ftype *rpc_gss_get_error;
rpc_gss_mech_to_oid_ftype *rpc_gss_mech_to_oid;
rpc_gss_oid_to_mech_ftype *rpc_gss_oid_to_mech;
rpc_gss_qop_to_num_ftype *rpc_gss_qop_to_num;
rpc_gss_get_mechanisms_ftype *rpc_gss_get_mechanisms;
rpc_gss_get_versions_ftype *rpc_gss_get_versions;
rpc_gss_is_installed_ftype *rpc_gss_is_installed;
rpc_gss_set_svc_name_ftype *rpc_gss_set_svc_name;
rpc_gss_clear_svc_name_ftype *rpc_gss_clear_svc_name;
rpc_gss_getcred_ftype *rpc_gss_getcred;
rpc_gss_set_callback_ftype *rpc_gss_set_callback;
rpc_gss_clear_callback_ftype *rpc_gss_clear_callback;
rpc_gss_get_principal_name_ftype *rpc_gss_get_principal_name;
rpc_gss_svc_max_data_length_ftype *rpc_gss_svc_max_data_length;
rpc_gss_refresh_auth_ftype *rpc_gss_refresh_auth;
};
extern struct rpc_gss_entries rpc_gss_entries;
/* Functions to access the entry points. */
static __inline AUTH *
rpc_gss_secfind_call(CLIENT *clnt, struct ucred *cred, const char *principal,
gss_OID mech_oid, rpc_gss_service_t service)
{
AUTH *ret = NULL;
if (rpc_gss_entries.rpc_gss_secfind != NULL)
ret = (*rpc_gss_entries.rpc_gss_secfind)(clnt, cred, principal,
mech_oid, service);
return (ret);
}
static __inline void
rpc_gss_secpurge_call(CLIENT *clnt)
{
if (rpc_gss_entries.rpc_gss_secpurge != NULL)
(*rpc_gss_entries.rpc_gss_secpurge)(clnt);
}
static __inline AUTH *
rpc_gss_seccreate_call(CLIENT *clnt, struct ucred *cred,
const char *clnt_principal, const char *principal, const char *mechanism,
rpc_gss_service_t service, const char *qop,
rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
{
AUTH *ret = NULL;
if (rpc_gss_entries.rpc_gss_seccreate != NULL)
ret = (*rpc_gss_entries.rpc_gss_seccreate)(clnt, cred,
clnt_principal, principal, mechanism, service, qop,
options_req, options_ret);
return (ret);
}
static __inline bool_t
rpc_gss_set_defaults_call(AUTH *auth, rpc_gss_service_t service,
const char *qop)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_set_defaults != NULL)
ret = (*rpc_gss_entries.rpc_gss_set_defaults)(auth, service,
qop);
return (ret);
}
static __inline int
rpc_gss_max_data_length_call(AUTH *handle, int max_tp_unit_len)
{
int ret = 0;
if (rpc_gss_entries.rpc_gss_max_data_length != NULL)
ret = (*rpc_gss_entries.rpc_gss_max_data_length)(handle,
max_tp_unit_len);
return (ret);
}
static __inline void
rpc_gss_get_error_call(rpc_gss_error_t *error)
{
if (rpc_gss_entries.rpc_gss_get_error != NULL)
(*rpc_gss_entries.rpc_gss_get_error)(error);
}
static __inline bool_t
rpc_gss_mech_to_oid_call(const char *mech, gss_OID *oid_ret)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_mech_to_oid != NULL)
ret = (*rpc_gss_entries.rpc_gss_mech_to_oid)(mech, oid_ret);
return (ret);
}
static __inline bool_t
rpc_gss_oid_to_mech_call(gss_OID oid, const char **mech_ret)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_oid_to_mech != NULL)
ret = (*rpc_gss_entries.rpc_gss_oid_to_mech)(oid, mech_ret);
return (ret);
}
static __inline bool_t
rpc_gss_qop_to_num_call(const char *qop, const char *mech, u_int *num_ret)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_qop_to_num != NULL)
ret = (*rpc_gss_entries.rpc_gss_qop_to_num)(qop, mech, num_ret);
return (ret);
}
static __inline const char **
rpc_gss_get_mechanisms_call(void)
{
const char **ret = NULL;
if (rpc_gss_entries.rpc_gss_get_mechanisms != NULL)
ret = (*rpc_gss_entries.rpc_gss_get_mechanisms)();
return (ret);
}
static __inline bool_t
rpc_gss_get_versions_call(u_int *vers_hi, u_int *vers_lo)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_get_versions != NULL)
ret = (*rpc_gss_entries.rpc_gss_get_versions)(vers_hi, vers_lo);
return (ret);
}
static __inline bool_t
rpc_gss_is_installed_call(const char *mech)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_is_installed != NULL)
ret = (*rpc_gss_entries.rpc_gss_is_installed)(mech);
return (ret);
}
static __inline bool_t
rpc_gss_set_svc_name_call(const char *principal, const char *mechanism,
u_int req_time, u_int program, u_int version)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_set_svc_name != NULL)
ret = (*rpc_gss_entries.rpc_gss_set_svc_name)(principal,
mechanism, req_time, program, version);
return (ret);
}
static __inline void
rpc_gss_clear_svc_name_call(u_int program, u_int version)
{
if (rpc_gss_entries.rpc_gss_clear_svc_name != NULL)
(*rpc_gss_entries.rpc_gss_clear_svc_name)(program, version);
}
static __inline bool_t
rpc_gss_getcred_call(struct svc_req *req, rpc_gss_rawcred_t **rcred,
rpc_gss_ucred_t **ucred, void **cookie)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_getcred != NULL)
ret = (*rpc_gss_entries.rpc_gss_getcred)(req, rcred, ucred,
cookie);
return (ret);
}
static __inline bool_t
rpc_gss_set_callback_call(rpc_gss_callback_t *cb)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_set_callback != NULL)
ret = (*rpc_gss_entries.rpc_gss_set_callback)(cb);
return (ret);
}
static __inline void
rpc_gss_clear_callback_call(rpc_gss_callback_t *cb)
{
if (rpc_gss_entries.rpc_gss_clear_callback != NULL)
(*rpc_gss_entries.rpc_gss_clear_callback)(cb);
}
static __inline bool_t
rpc_gss_get_principal_name_call(rpc_gss_principal_t *principal,
const char *mech, const char *name, const char *node, const char *domain)
{
bool_t ret = 1;
if (rpc_gss_entries.rpc_gss_get_principal_name != NULL)
ret = (*rpc_gss_entries.rpc_gss_get_principal_name)(principal,
mech, name, node, domain);
return (ret);
}
static __inline int
rpc_gss_svc_max_data_length_call(struct svc_req *req, int max_tp_unit_len)
{
int ret = 0;
if (rpc_gss_entries.rpc_gss_svc_max_data_length != NULL)
ret = (*rpc_gss_entries.rpc_gss_svc_max_data_length)(req,
max_tp_unit_len);
return (ret);
}
static __inline void
rpc_gss_refresh_auth_call(AUTH *auth)
{
if (rpc_gss_entries.rpc_gss_refresh_auth != NULL)
(*rpc_gss_entries.rpc_gss_refresh_auth)(auth);
}
AUTH *rpc_gss_secfind(CLIENT *clnt, struct ucred *cred,
const char *principal, gss_OID mech_oid, rpc_gss_service_t service);
void rpc_gss_secpurge(CLIENT *clnt);
void rpc_gss_refresh_auth(AUTH *auth);
AUTH *rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred,
const char *clnt_principal, const char *principal,
const char *mechanism, rpc_gss_service_t service,
const char *qop, rpc_gss_options_req_t *options_req,
rpc_gss_options_ret_t *options_ret);
#else /* !_KERNEL */
AUTH *rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred,
const char *principal, const char *mechanism, rpc_gss_service_t service,
const char *qop, rpc_gss_options_req_t *options_req,
rpc_gss_options_ret_t *options_ret);
#endif /* _KERNEL */
bool_t rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service,
const char *qop);
int rpc_gss_max_data_length(AUTH *handle, int max_tp_unit_len);
void rpc_gss_get_error(rpc_gss_error_t *error);
bool_t rpc_gss_mech_to_oid(const char *mech, gss_OID *oid_ret);
bool_t rpc_gss_oid_to_mech(gss_OID oid, const char **mech_ret);
bool_t rpc_gss_qop_to_num(const char *qop, const char *mech, u_int *num_ret);
const char **rpc_gss_get_mechanisms(void);
const char **rpc_gss_get_mech_info(const char *mech, rpc_gss_service_t *service);
bool_t rpc_gss_get_versions(u_int *vers_hi, u_int *vers_lo);
bool_t rpc_gss_is_installed(const char *mech);
bool_t rpc_gss_set_svc_name(const char *principal, const char *mechanism,
u_int req_time, u_int program, u_int version);
void rpc_gss_clear_svc_name(u_int program, u_int version);
bool_t rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred,
rpc_gss_ucred_t **ucred, void **cookie);
bool_t rpc_gss_set_callback(rpc_gss_callback_t *cb);
void rpc_gss_clear_callback(rpc_gss_callback_t *cb);
bool_t rpc_gss_get_principal_name(rpc_gss_principal_t *principal,
const char *mech, const char *name, const char *node, const char *domain);
int rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len);
/*
* Internal interface from the RPC implementation.
*/
#ifndef _KERNEL
bool_t __rpc_gss_wrap(AUTH *auth, void *header, size_t headerlen,
XDR* xdrs, xdrproc_t xdr_args, void *args_ptr);
bool_t __rpc_gss_unwrap(AUTH *auth, XDR* xdrs, xdrproc_t xdr_args,
void *args_ptr);
#endif
bool_t __rpc_gss_set_error(int rpc_gss_error, int system_error);
__END_DECLS
#endif /* !_RPCSEC_GSS_H */

1475
freebsd/sys/rpc/svc.c Normal file

File diff suppressed because it is too large Load Diff

911
freebsd/sys/rpc/svc.h Normal file
View File

@ -0,0 +1,911 @@
/* $NetBSD: svc.h,v 1.17 2000/06/02 22:57:56 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)svc.h 1.35 88/12/17 SMI
* from: @(#)svc.h 1.27 94/04/25 SMI
* $FreeBSD$
*/
/*
* svc.h, Server-side remote procedure call interface.
*
* Copyright (C) 1986-1993 by Sun Microsystems, Inc.
*/
#ifndef _RPC_SVC_H
#define _RPC_SVC_H
#include <sys/cdefs.h>
#ifdef _KERNEL
#include <sys/queue.h>
#include <sys/_lock.h>
#include <sys/_mutex.h>
#include <sys/_sx.h>
#include <sys/condvar.h>
#include <sys/sysctl.h>
#endif
/*
* This interface must manage two items concerning remote procedure calling:
*
* 1) An arbitrary number of transport connections upon which rpc requests
* are received. The two most notable transports are TCP and UDP; they are
* created and registered by routines in svc_tcp.c and svc_udp.c, respectively;
* they in turn call xprt_register and xprt_unregister.
*
* 2) An arbitrary number of locally registered services. Services are
* described by the following four data: program number, version number,
* "service dispatch" function, a transport handle, and a boolean that
* indicates whether or not the exported program should be registered with a
* local binder service; if true the program's number and version and the
* port number from the transport handle are registered with the binder.
* These data are registered with the rpc svc system via svc_register.
*
* A service's dispatch function is called whenever an rpc request comes in
* on a transport. The request's program and version numbers must match
* those of the registered service. The dispatch function is passed two
* parameters, struct svc_req * and SVCXPRT *, defined below.
*/
/*
* Service control requests
*/
#define SVCGET_VERSQUIET 1
#define SVCSET_VERSQUIET 2
#define SVCGET_CONNMAXREC 3
#define SVCSET_CONNMAXREC 4
/*
* Operations for rpc_control().
*/
#define RPC_SVC_CONNMAXREC_SET 0 /* set max rec size, enable nonblock */
#define RPC_SVC_CONNMAXREC_GET 1
enum xprt_stat {
XPRT_DIED,
XPRT_MOREREQS,
XPRT_IDLE
};
struct __rpc_svcxprt;
struct mbuf;
struct xp_ops {
#ifdef _KERNEL
/* receive incoming requests */
bool_t (*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *,
struct sockaddr **, struct mbuf **);
/* get transport status */
enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *);
/* get transport acknowledge sequence */
bool_t (*xp_ack)(struct __rpc_svcxprt *, uint32_t *);
/* send reply */
bool_t (*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *,
struct sockaddr *, struct mbuf *, uint32_t *);
/* destroy this struct */
void (*xp_destroy)(struct __rpc_svcxprt *);
/* catch-all function */
bool_t (*xp_control)(struct __rpc_svcxprt *, const u_int, void *);
#else
/* receive incoming requests */
bool_t (*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *);
/* get transport status */
enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *);
/* get arguments */
bool_t (*xp_getargs)(struct __rpc_svcxprt *, xdrproc_t, void *);
/* send reply */
bool_t (*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *);
/* free mem allocated for args */
bool_t (*xp_freeargs)(struct __rpc_svcxprt *, xdrproc_t, void *);
/* destroy this struct */
void (*xp_destroy)(struct __rpc_svcxprt *);
#endif
};
#ifndef _KERNEL
struct xp_ops2 {
/* catch-all function */
bool_t (*xp_control)(struct __rpc_svcxprt *, const u_int, void *);
};
#endif
#ifdef _KERNEL
struct __rpc_svcpool;
struct __rpc_svcgroup;
struct __rpc_svcthread;
#endif
/*
* Server side transport handle. In the kernel, transports have a
* reference count which tracks the number of currently assigned
* worker threads plus one for the service pool's reference.
* For NFSv4.1 sessions, a reference is also held for a backchannel.
*/
typedef struct __rpc_svcxprt {
#ifdef _KERNEL
volatile u_int xp_refs;
struct sx xp_lock;
struct __rpc_svcpool *xp_pool; /* owning pool (see below) */
struct __rpc_svcgroup *xp_group; /* owning group (see below) */
TAILQ_ENTRY(__rpc_svcxprt) xp_link;
TAILQ_ENTRY(__rpc_svcxprt) xp_alink;
bool_t xp_registered; /* xprt_register has been called */
bool_t xp_active; /* xprt_active has been called */
struct __rpc_svcthread *xp_thread; /* assigned service thread */
struct socket* xp_socket;
const struct xp_ops *xp_ops;
char *xp_netid; /* network token */
struct sockaddr_storage xp_ltaddr; /* local transport address */
struct sockaddr_storage xp_rtaddr; /* remote transport address */
void *xp_p1; /* private: for use by svc ops */
void *xp_p2; /* private: for use by svc ops */
void *xp_p3; /* private: for use by svc lib */
int xp_type; /* transport type */
int xp_idletimeout; /* idle time before closing */
time_t xp_lastactive; /* time of last RPC */
u_int64_t xp_sockref; /* set by nfsv4 to identify socket */
int xp_upcallset; /* socket upcall is set up */
uint32_t xp_snd_cnt; /* # of bytes to send to socket */
uint32_t xp_snt_cnt; /* # of bytes sent to socket */
#else
int xp_fd;
u_short xp_port; /* associated port number */
const struct xp_ops *xp_ops;
int xp_addrlen; /* length of remote address */
struct sockaddr_in xp_raddr; /* remote addr. (backward ABI compat) */
/* XXX - fvdl stick this here for ABI backward compat reasons */
const struct xp_ops2 *xp_ops2;
char *xp_tp; /* transport provider device name */
char *xp_netid; /* network token */
struct netbuf xp_ltaddr; /* local transport address */
struct netbuf xp_rtaddr; /* remote transport address */
struct opaque_auth xp_verf; /* raw response verifier */
void *xp_p1; /* private: for use by svc ops */
void *xp_p2; /* private: for use by svc ops */
void *xp_p3; /* private: for use by svc lib */
int xp_type; /* transport type */
#endif
} SVCXPRT;
/*
* Interface to server-side authentication flavors.
*/
typedef struct __rpc_svcauth {
struct svc_auth_ops {
#ifdef _KERNEL
int (*svc_ah_wrap)(struct __rpc_svcauth *, struct mbuf **);
int (*svc_ah_unwrap)(struct __rpc_svcauth *, struct mbuf **);
void (*svc_ah_release)(struct __rpc_svcauth *);
#else
int (*svc_ah_wrap)(struct __rpc_svcauth *, XDR *,
xdrproc_t, caddr_t);
int (*svc_ah_unwrap)(struct __rpc_svcauth *, XDR *,
xdrproc_t, caddr_t);
#endif
} *svc_ah_ops;
void *svc_ah_private;
} SVCAUTH;
/*
* Server transport extensions (accessed via xp_p3).
*/
typedef struct __rpc_svcxprt_ext {
int xp_flags; /* versquiet */
SVCAUTH xp_auth; /* interface to auth methods */
} SVCXPRT_EXT;
#ifdef _KERNEL
/*
* The services list
* Each entry represents a set of procedures (an rpc program).
* The dispatch routine takes request structs and runs the
* appropriate procedure.
*/
struct svc_callout {
TAILQ_ENTRY(svc_callout) sc_link;
rpcprog_t sc_prog;
rpcvers_t sc_vers;
char *sc_netid;
void (*sc_dispatch)(struct svc_req *, SVCXPRT *);
};
TAILQ_HEAD(svc_callout_list, svc_callout);
/*
* The services connection loss list
* The dispatch routine takes request structs and runs the
* appropriate procedure.
*/
struct svc_loss_callout {
TAILQ_ENTRY(svc_loss_callout) slc_link;
void (*slc_dispatch)(SVCXPRT *);
};
TAILQ_HEAD(svc_loss_callout_list, svc_loss_callout);
/*
* Service request
*/
struct svc_req {
STAILQ_ENTRY(svc_req) rq_link; /* list of requests for a thread */
struct __rpc_svcthread *rq_thread; /* thread which is to execute this */
uint32_t rq_xid; /* RPC transaction ID */
uint32_t rq_prog; /* service program number */
uint32_t rq_vers; /* service protocol version */
uint32_t rq_proc; /* the desired procedure */
size_t rq_size; /* space used by request */
struct mbuf *rq_args; /* XDR-encoded procedure arguments */
struct opaque_auth rq_cred; /* raw creds from the wire */
struct opaque_auth rq_verf; /* verifier for the reply */
void *rq_clntcred; /* read only cooked cred */
SVCAUTH rq_auth; /* interface to auth methods */
SVCXPRT *rq_xprt; /* associated transport */
struct sockaddr *rq_addr; /* reply address or NULL if connected */
void *rq_p1; /* application workspace */
int rq_p2; /* application workspace */
uint64_t rq_p3; /* application workspace */
uint32_t rq_reply_seq; /* reply socket sequence # */
char rq_credarea[3*MAX_AUTH_BYTES];
};
STAILQ_HEAD(svc_reqlist, svc_req);
#define svc_getrpccaller(rq) \
((rq)->rq_addr ? (rq)->rq_addr : \
(struct sockaddr *) &(rq)->rq_xprt->xp_rtaddr)
/*
* This structure is used to manage a thread which is executing
* requests from a service pool. A service thread is in one of three
* states:
*
* SVCTHREAD_SLEEPING waiting for a request to process
* SVCTHREAD_ACTIVE processing a request
* SVCTHREAD_EXITING exiting after finishing current request
*
* Threads which have no work to process sleep on the pool's sp_active
* list. When a transport becomes active, it is assigned a service
* thread to read and execute pending RPCs.
*/
typedef struct __rpc_svcthread {
struct mtx_padalign st_lock; /* protects st_reqs field */
struct __rpc_svcpool *st_pool;
SVCXPRT *st_xprt; /* transport we are processing */
struct svc_reqlist st_reqs; /* RPC requests to execute */
struct cv st_cond; /* sleeping for work */
LIST_ENTRY(__rpc_svcthread) st_ilink; /* idle threads list */
LIST_ENTRY(__rpc_svcthread) st_alink; /* application thread list */
int st_p2; /* application workspace */
uint64_t st_p3; /* application workspace */
} SVCTHREAD;
LIST_HEAD(svcthread_list, __rpc_svcthread);
/*
* A thread group contain all information needed to assign subset of
* transports to subset of threads. On systems with many CPUs and many
* threads that allows to reduce lock congestion and improve performance.
* Hundreds of threads on dozens of CPUs sharing the single pool lock do
* not scale well otherwise.
*/
TAILQ_HEAD(svcxprt_list, __rpc_svcxprt);
enum svcpool_state {
SVCPOOL_INIT, /* svc_run not called yet */
SVCPOOL_ACTIVE, /* normal running state */
SVCPOOL_THREADWANTED, /* new service thread requested */
SVCPOOL_THREADSTARTING, /* new service thread started */
SVCPOOL_CLOSING /* svc_exit called */
};
typedef struct __rpc_svcgroup {
struct mtx_padalign sg_lock; /* protect the thread/req lists */
struct __rpc_svcpool *sg_pool;
enum svcpool_state sg_state; /* current pool state */
struct svcxprt_list sg_xlist; /* all transports in the group */
struct svcxprt_list sg_active; /* transports needing service */
struct svcthread_list sg_idlethreads; /* idle service threads */
int sg_minthreads; /* minimum service thread count */
int sg_maxthreads; /* maximum service thread count */
int sg_threadcount; /* current service thread count */
time_t sg_lastcreatetime; /* when we last started a thread */
time_t sg_lastidlecheck; /* when we last checked idle transports */
} SVCGROUP;
/*
* In the kernel, we can't use global variables to store lists of
* transports etc. since otherwise we could not have two unrelated RPC
* services running, each on its own thread. We solve this by
* importing a tiny part of a Solaris kernel concept, SVCPOOL.
*
* A service pool contains a set of transports and service callbacks
* for a set of related RPC services. The pool handle should be passed
* when creating new transports etc. Future work may include extending
* this to support something similar to the Solaris multi-threaded RPC
* server.
*/
typedef SVCTHREAD *pool_assign_fn(SVCTHREAD *, struct svc_req *);
typedef void pool_done_fn(SVCTHREAD *, struct svc_req *);
#define SVC_MAXGROUPS 16
typedef struct __rpc_svcpool {
struct mtx_padalign sp_lock; /* protect the transport lists */
const char *sp_name; /* pool name (e.g. "nfsd", "NLM" */
enum svcpool_state sp_state; /* current pool state */
struct proc *sp_proc; /* process which is in svc_run */
struct svc_callout_list sp_callouts; /* (prog,vers)->dispatch list */
struct svc_loss_callout_list sp_lcallouts; /* loss->dispatch list */
int sp_minthreads; /* minimum service thread count */
int sp_maxthreads; /* maximum service thread count */
/*
* Hooks to allow an application to control request to thread
* placement.
*/
pool_assign_fn *sp_assign;
pool_done_fn *sp_done;
/*
* These variables are used to put an upper bound on the
* amount of memory used by RPC requests which are queued
* waiting for execution.
*/
unsigned long sp_space_low;
unsigned long sp_space_high;
unsigned long sp_space_used;
unsigned long sp_space_used_highest;
bool_t sp_space_throttled;
int sp_space_throttle_count;
struct replay_cache *sp_rcache; /* optional replay cache */
struct sysctl_ctx_list sp_sysctl;
int sp_groupcount; /* Number of groups in the pool. */
int sp_nextgroup; /* Next group to assign port. */
SVCGROUP sp_groups[SVC_MAXGROUPS]; /* Thread/port groups. */
} SVCPOOL;
#else
/*
* Service request
*/
struct svc_req {
uint32_t rq_prog; /* service program number */
uint32_t rq_vers; /* service protocol version */
uint32_t rq_proc; /* the desired procedure */
struct opaque_auth rq_cred; /* raw creds from the wire */
void *rq_clntcred; /* read only cooked cred */
SVCXPRT *rq_xprt; /* associated transport */
};
/*
* Approved way of getting address of caller
*/
#define svc_getrpccaller(x) (&(x)->xp_rtaddr)
#endif
/*
* Operations defined on an SVCXPRT handle
*
* SVCXPRT *xprt;
* struct rpc_msg *msg;
* xdrproc_t xargs;
* void * argsp;
*/
#ifdef _KERNEL
#define SVC_ACQUIRE(xprt) \
refcount_acquire(&(xprt)->xp_refs)
#define SVC_RELEASE(xprt) \
if (refcount_release(&(xprt)->xp_refs)) \
SVC_DESTROY(xprt)
#define SVC_RECV(xprt, msg, addr, args) \
(*(xprt)->xp_ops->xp_recv)((xprt), (msg), (addr), (args))
#define SVC_STAT(xprt) \
(*(xprt)->xp_ops->xp_stat)(xprt)
#define SVC_ACK(xprt, ack) \
((xprt)->xp_ops->xp_ack == NULL ? FALSE : \
((ack) == NULL ? TRUE : (*(xprt)->xp_ops->xp_ack)((xprt), (ack))))
#define SVC_REPLY(xprt, msg, addr, m, seq) \
(*(xprt)->xp_ops->xp_reply) ((xprt), (msg), (addr), (m), (seq))
#define SVC_DESTROY(xprt) \
(*(xprt)->xp_ops->xp_destroy)(xprt)
#define SVC_CONTROL(xprt, rq, in) \
(*(xprt)->xp_ops->xp_control)((xprt), (rq), (in))
#else
#define SVC_RECV(xprt, msg) \
(*(xprt)->xp_ops->xp_recv)((xprt), (msg))
#define svc_recv(xprt, msg) \
(*(xprt)->xp_ops->xp_recv)((xprt), (msg))
#define SVC_STAT(xprt) \
(*(xprt)->xp_ops->xp_stat)(xprt)
#define svc_stat(xprt) \
(*(xprt)->xp_ops->xp_stat)(xprt)
#define SVC_GETARGS(xprt, xargs, argsp) \
(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
#define svc_getargs(xprt, xargs, argsp) \
(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
#define SVC_REPLY(xprt, msg) \
(*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
#define svc_reply(xprt, msg) \
(*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
#define SVC_FREEARGS(xprt, xargs, argsp) \
(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
#define svc_freeargs(xprt, xargs, argsp) \
(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
#define SVC_DESTROY(xprt) \
(*(xprt)->xp_ops->xp_destroy)(xprt)
#define svc_destroy(xprt) \
(*(xprt)->xp_ops->xp_destroy)(xprt)
#define SVC_CONTROL(xprt, rq, in) \
(*(xprt)->xp_ops2->xp_control)((xprt), (rq), (in))
#endif
#define SVC_EXT(xprt) \
((SVCXPRT_EXT *) xprt->xp_p3)
#define SVC_AUTH(xprt) \
(SVC_EXT(xprt)->xp_auth)
/*
* Operations defined on an SVCAUTH handle
*/
#ifdef _KERNEL
#define SVCAUTH_WRAP(auth, mp) \
((auth)->svc_ah_ops->svc_ah_wrap(auth, mp))
#define SVCAUTH_UNWRAP(auth, mp) \
((auth)->svc_ah_ops->svc_ah_unwrap(auth, mp))
#define SVCAUTH_RELEASE(auth) \
((auth)->svc_ah_ops->svc_ah_release(auth))
#else
#define SVCAUTH_WRAP(auth, xdrs, xfunc, xwhere) \
((auth)->svc_ah_ops->svc_ah_wrap(auth, xdrs, xfunc, xwhere))
#define SVCAUTH_UNWRAP(auth, xdrs, xfunc, xwhere) \
((auth)->svc_ah_ops->svc_ah_unwrap(auth, xdrs, xfunc, xwhere))
#endif
/*
* Service registration
*
* svc_reg(xprt, prog, vers, dispatch, nconf)
* const SVCXPRT *xprt;
* const rpcprog_t prog;
* const rpcvers_t vers;
* const void (*dispatch)();
* const struct netconfig *nconf;
*/
__BEGIN_DECLS
extern bool_t svc_reg(SVCXPRT *, const rpcprog_t, const rpcvers_t,
void (*)(struct svc_req *, SVCXPRT *),
const struct netconfig *);
__END_DECLS
/*
* Service un-registration
*
* svc_unreg(prog, vers)
* const rpcprog_t prog;
* const rpcvers_t vers;
*/
__BEGIN_DECLS
#ifdef _KERNEL
extern void svc_unreg(SVCPOOL *, const rpcprog_t, const rpcvers_t);
#else
extern void svc_unreg(const rpcprog_t, const rpcvers_t);
#endif
__END_DECLS
#ifdef _KERNEL
/*
* Service connection loss registration
*
* svc_loss_reg(xprt, dispatch)
* const SVCXPRT *xprt;
* const void (*dispatch)();
*/
__BEGIN_DECLS
extern bool_t svc_loss_reg(SVCXPRT *, void (*)(SVCXPRT *));
__END_DECLS
/*
* Service connection loss un-registration
*
* svc_loss_unreg(xprt, dispatch)
* const SVCXPRT *xprt;
* const void (*dispatch)();
*/
__BEGIN_DECLS
extern void svc_loss_unreg(SVCPOOL *, void (*)(SVCXPRT *));
__END_DECLS
#endif
/*
* Transport registration.
*
* xprt_register(xprt)
* SVCXPRT *xprt;
*/
__BEGIN_DECLS
extern void xprt_register(SVCXPRT *);
__END_DECLS
/*
* Transport un-register
*
* xprt_unregister(xprt)
* SVCXPRT *xprt;
*/
__BEGIN_DECLS
extern void xprt_unregister(SVCXPRT *);
extern void __xprt_unregister_unlocked(SVCXPRT *);
__END_DECLS
#ifdef _KERNEL
/*
* Called when a transport has pending requests.
*/
__BEGIN_DECLS
extern void xprt_active(SVCXPRT *);
extern void xprt_inactive(SVCXPRT *);
extern void xprt_inactive_locked(SVCXPRT *);
extern void xprt_inactive_self(SVCXPRT *);
__END_DECLS
#endif
/*
* When the service routine is called, it must first check to see if it
* knows about the procedure; if not, it should call svcerr_noproc
* and return. If so, it should deserialize its arguments via
* SVC_GETARGS (defined above). If the deserialization does not work,
* svcerr_decode should be called followed by a return. Successful
* decoding of the arguments should be followed the execution of the
* procedure's code and a call to svc_sendreply.
*
* Also, if the service refuses to execute the procedure due to too-
* weak authentication parameters, svcerr_weakauth should be called.
* Note: do not confuse access-control failure with weak authentication!
*
* NB: In pure implementations of rpc, the caller always waits for a reply
* msg. This message is sent when svc_sendreply is called.
* Therefore pure service implementations should always call
* svc_sendreply even if the function logically returns void; use
* xdr.h - xdr_void for the xdr routine. HOWEVER, tcp based rpc allows
* for the abuse of pure rpc via batched calling or pipelining. In the
* case of a batched call, svc_sendreply should NOT be called since
* this would send a return message, which is what batching tries to avoid.
* It is the service/protocol writer's responsibility to know which calls are
* batched and which are not. Warning: responding to batch calls may
* deadlock the caller and server processes!
*/
__BEGIN_DECLS
#ifdef _KERNEL
extern bool_t svc_sendreply(struct svc_req *, xdrproc_t, void *);
extern bool_t svc_sendreply_mbuf(struct svc_req *, struct mbuf *);
extern void svcerr_decode(struct svc_req *);
extern void svcerr_weakauth(struct svc_req *);
extern void svcerr_noproc(struct svc_req *);
extern void svcerr_progvers(struct svc_req *, rpcvers_t, rpcvers_t);
extern void svcerr_auth(struct svc_req *, enum auth_stat);
extern void svcerr_noprog(struct svc_req *);
extern void svcerr_systemerr(struct svc_req *);
#else
extern bool_t svc_sendreply(SVCXPRT *, xdrproc_t, void *);
extern void svcerr_decode(SVCXPRT *);
extern void svcerr_weakauth(SVCXPRT *);
extern void svcerr_noproc(SVCXPRT *);
extern void svcerr_progvers(SVCXPRT *, rpcvers_t, rpcvers_t);
extern void svcerr_auth(SVCXPRT *, enum auth_stat);
extern void svcerr_noprog(SVCXPRT *);
extern void svcerr_systemerr(SVCXPRT *);
#endif
extern int rpc_reg(rpcprog_t, rpcvers_t, rpcproc_t,
char *(*)(char *), xdrproc_t, xdrproc_t,
char *);
__END_DECLS
/*
* Lowest level dispatching -OR- who owns this process anyway.
* Somebody has to wait for incoming requests and then call the correct
* service routine. The routine svc_run does infinite waiting; i.e.,
* svc_run never returns.
* Since another (co-existant) package may wish to selectively wait for
* incoming calls or other events outside of the rpc architecture, the
* routine svc_getreq is provided. It must be passed readfds, the
* "in-place" results of a select system call (see select, section 2).
*/
#ifndef _KERNEL
/*
* Global keeper of rpc service descriptors in use
* dynamic; must be inspected before each call to select
*/
extern int svc_maxfd;
#ifdef FD_SETSIZE
extern fd_set svc_fdset;
#define svc_fds svc_fdset.fds_bits[0] /* compatibility */
#else
extern int svc_fds;
#endif /* def FD_SETSIZE */
#endif
/*
* a small program implemented by the svc_rpc implementation itself;
* also see clnt.h for protocol numbers.
*/
__BEGIN_DECLS
extern void rpctest_service(void);
__END_DECLS
__BEGIN_DECLS
extern SVCXPRT *svc_xprt_alloc(void);
extern void svc_xprt_free(SVCXPRT *);
#ifndef _KERNEL
extern void svc_getreq(int);
extern void svc_getreqset(fd_set *);
extern void svc_getreq_common(int);
struct pollfd;
extern void svc_getreq_poll(struct pollfd *, int);
extern void svc_run(void);
extern void svc_exit(void);
#else
extern void svc_run(SVCPOOL *);
extern void svc_exit(SVCPOOL *);
extern bool_t svc_getargs(struct svc_req *, xdrproc_t, void *);
extern bool_t svc_freeargs(struct svc_req *, xdrproc_t, void *);
extern void svc_freereq(struct svc_req *);
#endif
__END_DECLS
/*
* Socket to use on svcxxx_create call to get default socket
*/
#define RPC_ANYSOCK -1
#define RPC_ANYFD RPC_ANYSOCK
/*
* These are the existing service side transport implementations
*/
__BEGIN_DECLS
#ifdef _KERNEL
/*
* Create a new service pool.
*/
extern SVCPOOL* svcpool_create(const char *name,
struct sysctl_oid_list *sysctl_base);
/*
* Destroy a service pool, including all registered transports.
*/
extern void svcpool_destroy(SVCPOOL *pool);
/*
* Close a service pool. Similar to svcpool_destroy(), but it does not
* free the data structures. As such, the pool can be used again.
*/
extern void svcpool_close(SVCPOOL *pool);
/*
* Transport independent svc_create routine.
*/
extern int svc_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *),
const rpcprog_t, const rpcvers_t, const char *);
/*
* void (*dispatch)(); -- dispatch routine
* const rpcprog_t prognum; -- program number
* const rpcvers_t versnum; -- version number
* const char *nettype; -- network type
*/
/*
* Generic server creation routine. It takes a netconfig structure
* instead of a nettype.
*/
extern SVCXPRT *svc_tp_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *),
const rpcprog_t, const rpcvers_t, const char *uaddr,
const struct netconfig *);
/*
* void (*dispatch)(); -- dispatch routine
* const rpcprog_t prognum; -- program number
* const rpcvers_t versnum; -- version number
* const char *uaddr; -- universal address of service
* const struct netconfig *nconf; -- netconfig structure
*/
extern SVCXPRT *svc_dg_create(SVCPOOL *, struct socket *,
const size_t, const size_t);
/*
* struct socket *; -- open connection
* const size_t sendsize; -- max send size
* const size_t recvsize; -- max recv size
*/
extern SVCXPRT *svc_vc_create(SVCPOOL *, struct socket *,
const size_t, const size_t);
/*
* struct socket *; -- open connection
* const size_t sendsize; -- max send size
* const size_t recvsize; -- max recv size
*/
extern SVCXPRT *svc_vc_create_backchannel(SVCPOOL *);
extern void *clnt_bck_create(struct socket *, const rpcprog_t, const rpcvers_t);
/*
* struct socket *; -- server transport socket
* const rpcprog_t prog; -- RPC program number
* const rpcvers_t vers; -- RPC program version
*/
/*
* Generic TLI create routine
*/
extern SVCXPRT *svc_tli_create(SVCPOOL *, struct socket *,
const struct netconfig *, const struct t_bind *, const size_t, const size_t);
/*
* struct socket * so; -- connection end point
* const struct netconfig *nconf; -- netconfig structure for network
* const struct t_bind *bindaddr; -- local bind address
* const size_t sendsz; -- max sendsize
* const size_t recvsz; -- max recvsize
*/
#else /* !_KERNEL */
/*
* Transport independent svc_create routine.
*/
extern int svc_create(void (*)(struct svc_req *, SVCXPRT *),
const rpcprog_t, const rpcvers_t, const char *);
/*
* void (*dispatch)(); -- dispatch routine
* const rpcprog_t prognum; -- program number
* const rpcvers_t versnum; -- version number
* const char *nettype; -- network type
*/
/*
* Generic server creation routine. It takes a netconfig structure
* instead of a nettype.
*/
extern SVCXPRT *svc_tp_create(void (*)(struct svc_req *, SVCXPRT *),
const rpcprog_t, const rpcvers_t,
const struct netconfig *);
/*
* void (*dispatch)(); -- dispatch routine
* const rpcprog_t prognum; -- program number
* const rpcvers_t versnum; -- version number
* const struct netconfig *nconf; -- netconfig structure
*/
/*
* Generic TLI create routine
*/
extern SVCXPRT *svc_tli_create(const int, const struct netconfig *,
const struct t_bind *, const u_int,
const u_int);
/*
* const int fd; -- connection end point
* const struct netconfig *nconf; -- netconfig structure for network
* const struct t_bind *bindaddr; -- local bind address
* const u_int sendsz; -- max sendsize
* const u_int recvsz; -- max recvsize
*/
/*
* Connectionless and connectionful create routines
*/
extern SVCXPRT *svc_vc_create(const int, const u_int, const u_int);
/*
* const int fd; -- open connection end point
* const u_int sendsize; -- max send size
* const u_int recvsize; -- max recv size
*/
/*
* Added for compatibility to old rpc 4.0. Obsoleted by svc_vc_create().
*/
extern SVCXPRT *svcunix_create(int, u_int, u_int, char *);
extern SVCXPRT *svc_dg_create(const int, const u_int, const u_int);
/*
* const int fd; -- open connection
* const u_int sendsize; -- max send size
* const u_int recvsize; -- max recv size
*/
/*
* the routine takes any *open* connection
* descriptor as its first input and is used for open connections.
*/
extern SVCXPRT *svc_fd_create(const int, const u_int, const u_int);
/*
* const int fd; -- open connection end point
* const u_int sendsize; -- max send size
* const u_int recvsize; -- max recv size
*/
/*
* Added for compatibility to old rpc 4.0. Obsoleted by svc_fd_create().
*/
extern SVCXPRT *svcunixfd_create(int, u_int, u_int);
/*
* Memory based rpc (for speed check and testing)
*/
extern SVCXPRT *svc_raw_create(void);
/*
* svc_dg_enable_cache() enables the cache on dg transports.
*/
int svc_dg_enablecache(SVCXPRT *, const u_int);
int __rpc_get_local_uid(SVCXPRT *_transp, uid_t *_uid);
#endif /* !_KERNEL */
__END_DECLS
#ifndef _KERNEL
/* for backward compatibility */
#include <rpc/svc_soc.h>
#endif
#endif /* !_RPC_SVC_H */

198
freebsd/sys/rpc/svc_auth.c Normal file
View File

@ -0,0 +1,198 @@
/* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)svc_auth.c 1.16 94/04/24 SMI"
static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* svc_auth.c, Server-side rpc authenticator interface.
*
*/
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
#include <sys/jail.h>
#include <sys/ucred.h>
#include <rpc/rpc.h>
static enum auth_stat (*_svcauth_rpcsec_gss)(struct svc_req *,
struct rpc_msg *) = NULL;
static int (*_svcauth_rpcsec_gss_getcred)(struct svc_req *,
struct ucred **, int *);
static struct svc_auth_ops svc_auth_null_ops;
/*
* The call rpc message, msg has been obtained from the wire. The msg contains
* the raw form of credentials and verifiers. authenticate returns AUTH_OK
* if the msg is successfully authenticated. If AUTH_OK then the routine also
* does the following things:
* set rqst->rq_xprt->verf to the appropriate response verifier;
* sets rqst->rq_client_cred to the "cooked" form of the credentials.
*
* NB: rqst->rq_cxprt->verf must be pre-alloctaed;
* its length is set appropriately.
*
* The caller still owns and is responsible for msg->u.cmb.cred and
* msg->u.cmb.verf. The authentication system retains ownership of
* rqst->rq_client_cred, the cooked credentials.
*
* There is an assumption that any flavour less than AUTH_NULL is
* invalid.
*/
enum auth_stat
_authenticate(struct svc_req *rqst, struct rpc_msg *msg)
{
int cred_flavor;
enum auth_stat dummy;
rqst->rq_cred = msg->rm_call.cb_cred;
rqst->rq_auth.svc_ah_ops = &svc_auth_null_ops;
rqst->rq_auth.svc_ah_private = NULL;
cred_flavor = rqst->rq_cred.oa_flavor;
switch (cred_flavor) {
case AUTH_NULL:
dummy = _svcauth_null(rqst, msg);
return (dummy);
case AUTH_SYS:
dummy = _svcauth_unix(rqst, msg);
return (dummy);
case AUTH_SHORT:
dummy = _svcauth_short(rqst, msg);
return (dummy);
case RPCSEC_GSS:
if (!_svcauth_rpcsec_gss)
return (AUTH_REJECTEDCRED);
dummy = _svcauth_rpcsec_gss(rqst, msg);
return (dummy);
default:
break;
}
return (AUTH_REJECTEDCRED);
}
/*
* A set of null auth methods used by any authentication protocols
* that don't need to inspect or modify the message body.
*/
static bool_t
svcauth_null_wrap(SVCAUTH *auth, struct mbuf **mp)
{
return (TRUE);
}
static bool_t
svcauth_null_unwrap(SVCAUTH *auth, struct mbuf **mp)
{
return (TRUE);
}
static void
svcauth_null_release(SVCAUTH *auth)
{
}
static struct svc_auth_ops svc_auth_null_ops = {
svcauth_null_wrap,
svcauth_null_unwrap,
svcauth_null_release,
};
/*ARGSUSED*/
enum auth_stat
_svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
{
rqst->rq_verf = _null_auth;
return (AUTH_OK);
}
int
svc_auth_reg(int flavor,
enum auth_stat (*svcauth)(struct svc_req *, struct rpc_msg *),
int (*getcred)(struct svc_req *, struct ucred **, int *))
{
if (flavor == RPCSEC_GSS) {
_svcauth_rpcsec_gss = svcauth;
_svcauth_rpcsec_gss_getcred = getcred;
}
return (TRUE);
}
int
svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
{
struct ucred *cr = NULL;
int flavor;
struct xucred *xcr;
flavor = rqst->rq_cred.oa_flavor;
if (flavorp)
*flavorp = flavor;
switch (flavor) {
case AUTH_UNIX:
xcr = (struct xucred *) rqst->rq_clntcred;
cr = crget();
cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid;
crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
cr->cr_prison = &prison0;
prison_hold(cr->cr_prison);
*crp = cr;
return (TRUE);
case RPCSEC_GSS:
if (!_svcauth_rpcsec_gss_getcred)
return (FALSE);
return (_svcauth_rpcsec_gss_getcred(rqst, crp, flavorp));
default:
return (FALSE);
}
}

View File

@ -0,0 +1,80 @@
/* $NetBSD: svc_auth.h,v 1.8 2000/06/02 22:57:57 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)svc_auth.h 1.6 86/07/16 SMI
* @(#)svc_auth.h 2.1 88/07/29 4.0 RPCSRC
* $FreeBSD$
*/
/*
* svc_auth.h, Service side of rpc authentication.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#ifndef _RPC_SVC_AUTH_H
#define _RPC_SVC_AUTH_H
/*
* Server side authenticator
*/
__BEGIN_DECLS
extern enum auth_stat _authenticate(struct svc_req *, struct rpc_msg *);
#ifdef _KERNEL
extern int svc_auth_reg(int,
enum auth_stat (*)(struct svc_req *, struct rpc_msg *),
int (*)(struct svc_req *, struct ucred **, int *));
#else
extern int svc_auth_reg(int, enum auth_stat (*)(struct svc_req *,
struct rpc_msg *));
#endif
extern int svc_getcred(struct svc_req *, struct ucred **, int *);
/*
* struct svc_req *req; -- RPC request
* struct ucred **crp -- Kernel cred to modify
* int *flavorp -- Return RPC auth flavor
*
* Retrieve unix creds corresponding to an RPC request, if
* possible. The auth flavor (AUTH_NONE or AUTH_UNIX) is returned in
* *flavorp. If the flavor is AUTH_UNIX the caller's ucred pointer
* will be modified to point at a ucred structure which reflects the
* values from the request. The caller should call crfree on this
* pointer.
*
* Return's non-zero if credentials were retrieved from the request,
* otherwise zero.
*/
__END_DECLS
#endif /* !_RPC_SVC_AUTH_H */

View File

@ -0,0 +1,144 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* svc_auth_unix.c
* Handles UNIX flavor authentication parameters on the service side of rpc.
* There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
* _svcauth_unix does full blown unix style uid,gid+gids auth,
* _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
* Note: the shorthand has been gutted for efficiency.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/systm.h>
#include <sys/ucred.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#define MAX_MACHINE_NAME 255
#define NGRPS 16
/*
* Unix longhand authenticator
*/
enum auth_stat
_svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
{
enum auth_stat stat;
XDR xdrs;
int32_t *buf;
uint32_t time;
struct xucred *xcr;
u_int auth_len;
size_t str_len, gid_len;
u_int i;
xcr = rqst->rq_clntcred;
auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,
XDR_DECODE);
buf = XDR_INLINE(&xdrs, auth_len);
if (buf != NULL) {
time = IXDR_GET_UINT32(buf);
str_len = (size_t)IXDR_GET_UINT32(buf);
if (str_len > MAX_MACHINE_NAME) {
stat = AUTH_BADCRED;
goto done;
}
str_len = RNDUP(str_len);
buf += str_len / sizeof (int32_t);
xcr->cr_uid = IXDR_GET_UINT32(buf);
xcr->cr_groups[0] = IXDR_GET_UINT32(buf);
gid_len = (size_t)IXDR_GET_UINT32(buf);
if (gid_len > NGRPS) {
stat = AUTH_BADCRED;
goto done;
}
for (i = 0; i < gid_len; i++) {
if (i + 1 < XU_NGROUPS)
xcr->cr_groups[i + 1] = IXDR_GET_INT32(buf);
else
buf++;
}
if (gid_len + 1 > XU_NGROUPS)
xcr->cr_ngroups = XU_NGROUPS;
else
xcr->cr_ngroups = gid_len + 1;
/*
* five is the smallest unix credentials structure -
* timestamp, hostname len (0), uid, gid, and gids len (0).
*/
if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
(void) printf("bad auth_len gid %ld str %ld auth %u\n",
(long)gid_len, (long)str_len, auth_len);
stat = AUTH_BADCRED;
goto done;
}
} else if (! xdr_authunix_parms(&xdrs, &time, xcr)) {
stat = AUTH_BADCRED;
goto done;
}
rqst->rq_verf = _null_auth;
stat = AUTH_OK;
done:
XDR_DESTROY(&xdrs);
return (stat);
}
/*
* Shorthand unix authenticator
* Looks up longhand in a cache.
*/
/*ARGSUSED*/
enum auth_stat
_svcauth_short(rqst, msg)
struct svc_req *rqst;
struct rpc_msg *msg;
{
return (AUTH_REJECTEDCRED);
}

307
freebsd/sys/rpc/svc_dg.c Normal file
View File

@ -0,0 +1,307 @@
/* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)svc_dg.c 1.17 94/04/24 SMI"
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* svc_dg.c, Server side for connectionless RPC.
*/
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/protosw.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sx.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <net/vnet.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
static enum xprt_stat svc_dg_stat(SVCXPRT *);
static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *,
struct sockaddr **, struct mbuf **);
static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *,
struct sockaddr *, struct mbuf *, uint32_t *);
static void svc_dg_destroy(SVCXPRT *);
static bool_t svc_dg_control(SVCXPRT *, const u_int, void *);
static int svc_dg_soupcall(struct socket *so, void *arg, int waitflag);
static struct xp_ops svc_dg_ops = {
.xp_recv = svc_dg_recv,
.xp_stat = svc_dg_stat,
.xp_reply = svc_dg_reply,
.xp_destroy = svc_dg_destroy,
.xp_control = svc_dg_control,
};
/*
* Usage:
* xprt = svc_dg_create(sock, sendsize, recvsize);
* Does other connectionless specific initializations.
* Once *xprt is initialized, it is registered.
* see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
* system defaults are chosen.
* The routines returns NULL if a problem occurred.
*/
static const char svc_dg_str[] = "svc_dg_create: %s";
static const char svc_dg_err1[] = "could not get transport information";
static const char svc_dg_err2[] = "transport does not support data transfer";
static const char __no_mem_str[] = "out of memory";
SVCXPRT *
svc_dg_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
size_t recvsize)
{
SVCXPRT *xprt;
struct __rpc_sockinfo si;
struct sockaddr* sa;
int error;
if (!__rpc_socket2sockinfo(so, &si)) {
printf(svc_dg_str, svc_dg_err1);
return (NULL);
}
/*
* Find the receive and the send size
*/
sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
if ((sendsize == 0) || (recvsize == 0)) {
printf(svc_dg_str, svc_dg_err2);
return (NULL);
}
xprt = svc_xprt_alloc();
sx_init(&xprt->xp_lock, "xprt->xp_lock");
xprt->xp_pool = pool;
xprt->xp_socket = so;
xprt->xp_p1 = NULL;
xprt->xp_p2 = NULL;
xprt->xp_ops = &svc_dg_ops;
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
CURVNET_RESTORE();
if (error)
goto freedata;
memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
free(sa, M_SONAME);
xprt_register(xprt);
SOCKBUF_LOCK(&so->so_rcv);
soupcall_set(so, SO_RCV, svc_dg_soupcall, xprt);
SOCKBUF_UNLOCK(&so->so_rcv);
return (xprt);
freedata:
(void) printf(svc_dg_str, __no_mem_str);
svc_xprt_free(xprt);
return (NULL);
}
/*ARGSUSED*/
static enum xprt_stat
svc_dg_stat(SVCXPRT *xprt)
{
if (soreadable(xprt->xp_socket))
return (XPRT_MOREREQS);
return (XPRT_IDLE);
}
static bool_t
svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr **addrp, struct mbuf **mp)
{
struct uio uio;
struct sockaddr *raddr;
struct mbuf *mreq;
XDR xdrs;
int error, rcvflag;
/*
* Serialise access to the socket.
*/
sx_xlock(&xprt->xp_lock);
/*
* The socket upcall calls xprt_active() which will eventually
* cause the server to call us here. We attempt to read a
* packet from the socket and process it. If the read fails,
* we have drained all pending requests so we call
* xprt_inactive().
*/
uio.uio_resid = 1000000000;
uio.uio_td = curthread;
mreq = NULL;
rcvflag = MSG_DONTWAIT;
error = soreceive(xprt->xp_socket, &raddr, &uio, &mreq, NULL, &rcvflag);
if (error == EWOULDBLOCK) {
/*
* We must re-test for readability after taking the
* lock to protect us in the case where a new packet
* arrives on the socket after our call to soreceive
* fails with EWOULDBLOCK. The pool lock protects us
* from racing the upcall after our soreadable() call
* returns false.
*/
SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
if (!soreadable(xprt->xp_socket))
xprt_inactive_self(xprt);
SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
if (error) {
SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
soupcall_clear(xprt->xp_socket, SO_RCV);
SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
xprt_inactive_self(xprt);
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
sx_xunlock(&xprt->xp_lock);
xdrmbuf_create(&xdrs, mreq, XDR_DECODE);
if (! xdr_callmsg(&xdrs, msg)) {
XDR_DESTROY(&xdrs);
return (FALSE);
}
*addrp = raddr;
*mp = xdrmbuf_getall(&xdrs);
XDR_DESTROY(&xdrs);
return (TRUE);
}
static bool_t
svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
XDR xdrs;
struct mbuf *mrep;
bool_t stat = TRUE;
int error;
mrep = m_gethdr(M_WAITOK, MT_DATA);
xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
if (!xdr_replymsg(&xdrs, msg))
stat = FALSE;
else
xdrmbuf_append(&xdrs, m);
} else {
stat = xdr_replymsg(&xdrs, msg);
}
if (stat) {
m_fixhdr(mrep);
error = sosend(xprt->xp_socket, addr, NULL, mrep, NULL,
0, curthread);
if (!error) {
stat = TRUE;
}
} else {
m_freem(mrep);
}
XDR_DESTROY(&xdrs);
xprt->xp_p2 = NULL;
return (stat);
}
static void
svc_dg_destroy(SVCXPRT *xprt)
{
SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
soupcall_clear(xprt->xp_socket, SO_RCV);
SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
sx_destroy(&xprt->xp_lock);
if (xprt->xp_socket)
(void)soclose(xprt->xp_socket);
if (xprt->xp_netid)
(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
svc_xprt_free(xprt);
}
static bool_t
/*ARGSUSED*/
svc_dg_control(xprt, rq, in)
SVCXPRT *xprt;
const u_int rq;
void *in;
{
return (FALSE);
}
static int
svc_dg_soupcall(struct socket *so, void *arg, int waitflag)
{
SVCXPRT *xprt = (SVCXPRT *) arg;
xprt_active(xprt);
return (SU_OK);
}

View File

@ -0,0 +1,328 @@
/* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)svc_generic.c 1.19 94/04/24 SMI"
static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* svc_generic.c, Server side for RPC.
*
*/
#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/protosw.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/systm.h>
#include <sys/sx.h>
#include <sys/ucred.h>
#include <net/vnet.h>
#include <rpc/rpc.h>
#include <rpc/rpcb_clnt.h>
#include <rpc/nettype.h>
#include <rpc/rpc_com.h>
extern int __svc_vc_setflag(SVCXPRT *, int);
/*
* The highest level interface for server creation.
* It tries for all the nettokens in that particular class of token
* and returns the number of handles it can create and/or find.
*
* It creates a link list of all the handles it could create.
* If svc_create() is called multiple times, it uses the handle
* created earlier instead of creating a new handle every time.
*/
int
svc_create(
SVCPOOL *pool,
void (*dispatch)(struct svc_req *, SVCXPRT *),
rpcprog_t prognum, /* Program number */
rpcvers_t versnum, /* Version number */
const char *nettype) /* Networktype token */
{
int g, num = 0;
SVCGROUP *grp;
SVCXPRT *xprt;
struct netconfig *nconf;
void *handle;
if ((handle = __rpc_setconf(nettype)) == NULL) {
printf("svc_create: unknown protocol");
return (0);
}
while ((nconf = __rpc_getconf(handle)) != NULL) {
for (g = 0; g < SVC_MAXGROUPS; g++) {
grp = &pool->sp_groups[g];
mtx_lock(&grp->sg_lock);
TAILQ_FOREACH(xprt, &grp->sg_xlist, xp_link) {
if (strcmp(xprt->xp_netid, nconf->nc_netid))
continue;
/* Found an old one, use it */
mtx_unlock(&grp->sg_lock);
(void) rpcb_unset(prognum, versnum, nconf);
if (svc_reg(xprt, prognum, versnum,
dispatch, nconf) == FALSE) {
printf(
"svc_create: could not register prog %u vers %u on %s\n",
(unsigned)prognum, (unsigned)versnum,
nconf->nc_netid);
mtx_lock(&grp->sg_lock);
} else {
num++;
mtx_lock(&grp->sg_lock);
break;
}
}
mtx_unlock(&grp->sg_lock);
}
if (xprt == NULL) {
/* It was not found. Now create a new one */
xprt = svc_tp_create(pool, dispatch, prognum, versnum,
NULL, nconf);
if (xprt) {
num++;
SVC_RELEASE(xprt);
}
}
}
__rpc_endconf(handle);
/*
* In case of num == 0; the error messages are generated by the
* underlying layers; and hence not needed here.
*/
return (num);
}
/*
* The high level interface to svc_tli_create().
* It tries to create a server for "nconf" and registers the service
* with the rpcbind. It calls svc_tli_create();
*/
SVCXPRT *
svc_tp_create(
SVCPOOL *pool,
void (*dispatch)(struct svc_req *, SVCXPRT *),
rpcprog_t prognum, /* Program number */
rpcvers_t versnum, /* Version number */
const char *uaddr, /* Address (or null for default) */
const struct netconfig *nconf) /* Netconfig structure for the network */
{
struct netconfig nconfcopy;
struct netbuf *taddr;
struct t_bind bind;
SVCXPRT *xprt;
if (nconf == NULL) {
printf(
"svc_tp_create: invalid netconfig structure for prog %u vers %u\n",
(unsigned)prognum, (unsigned)versnum);
return (NULL);
}
if (uaddr) {
taddr = uaddr2taddr(nconf, uaddr);
bind.addr = *taddr;
free(taddr, M_RPC);
bind.qlen = -1;
xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0);
free(bind.addr.buf, M_RPC);
} else {
xprt = svc_tli_create(pool, NULL, nconf, NULL, 0, 0);
}
if (xprt == NULL) {
return (NULL);
}
/*LINTED const castaway*/
nconfcopy = *nconf;
(void) rpcb_unset(prognum, versnum, &nconfcopy);
if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
printf(
"svc_tp_create: Could not register prog %u vers %u on %s\n",
(unsigned)prognum, (unsigned)versnum,
nconf->nc_netid);
xprt_unregister(xprt);
SVC_RELEASE(xprt);
return (NULL);
}
return (xprt);
}
/*
* If so is NULL, then it opens a socket for the given transport
* provider (nconf cannot be NULL then). If the t_state is T_UNBND and
* bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
* NULL bindadr and Connection oriented transports, the value of qlen
* is set to 8.
*
* If sendsz or recvsz are zero, their default values are chosen.
*/
SVCXPRT *
svc_tli_create(
SVCPOOL *pool,
struct socket *so, /* Connection end point */
const struct netconfig *nconf, /* Netconfig struct for nettoken */
const struct t_bind *bindaddr, /* Local bind address */
size_t sendsz, /* Max sendsize */
size_t recvsz) /* Max recvsize */
{
SVCXPRT *xprt = NULL; /* service handle */
bool_t madeso = FALSE; /* whether so opened here */
struct __rpc_sockinfo si;
struct sockaddr_storage ss;
if (!so) {
if (nconf == NULL) {
printf("svc_tli_create: invalid netconfig\n");
return (NULL);
}
so = __rpc_nconf2socket(nconf);
if (!so) {
printf(
"svc_tli_create: could not open connection for %s\n",
nconf->nc_netid);
return (NULL);
}
__rpc_nconf2sockinfo(nconf, &si);
madeso = TRUE;
} else {
/*
* It is an open socket. Get the transport info.
*/
if (!__rpc_socket2sockinfo(so, &si)) {
printf(
"svc_tli_create: could not get transport information\n");
return (NULL);
}
}
/*
* If the socket is unbound, try to bind it.
*/
if (madeso || !__rpc_sockisbound(so)) {
if (bindaddr == NULL) {
if (bindresvport(so, NULL)) {
memset(&ss, 0, sizeof ss);
ss.ss_family = si.si_af;
ss.ss_len = si.si_alen;
if (sobind(so, (struct sockaddr *)&ss,
curthread)) {
printf(
"svc_tli_create: could not bind to anonymous port\n");
goto freedata;
}
}
solisten(so, -1, curthread);
} else {
if (bindresvport(so,
(struct sockaddr *)bindaddr->addr.buf)) {
printf(
"svc_tli_create: could not bind to requested address\n");
goto freedata;
}
solisten(so, (int)bindaddr->qlen, curthread);
}
}
/*
* call transport specific function.
*/
switch (si.si_socktype) {
case SOCK_STREAM:
#if 0
slen = sizeof ss;
if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
== 0) {
/* accepted socket */
xprt = svc_fd_create(fd, sendsz, recvsz);
} else
#endif
xprt = svc_vc_create(pool, so, sendsz, recvsz);
if (!nconf || !xprt)
break;
#if 0
/* XXX fvdl */
if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
strcmp(nconf->nc_protofmly, "inet6") == 0)
(void) __svc_vc_setflag(xprt, TRUE);
#endif
break;
case SOCK_DGRAM:
xprt = svc_dg_create(pool, so, sendsz, recvsz);
break;
default:
printf("svc_tli_create: bad service type");
goto freedata;
}
if (xprt == NULL)
/*
* The error messages here are spitted out by the lower layers:
* svc_vc_create(), svc_fd_create() and svc_dg_create().
*/
goto freedata;
/* Fill in type of service */
xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
if (nconf) {
xprt->xp_netid = strdup(nconf->nc_netid, M_RPC);
}
return (xprt);
freedata:
if (madeso)
(void)soclose(so);
if (xprt) {
if (!madeso) /* so that svc_destroy doesnt close fd */
xprt->xp_socket = NULL;
xprt_unregister(xprt);
}
return (NULL);
}

995
freebsd/sys/rpc/svc_vc.c Normal file
View File

@ -0,0 +1,995 @@
/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* svc_vc.c, Server side for Connection Oriented based RPC.
*
* Actually implements two flavors of transporter -
* a tcp rendezvouser (a listner and connection establisher)
* and a record/tcp stream.
*/
#include <sys/param.h>
#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/sx.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <net/vnet.h>
#include <netinet/tcp.h>
#include <rpc/rpc.h>
#include <rpc/krpc.h>
#include <rpc/rpc_com.h>
#include <security/mac/mac_framework.h>
static bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
struct sockaddr **, struct mbuf **);
static enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
static void svc_vc_rendezvous_destroy(SVCXPRT *);
static bool_t svc_vc_null(void);
static void svc_vc_destroy(SVCXPRT *);
static enum xprt_stat svc_vc_stat(SVCXPRT *);
static bool_t svc_vc_ack(SVCXPRT *, uint32_t *);
static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
struct sockaddr **, struct mbuf **);
static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
struct sockaddr *, struct mbuf *, uint32_t *seq);
static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
void *in);
static void svc_vc_backchannel_destroy(SVCXPRT *);
static enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
static bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
struct sockaddr **, struct mbuf **);
static bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
struct sockaddr *, struct mbuf *, uint32_t *);
static bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
void *in);
static SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
struct sockaddr *raddr);
static int svc_vc_accept(struct socket *head, struct socket **sop);
static int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
static int svc_vc_rendezvous_soupcall(struct socket *, void *, int);
static struct xp_ops svc_vc_rendezvous_ops = {
.xp_recv = svc_vc_rendezvous_recv,
.xp_stat = svc_vc_rendezvous_stat,
.xp_reply = (bool_t (*)(SVCXPRT *, struct rpc_msg *,
struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null,
.xp_destroy = svc_vc_rendezvous_destroy,
.xp_control = svc_vc_rendezvous_control
};
static struct xp_ops svc_vc_ops = {
.xp_recv = svc_vc_recv,
.xp_stat = svc_vc_stat,
.xp_ack = svc_vc_ack,
.xp_reply = svc_vc_reply,
.xp_destroy = svc_vc_destroy,
.xp_control = svc_vc_control
};
static struct xp_ops svc_vc_backchannel_ops = {
.xp_recv = svc_vc_backchannel_recv,
.xp_stat = svc_vc_backchannel_stat,
.xp_reply = svc_vc_backchannel_reply,
.xp_destroy = svc_vc_backchannel_destroy,
.xp_control = svc_vc_backchannel_control
};
/*
* Usage:
* xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
*
* Creates, registers, and returns a (rpc) tcp based transporter.
* Once *xprt is initialized, it is registered as a transporter
* see (svc.h, xprt_register). This routine returns
* a NULL if a problem occurred.
*
* The filedescriptor passed in is expected to refer to a bound, but
* not yet connected socket.
*
* Since streams do buffered io similar to stdio, the caller can specify
* how big the send and receive buffers are via the second and third parms;
* 0 => use the system default.
*/
SVCXPRT *
svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
size_t recvsize)
{
SVCXPRT *xprt;
struct sockaddr* sa;
int error;
SOCK_LOCK(so);
if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
SOCK_UNLOCK(so);
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
CURVNET_RESTORE();
if (error)
return (NULL);
xprt = svc_vc_create_conn(pool, so, sa);
free(sa, M_SONAME);
return (xprt);
}
SOCK_UNLOCK(so);
xprt = svc_xprt_alloc();
sx_init(&xprt->xp_lock, "xprt->xp_lock");
xprt->xp_pool = pool;
xprt->xp_socket = so;
xprt->xp_p1 = NULL;
xprt->xp_p2 = NULL;
xprt->xp_ops = &svc_vc_rendezvous_ops;
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
CURVNET_RESTORE();
if (error) {
goto cleanup_svc_vc_create;
}
memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
free(sa, M_SONAME);
xprt_register(xprt);
solisten(so, -1, curthread);
SOLISTEN_LOCK(so);
xprt->xp_upcallset = 1;
solisten_upcall_set(so, svc_vc_rendezvous_soupcall, xprt);
SOLISTEN_UNLOCK(so);
return (xprt);
cleanup_svc_vc_create:
sx_destroy(&xprt->xp_lock);
svc_xprt_free(xprt);
return (NULL);
}
/*
* Create a new transport for a socket optained via soaccept().
*/
SVCXPRT *
svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
{
SVCXPRT *xprt;
struct cf_conn *cd;
struct sockaddr* sa = NULL;
struct sockopt opt;
int one = 1;
int error;
bzero(&opt, sizeof(struct sockopt));
opt.sopt_dir = SOPT_SET;
opt.sopt_level = SOL_SOCKET;
opt.sopt_name = SO_KEEPALIVE;
opt.sopt_val = &one;
opt.sopt_valsize = sizeof(one);
error = sosetopt(so, &opt);
if (error) {
return (NULL);
}
if (so->so_proto->pr_protocol == IPPROTO_TCP) {
bzero(&opt, sizeof(struct sockopt));
opt.sopt_dir = SOPT_SET;
opt.sopt_level = IPPROTO_TCP;
opt.sopt_name = TCP_NODELAY;
opt.sopt_val = &one;
opt.sopt_valsize = sizeof(one);
error = sosetopt(so, &opt);
if (error) {
return (NULL);
}
}
cd = mem_alloc(sizeof(*cd));
cd->strm_stat = XPRT_IDLE;
xprt = svc_xprt_alloc();
sx_init(&xprt->xp_lock, "xprt->xp_lock");
xprt->xp_pool = pool;
xprt->xp_socket = so;
xprt->xp_p1 = cd;
xprt->xp_p2 = NULL;
xprt->xp_ops = &svc_vc_ops;
/*
* See http://www.connectathon.org/talks96/nfstcp.pdf - client
* has a 5 minute timer, server has a 6 minute timer.
*/
xprt->xp_idletimeout = 6 * 60;
memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
CURVNET_SET(so->so_vnet);
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
CURVNET_RESTORE();
if (error)
goto cleanup_svc_vc_create;
memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
free(sa, M_SONAME);
xprt_register(xprt);
SOCKBUF_LOCK(&so->so_rcv);
xprt->xp_upcallset = 1;
soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
SOCKBUF_UNLOCK(&so->so_rcv);
/*
* Throw the transport into the active list in case it already
* has some data buffered.
*/
sx_xlock(&xprt->xp_lock);
xprt_active(xprt);
sx_xunlock(&xprt->xp_lock);
return (xprt);
cleanup_svc_vc_create:
sx_destroy(&xprt->xp_lock);
svc_xprt_free(xprt);
mem_free(cd, sizeof(*cd));
return (NULL);
}
/*
* Create a new transport for a backchannel on a clnt_vc socket.
*/
SVCXPRT *
svc_vc_create_backchannel(SVCPOOL *pool)
{
SVCXPRT *xprt = NULL;
struct cf_conn *cd = NULL;
cd = mem_alloc(sizeof(*cd));
cd->strm_stat = XPRT_IDLE;
xprt = svc_xprt_alloc();
sx_init(&xprt->xp_lock, "xprt->xp_lock");
xprt->xp_pool = pool;
xprt->xp_socket = NULL;
xprt->xp_p1 = cd;
xprt->xp_p2 = NULL;
xprt->xp_ops = &svc_vc_backchannel_ops;
return (xprt);
}
/*
* This does all of the accept except the final call to soaccept. The
* caller will call soaccept after dropping its locks (soaccept may
* call malloc).
*/
int
svc_vc_accept(struct socket *head, struct socket **sop)
{
struct socket *so;
int error = 0;
short nbio;
/* XXXGL: shouldn't that be an assertion? */
if ((head->so_options & SO_ACCEPTCONN) == 0) {
error = EINVAL;
goto done;
}
#ifdef MAC
error = mac_socket_check_accept(curthread->td_ucred, head);
if (error != 0)
goto done;
#endif
/*
* XXXGL: we want non-blocking semantics. The socket could be a
* socket created by kernel as well as socket shared with userland,
* so we can't be sure about presense of SS_NBIO. We also shall not
* toggle it on the socket, since that may surprise userland. So we
* set SS_NBIO only temporarily.
*/
SOLISTEN_LOCK(head);
nbio = head->so_state & SS_NBIO;
head->so_state |= SS_NBIO;
error = solisten_dequeue(head, &so, 0);
head->so_state &= (nbio & ~SS_NBIO);
if (error)
goto done;
so->so_state |= nbio;
*sop = so;
/* connection has been removed from the listen queue */
KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0);
done:
return (error);
}
/*ARGSUSED*/
static bool_t
svc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr **addrp, struct mbuf **mp)
{
struct socket *so = NULL;
struct sockaddr *sa = NULL;
int error;
SVCXPRT *new_xprt;
/*
* The socket upcall calls xprt_active() which will eventually
* cause the server to call us here. We attempt to accept a
* connection from the socket and turn it into a new
* transport. If the accept fails, we have drained all pending
* connections so we call xprt_inactive().
*/
sx_xlock(&xprt->xp_lock);
error = svc_vc_accept(xprt->xp_socket, &so);
if (error == EWOULDBLOCK) {
/*
* We must re-test for new connections after taking
* the lock to protect us in the case where a new
* connection arrives after our call to accept fails
* with EWOULDBLOCK.
*/
SOLISTEN_LOCK(xprt->xp_socket);
if (TAILQ_EMPTY(&xprt->xp_socket->sol_comp))
xprt_inactive_self(xprt);
SOLISTEN_UNLOCK(xprt->xp_socket);
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
if (error) {
SOLISTEN_LOCK(xprt->xp_socket);
if (xprt->xp_upcallset) {
xprt->xp_upcallset = 0;
soupcall_clear(xprt->xp_socket, SO_RCV);
}
SOLISTEN_UNLOCK(xprt->xp_socket);
xprt_inactive_self(xprt);
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
sx_xunlock(&xprt->xp_lock);
sa = NULL;
error = soaccept(so, &sa);
if (error) {
/*
* XXX not sure if I need to call sofree or soclose here.
*/
if (sa)
free(sa, M_SONAME);
return (FALSE);
}
/*
* svc_vc_create_conn will call xprt_register - we don't need
* to do anything with the new connection except derefence it.
*/
new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
if (!new_xprt) {
soclose(so);
} else {
SVC_RELEASE(new_xprt);
}
free(sa, M_SONAME);
return (FALSE); /* there is never an rpc msg to be processed */
}
/*ARGSUSED*/
static enum xprt_stat
svc_vc_rendezvous_stat(SVCXPRT *xprt)
{
return (XPRT_IDLE);
}
static void
svc_vc_destroy_common(SVCXPRT *xprt)
{
if (xprt->xp_socket)
(void)soclose(xprt->xp_socket);
if (xprt->xp_netid)
(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
svc_xprt_free(xprt);
}
static void
svc_vc_rendezvous_destroy(SVCXPRT *xprt)
{
SOLISTEN_LOCK(xprt->xp_socket);
if (xprt->xp_upcallset) {
xprt->xp_upcallset = 0;
solisten_upcall_set(xprt->xp_socket, NULL, NULL);
}
SOLISTEN_UNLOCK(xprt->xp_socket);
svc_vc_destroy_common(xprt);
}
static void
svc_vc_destroy(SVCXPRT *xprt)
{
struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
if (xprt->xp_upcallset) {
xprt->xp_upcallset = 0;
soupcall_clear(xprt->xp_socket, SO_RCV);
}
SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
svc_vc_destroy_common(xprt);
if (cd->mreq)
m_freem(cd->mreq);
if (cd->mpending)
m_freem(cd->mpending);
mem_free(cd, sizeof(*cd));
}
static void
svc_vc_backchannel_destroy(SVCXPRT *xprt)
{
struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
struct mbuf *m, *m2;
svc_xprt_free(xprt);
m = cd->mreq;
while (m != NULL) {
m2 = m;
m = m->m_nextpkt;
m_freem(m2);
}
mem_free(cd, sizeof(*cd));
}
/*ARGSUSED*/
static bool_t
svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
{
return (FALSE);
}
static bool_t
svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
{
return (FALSE);
}
static bool_t
svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
{
return (FALSE);
}
static enum xprt_stat
svc_vc_stat(SVCXPRT *xprt)
{
struct cf_conn *cd;
cd = (struct cf_conn *)(xprt->xp_p1);
if (cd->strm_stat == XPRT_DIED)
return (XPRT_DIED);
if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
return (XPRT_MOREREQS);
if (soreadable(xprt->xp_socket))
return (XPRT_MOREREQS);
return (XPRT_IDLE);
}
static bool_t
svc_vc_ack(SVCXPRT *xprt, uint32_t *ack)
{
*ack = atomic_load_acq_32(&xprt->xp_snt_cnt);
*ack -= sbused(&xprt->xp_socket->so_snd);
return (TRUE);
}
static enum xprt_stat
svc_vc_backchannel_stat(SVCXPRT *xprt)
{
struct cf_conn *cd;
cd = (struct cf_conn *)(xprt->xp_p1);
if (cd->mreq != NULL)
return (XPRT_MOREREQS);
return (XPRT_IDLE);
}
/*
* If we have an mbuf chain in cd->mpending, try to parse a record from it,
* leaving the result in cd->mreq. If we don't have a complete record, leave
* the partial result in cd->mreq and try to read more from the socket.
*/
static int
svc_vc_process_pending(SVCXPRT *xprt)
{
struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
struct socket *so = xprt->xp_socket;
struct mbuf *m;
/*
* If cd->resid is non-zero, we have part of the
* record already, otherwise we are expecting a record
* marker.
*/
if (!cd->resid && cd->mpending) {
/*
* See if there is enough data buffered to
* make up a record marker. Make sure we can
* handle the case where the record marker is
* split across more than one mbuf.
*/
size_t n = 0;
uint32_t header;
m = cd->mpending;
while (n < sizeof(uint32_t) && m) {
n += m->m_len;
m = m->m_next;
}
if (n < sizeof(uint32_t)) {
so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
return (FALSE);
}
m_copydata(cd->mpending, 0, sizeof(header),
(char *)&header);
header = ntohl(header);
cd->eor = (header & 0x80000000) != 0;
cd->resid = header & 0x7fffffff;
m_adj(cd->mpending, sizeof(uint32_t));
}
/*
* Start pulling off mbufs from cd->mpending
* until we either have a complete record or
* we run out of data. We use m_split to pull
* data - it will pull as much as possible and
* split the last mbuf if necessary.
*/
while (cd->mpending && cd->resid) {
m = cd->mpending;
if (cd->mpending->m_next
|| cd->mpending->m_len > cd->resid)
cd->mpending = m_split(cd->mpending,
cd->resid, M_WAITOK);
else
cd->mpending = NULL;
if (cd->mreq)
m_last(cd->mreq)->m_next = m;
else
cd->mreq = m;
while (m) {
cd->resid -= m->m_len;
m = m->m_next;
}
}
/*
* Block receive upcalls if we have more data pending,
* otherwise report our need.
*/
if (cd->mpending)
so->so_rcv.sb_lowat = INT_MAX;
else
so->so_rcv.sb_lowat =
imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
return (TRUE);
}
static bool_t
svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr **addrp, struct mbuf **mp)
{
struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
struct uio uio;
struct mbuf *m;
struct socket* so = xprt->xp_socket;
XDR xdrs;
int error, rcvflag;
uint32_t xid_plus_direction[2];
/*
* Serialise access to the socket and our own record parsing
* state.
*/
sx_xlock(&xprt->xp_lock);
for (;;) {
/* If we have no request ready, check pending queue. */
while (cd->mpending &&
(cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
if (!svc_vc_process_pending(xprt))
break;
}
/* Process and return complete request in cd->mreq. */
if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
/*
* Now, check for a backchannel reply.
* The XID is in the first uint32_t of the reply
* and the message direction is the second one.
*/
if ((cd->mreq->m_len >= sizeof(xid_plus_direction) ||
m_length(cd->mreq, NULL) >=
sizeof(xid_plus_direction)) &&
xprt->xp_p2 != NULL) {
m_copydata(cd->mreq, 0,
sizeof(xid_plus_direction),
(char *)xid_plus_direction);
xid_plus_direction[0] =
ntohl(xid_plus_direction[0]);
xid_plus_direction[1] =
ntohl(xid_plus_direction[1]);
/* Check message direction. */
if (xid_plus_direction[1] == REPLY) {
clnt_bck_svccall(xprt->xp_p2,
cd->mreq,
xid_plus_direction[0]);
cd->mreq = NULL;
continue;
}
}
xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
cd->mreq = NULL;
/* Check for next request in a pending queue. */
svc_vc_process_pending(xprt);
if (cd->mreq == NULL || cd->resid != 0) {
SOCKBUF_LOCK(&so->so_rcv);
if (!soreadable(so))
xprt_inactive_self(xprt);
SOCKBUF_UNLOCK(&so->so_rcv);
}
sx_xunlock(&xprt->xp_lock);
if (! xdr_callmsg(&xdrs, msg)) {
XDR_DESTROY(&xdrs);
return (FALSE);
}
*addrp = NULL;
*mp = xdrmbuf_getall(&xdrs);
XDR_DESTROY(&xdrs);
return (TRUE);
}
/*
* The socket upcall calls xprt_active() which will eventually
* cause the server to call us here. We attempt to
* read as much as possible from the socket and put
* the result in cd->mpending. If the read fails,
* we have drained both cd->mpending and the socket so
* we can call xprt_inactive().
*/
uio.uio_resid = 1000000000;
uio.uio_td = curthread;
m = NULL;
rcvflag = MSG_DONTWAIT;
error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
if (error == EWOULDBLOCK) {
/*
* We must re-test for readability after
* taking the lock to protect us in the case
* where a new packet arrives on the socket
* after our call to soreceive fails with
* EWOULDBLOCK.
*/
SOCKBUF_LOCK(&so->so_rcv);
if (!soreadable(so))
xprt_inactive_self(xprt);
SOCKBUF_UNLOCK(&so->so_rcv);
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
if (error) {
SOCKBUF_LOCK(&so->so_rcv);
if (xprt->xp_upcallset) {
xprt->xp_upcallset = 0;
soupcall_clear(so, SO_RCV);
}
SOCKBUF_UNLOCK(&so->so_rcv);
xprt_inactive_self(xprt);
cd->strm_stat = XPRT_DIED;
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
if (!m) {
/*
* EOF - the other end has closed the socket.
*/
xprt_inactive_self(xprt);
cd->strm_stat = XPRT_DIED;
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
if (cd->mpending)
m_last(cd->mpending)->m_next = m;
else
cd->mpending = m;
}
}
static bool_t
svc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr **addrp, struct mbuf **mp)
{
struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
struct ct_data *ct;
struct mbuf *m;
XDR xdrs;
sx_xlock(&xprt->xp_lock);
ct = (struct ct_data *)xprt->xp_p2;
if (ct == NULL) {
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
mtx_lock(&ct->ct_lock);
m = cd->mreq;
if (m == NULL) {
xprt_inactive_self(xprt);
mtx_unlock(&ct->ct_lock);
sx_xunlock(&xprt->xp_lock);
return (FALSE);
}
cd->mreq = m->m_nextpkt;
mtx_unlock(&ct->ct_lock);
sx_xunlock(&xprt->xp_lock);
xdrmbuf_create(&xdrs, m, XDR_DECODE);
if (! xdr_callmsg(&xdrs, msg)) {
XDR_DESTROY(&xdrs);
return (FALSE);
}
*addrp = NULL;
*mp = xdrmbuf_getall(&xdrs);
XDR_DESTROY(&xdrs);
return (TRUE);
}
static bool_t
svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
XDR xdrs;
struct mbuf *mrep;
bool_t stat = TRUE;
int error, len;
/*
* Leave space for record mark.
*/
mrep = m_gethdr(M_WAITOK, MT_DATA);
mrep->m_data += sizeof(uint32_t);
xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
if (!xdr_replymsg(&xdrs, msg))
stat = FALSE;
else
xdrmbuf_append(&xdrs, m);
} else {
stat = xdr_replymsg(&xdrs, msg);
}
if (stat) {
m_fixhdr(mrep);
/*
* Prepend a record marker containing the reply length.
*/
M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
len = mrep->m_pkthdr.len;
*mtod(mrep, uint32_t *) =
htonl(0x80000000 | (len - sizeof(uint32_t)));
atomic_add_32(&xprt->xp_snd_cnt, len);
error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
0, curthread);
if (!error) {
atomic_add_rel_32(&xprt->xp_snt_cnt, len);
if (seq)
*seq = xprt->xp_snd_cnt;
stat = TRUE;
} else
atomic_subtract_32(&xprt->xp_snd_cnt, len);
} else {
m_freem(mrep);
}
XDR_DESTROY(&xdrs);
return (stat);
}
static bool_t
svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
{
struct ct_data *ct;
XDR xdrs;
struct mbuf *mrep;
bool_t stat = TRUE;
int error;
/*
* Leave space for record mark.
*/
mrep = m_gethdr(M_WAITOK, MT_DATA);
mrep->m_data += sizeof(uint32_t);
xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
if (!xdr_replymsg(&xdrs, msg))
stat = FALSE;
else
xdrmbuf_append(&xdrs, m);
} else {
stat = xdr_replymsg(&xdrs, msg);
}
if (stat) {
m_fixhdr(mrep);
/*
* Prepend a record marker containing the reply length.
*/
M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
*mtod(mrep, uint32_t *) =
htonl(0x80000000 | (mrep->m_pkthdr.len
- sizeof(uint32_t)));
sx_xlock(&xprt->xp_lock);
ct = (struct ct_data *)xprt->xp_p2;
if (ct != NULL)
error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
0, curthread);
else
error = EPIPE;
sx_xunlock(&xprt->xp_lock);
if (!error) {
stat = TRUE;
}
} else {
m_freem(mrep);
}
XDR_DESTROY(&xdrs);
return (stat);
}
static bool_t
svc_vc_null()
{
return (FALSE);
}
static int
svc_vc_soupcall(struct socket *so, void *arg, int waitflag)
{
SVCXPRT *xprt = (SVCXPRT *) arg;
if (soreadable(xprt->xp_socket))
xprt_active(xprt);
return (SU_OK);
}
static int
svc_vc_rendezvous_soupcall(struct socket *head, void *arg, int waitflag)
{
SVCXPRT *xprt = (SVCXPRT *) arg;
if (!TAILQ_EMPTY(&head->sol_comp))
xprt_active(xprt);
return (SU_OK);
}
#if 0
/*
* Get the effective UID of the sending process. Used by rpcbind, keyserv
* and rpc.yppasswdd on AF_LOCAL.
*/
int
__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
int sock, ret;
gid_t egid;
uid_t euid;
struct sockaddr *sa;
sock = transp->xp_fd;
sa = (struct sockaddr *)transp->xp_rtaddr;
if (sa->sa_family == AF_LOCAL) {
ret = getpeereid(sock, &euid, &egid);
if (ret == 0)
*uid = euid;
return (ret);
} else
return (-1);
}
#endif

387
freebsd/sys/rpc/xdr.h Normal file
View File

@ -0,0 +1,387 @@
/* $NetBSD: xdr.h,v 1.19 2000/07/17 05:00:45 matt Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - 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.
* - Neither the name of Sun Microsystems, Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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.
*
* from: @(#)xdr.h 1.19 87/04/22 SMI
* from: @(#)xdr.h 2.2 88/07/29 4.0 RPCSRC
* $FreeBSD$
*/
/*
* xdr.h, External Data Representation Serialization Routines.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#ifndef _KRPC_XDR_H
#define _KRPC_XDR_H
#include <sys/cdefs.h>
/*
* XDR provides a conventional way for converting between C data
* types and an external bit-string representation. Library supplied
* routines provide for the conversion on built-in C data types. These
* routines and utility routines defined here are used to help implement
* a type encode/decode routine for each user-defined type.
*
* Each data type provides a single procedure which takes two arguments:
*
* bool_t
* xdrproc(xdrs, argresp)
* XDR *xdrs;
* <type> *argresp;
*
* xdrs is an instance of a XDR handle, to which or from which the data
* type is to be converted. argresp is a pointer to the structure to be
* converted. The XDR handle contains an operation field which indicates
* which of the operations (ENCODE, DECODE * or FREE) is to be performed.
*
* XDR_DECODE may allocate space if the pointer argresp is null. This
* data can be freed with the XDR_FREE operation.
*
* We write only one procedure per data type to make it easy
* to keep the encode and decode procedures for a data type consistent.
* In many cases the same code performs all operations on a user defined type,
* because all the hard work is done in the component type routines.
* decode as a series of calls on the nested data types.
*/
/*
* Xdr operations. XDR_ENCODE causes the type to be encoded into the
* stream. XDR_DECODE causes the type to be extracted from the stream.
* XDR_FREE can be used to release the space allocated by an XDR_DECODE
* request.
*/
enum xdr_op {
XDR_ENCODE=0,
XDR_DECODE=1,
XDR_FREE=2
};
/*
* This is the number of bytes per unit of external data.
*/
#define BYTES_PER_XDR_UNIT (4)
#define RNDUP(x) ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
* BYTES_PER_XDR_UNIT)
/*
* The XDR handle.
* Contains operation which is being applied to the stream,
* an operations vector for the particular implementation (e.g. see xdr_mem.c),
* and two private fields for the use of the particular implementation.
*/
typedef struct XDR {
enum xdr_op x_op; /* operation; fast additional param */
const struct xdr_ops {
/* get a long from underlying stream */
bool_t (*x_getlong)(struct XDR *, long *);
/* put a long to " */
bool_t (*x_putlong)(struct XDR *, const long *);
/* get some bytes from " */
bool_t (*x_getbytes)(struct XDR *, char *, u_int);
/* put some bytes to " */
bool_t (*x_putbytes)(struct XDR *, const char *, u_int);
/* returns bytes off from beginning */
u_int (*x_getpostn)(struct XDR *);
/* lets you reposition the stream */
bool_t (*x_setpostn)(struct XDR *, u_int);
/* buf quick ptr to buffered data */
int32_t *(*x_inline)(struct XDR *, u_int);
/* free privates of this xdr_stream */
void (*x_destroy)(struct XDR *);
bool_t (*x_control)(struct XDR *, int, void *);
} *x_ops;
char * x_public; /* users' data */
void * x_private; /* pointer to private data */
char * x_base; /* private used for position info */
u_int x_handy; /* extra private word */
} XDR;
/*
* A xdrproc_t exists for each data type which is to be encoded or decoded.
*
* The second argument to the xdrproc_t is a pointer to an opaque pointer.
* The opaque pointer generally points to a structure of the data type
* to be decoded. If this pointer is 0, then the type routines should
* allocate dynamic storage of the appropriate size and return it.
*/
#ifdef _KERNEL
typedef bool_t (*xdrproc_t)(XDR *, void *, ...);
#else
/*
* XXX can't actually prototype it, because some take three args!!!
*/
typedef bool_t (*xdrproc_t)(XDR *, ...);
#endif
/*
* Operations defined on a XDR handle
*
* XDR *xdrs;
* long *longp;
* char * addr;
* u_int len;
* u_int pos;
*/
#define XDR_GETLONG(xdrs, longp) \
(*(xdrs)->x_ops->x_getlong)(xdrs, longp)
#define xdr_getlong(xdrs, longp) \
(*(xdrs)->x_ops->x_getlong)(xdrs, longp)
#define XDR_PUTLONG(xdrs, longp) \
(*(xdrs)->x_ops->x_putlong)(xdrs, longp)
#define xdr_putlong(xdrs, longp) \
(*(xdrs)->x_ops->x_putlong)(xdrs, longp)
static __inline int
xdr_getint32(XDR *xdrs, int32_t *ip)
{
long l;
if (!xdr_getlong(xdrs, &l))
return (FALSE);
*ip = (int32_t)l;
return (TRUE);
}
static __inline int
xdr_putint32(XDR *xdrs, int32_t *ip)
{
long l;
l = (long)*ip;
return xdr_putlong(xdrs, &l);
}
#define XDR_GETINT32(xdrs, int32p) xdr_getint32(xdrs, int32p)
#define XDR_PUTINT32(xdrs, int32p) xdr_putint32(xdrs, int32p)
#define XDR_GETBYTES(xdrs, addr, len) \
(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
#define xdr_getbytes(xdrs, addr, len) \
(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
#define XDR_PUTBYTES(xdrs, addr, len) \
(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
#define xdr_putbytes(xdrs, addr, len) \
(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
#define XDR_GETPOS(xdrs) \
(*(xdrs)->x_ops->x_getpostn)(xdrs)
#define xdr_getpos(xdrs) \
(*(xdrs)->x_ops->x_getpostn)(xdrs)
#define XDR_SETPOS(xdrs, pos) \
(*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
#define xdr_setpos(xdrs, pos) \
(*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
#define XDR_INLINE(xdrs, len) \
(*(xdrs)->x_ops->x_inline)(xdrs, len)
#define xdr_inline(xdrs, len) \
(*(xdrs)->x_ops->x_inline)(xdrs, len)
#define XDR_DESTROY(xdrs) \
if ((xdrs)->x_ops->x_destroy) \
(*(xdrs)->x_ops->x_destroy)(xdrs)
#define xdr_destroy(xdrs) \
if ((xdrs)->x_ops->x_destroy) \
(*(xdrs)->x_ops->x_destroy)(xdrs)
#define XDR_CONTROL(xdrs, req, op) \
(((xdrs)->x_ops->x_control == NULL) ? (FALSE) : \
(*(xdrs)->x_ops->x_control)(xdrs, req, op))
#define xdr_control(xdrs, req, op) XDR_CONTROL(xdrs, req, op)
/*
* Solaris strips the '_t' from these types -- not sure why.
* But, let's be compatible.
*/
#define xdr_rpcvers(xdrs, versp) xdr_uint32_t(xdrs, versp)
#define xdr_rpcprog(xdrs, progp) xdr_uint32_t(xdrs, progp)
#define xdr_rpcproc(xdrs, procp) xdr_uint32_t(xdrs, procp)
#define xdr_rpcprot(xdrs, protp) xdr_uint32_t(xdrs, protp)
#define xdr_rpcport(xdrs, portp) xdr_uint32_t(xdrs, portp)
/*
* Support struct for discriminated unions.
* You create an array of xdrdiscrim structures, terminated with
* an entry with a null procedure pointer. The xdr_union routine gets
* the discriminant value and then searches the array of structures
* for a matching value. If a match is found the associated xdr routine
* is called to handle that part of the union. If there is
* no match, then a default routine may be called.
* If there is no match and no default routine it is an error.
*/
#define NULL_xdrproc_t ((xdrproc_t)0)
struct xdr_discrim {
int value;
xdrproc_t proc;
};
/*
* In-line routines for fast encode/decode of primitive data types.
* Caveat emptor: these use single memory cycles to get the
* data from the underlying buffer, and will fail to operate
* properly if the data is not aligned. The standard way to use these
* is to say:
* if ((buf = XDR_INLINE(xdrs, count)) == NULL)
* return (FALSE);
* <<< macro calls >>>
* where ``count'' is the number of bytes of data occupied
* by the primitive data types.
*
* N.B. and frozen for all time: each data type here uses 4 bytes
* of external representation.
*/
#define IXDR_GET_INT32(buf) ((int32_t)__ntohl((uint32_t)*(buf)++))
#define IXDR_PUT_INT32(buf, v) (*(buf)++ =(int32_t)__htonl((uint32_t)v))
#define IXDR_GET_U_INT32(buf) ((uint32_t)IXDR_GET_INT32(buf))
#define IXDR_PUT_U_INT32(buf, v) IXDR_PUT_INT32((buf), ((int32_t)(v)))
#define IXDR_GET_UINT32(buf) ((uint32_t)IXDR_GET_INT32(buf))
#define IXDR_PUT_UINT32(buf, v) IXDR_PUT_INT32((buf), ((int32_t)(v)))
#define IXDR_GET_LONG(buf) ((long)__ntohl((uint32_t)*(buf)++))
#define IXDR_PUT_LONG(buf, v) (*(buf)++ =(int32_t)__htonl((uint32_t)v))
#define IXDR_GET_BOOL(buf) ((bool_t)IXDR_GET_LONG(buf))
#define IXDR_GET_ENUM(buf, t) ((t)IXDR_GET_LONG(buf))
#define IXDR_GET_U_LONG(buf) ((u_long)IXDR_GET_LONG(buf))
#define IXDR_GET_SHORT(buf) ((short)IXDR_GET_LONG(buf))
#define IXDR_GET_U_SHORT(buf) ((u_short)IXDR_GET_LONG(buf))
#define IXDR_PUT_BOOL(buf, v) IXDR_PUT_LONG((buf), (v))
#define IXDR_PUT_ENUM(buf, v) IXDR_PUT_LONG((buf), (v))
#define IXDR_PUT_U_LONG(buf, v) IXDR_PUT_LONG((buf), (v))
#define IXDR_PUT_SHORT(buf, v) IXDR_PUT_LONG((buf), (v))
#define IXDR_PUT_U_SHORT(buf, v) IXDR_PUT_LONG((buf), (v))
/*
* These are the "generic" xdr routines.
*/
__BEGIN_DECLS
extern bool_t xdr_void(void);
extern bool_t xdr_int(XDR *, int *);
extern bool_t xdr_u_int(XDR *, u_int *);
extern bool_t xdr_long(XDR *, long *);
extern bool_t xdr_u_long(XDR *, u_long *);
extern bool_t xdr_short(XDR *, short *);
extern bool_t xdr_u_short(XDR *, u_short *);
extern bool_t xdr_int16_t(XDR *, int16_t *);
extern bool_t xdr_uint16_t(XDR *, uint16_t *);
extern bool_t xdr_int32_t(XDR *, int32_t *);
extern bool_t xdr_uint32_t(XDR *, uint32_t *);
extern bool_t xdr_int64_t(XDR *, int64_t *);
extern bool_t xdr_uint64_t(XDR *, uint64_t *);
extern bool_t xdr_bool(XDR *, bool_t *);
extern bool_t xdr_enum(XDR *, enum_t *);
extern bool_t xdr_array(XDR *, char **, u_int *, u_int, u_int, xdrproc_t);
extern bool_t xdr_bytes(XDR *, char **, u_int *, u_int);
extern bool_t xdr_opaque(XDR *, char *, u_int);
extern bool_t xdr_string(XDR *, char **, u_int);
extern bool_t xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t);
extern bool_t xdr_char(XDR *, char *);
extern bool_t xdr_u_char(XDR *, u_char *);
extern bool_t xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t);
extern bool_t xdr_float(XDR *, float *);
extern bool_t xdr_double(XDR *, double *);
extern bool_t xdr_quadruple(XDR *, long double *);
extern bool_t xdr_reference(XDR *, char **, u_int, xdrproc_t);
extern bool_t xdr_pointer(XDR *, char **, u_int, xdrproc_t);
extern bool_t xdr_wrapstring(XDR *, char **);
extern void xdr_free(xdrproc_t, void *);
extern bool_t xdr_hyper(XDR *, quad_t *);
extern bool_t xdr_u_hyper(XDR *, u_quad_t *);
extern bool_t xdr_longlong_t(XDR *, quad_t *);
extern bool_t xdr_u_longlong_t(XDR *, u_quad_t *);
extern unsigned long xdr_sizeof(xdrproc_t func, void *data);
__END_DECLS
/*
* Common opaque bytes objects used by many rpc protocols;
* declared here due to commonality.
*/
#define MAX_NETOBJ_SZ 1024
struct netobj {
u_int n_len;
char *n_bytes;
};
typedef struct netobj netobj;
extern bool_t xdr_netobj(XDR *, struct netobj *);
/*
* These are XDR control operators
*/
#define XDR_GET_BYTES_AVAIL 1
#define XDR_PEEK 2
#define XDR_SKIPBYTES 3
struct xdr_bytesrec {
bool_t xc_is_last_record;
size_t xc_num_avail;
};
typedef struct xdr_bytesrec xdr_bytesrec;
/*
* These are the public routines for the various implementations of
* xdr streams.
*/
__BEGIN_DECLS
/* XDR using memory buffers */
extern void xdrmem_create(XDR *, char *, u_int, enum xdr_op);
/* XDR using mbufs */
struct mbuf;
extern void xdrmbuf_create(XDR *, struct mbuf *, enum xdr_op);
extern void xdrmbuf_append(XDR *, struct mbuf *);
extern struct mbuf * xdrmbuf_getall(XDR *);
/* XDR pseudo records for tcp */
extern void xdrrec_create(XDR *, u_int, u_int, void *,
int (*)(void *, void *, int),
int (*)(void *, void *, int));
/* make end of xdr record */
extern bool_t xdrrec_endofrecord(XDR *, int);
/* move to beginning of next record */
extern bool_t xdrrec_skiprecord(XDR *);
/* true if no more input */
extern bool_t xdrrec_eof(XDR *);
extern u_int xdrrec_readbytes(XDR *, caddr_t, u_int);
__END_DECLS
#endif /* !_KRPC_XDR_H */

836
freebsd/sys/xdr/xdr.c Normal file
View File

@ -0,0 +1,836 @@
/* $NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $ */
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
static char *sccsid = "@(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* xdr.c, Generic XDR routines implementation.
*
* Copyright (C) 1986, Sun Microsystems, Inc.
*
* These are the "generic" xdr routines used to serialize and de-serialize
* most common data items. See xdr.h for more info on the interface to
* xdr.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
typedef quad_t longlong_t; /* ANSI long long type */
typedef u_quad_t u_longlong_t; /* ANSI unsigned long long type */
/*
* constants specific to the xdr "protocol"
*/
#define XDR_FALSE ((long) 0)
#define XDR_TRUE ((long) 1)
/*
* for unit alignment
*/
static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
/*
* Free a data structure using XDR
* Not a filter, but a convenient utility nonetheless
*/
void
xdr_free(xdrproc_t proc, void *objp)
{
XDR x;
x.x_op = XDR_FREE;
(*proc)(&x, objp);
}
/*
* XDR nothing
*/
bool_t
xdr_void(void)
{
return (TRUE);
}
/*
* XDR integers
*/
bool_t
xdr_int(XDR *xdrs, int *ip)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *ip;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*ip = (int) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned integers
*/
bool_t
xdr_u_int(XDR *xdrs, u_int *up)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *up;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*up = (u_int) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR long integers
* same as xdr_u_long - open coded to save a proc call!
*/
bool_t
xdr_long(XDR *xdrs, long *lp)
{
switch (xdrs->x_op) {
case XDR_ENCODE:
return (XDR_PUTLONG(xdrs, lp));
case XDR_DECODE:
return (XDR_GETLONG(xdrs, lp));
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned long integers
* same as xdr_long - open coded to save a proc call!
*/
bool_t
xdr_u_long(XDR *xdrs, u_long *ulp)
{
switch (xdrs->x_op) {
case XDR_ENCODE:
return (XDR_PUTLONG(xdrs, (long *)ulp));
case XDR_DECODE:
return (XDR_GETLONG(xdrs, (long *)ulp));
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR 32-bit integers
* same as xdr_uint32_t - open coded to save a proc call!
*/
bool_t
xdr_int32_t(XDR *xdrs, int32_t *int32_p)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *int32_p;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*int32_p = (int32_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 32-bit integers
* same as xdr_int32_t - open coded to save a proc call!
*/
bool_t
xdr_uint32_t(XDR *xdrs, uint32_t *uint32_p)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *uint32_p;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*uint32_p = (uint32_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR short integers
*/
bool_t
xdr_short(XDR *xdrs, short *sp)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *sp;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*sp = (short) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned short integers
*/
bool_t
xdr_u_short(XDR *xdrs, u_short *usp)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *usp;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*usp = (u_short) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR 16-bit integers
*/
bool_t
xdr_int16_t(XDR *xdrs, int16_t *int16_p)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *int16_p;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*int16_p = (int16_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 16-bit integers
*/
bool_t
xdr_uint16_t(XDR *xdrs, uint16_t *uint16_p)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *uint16_p;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*uint16_p = (uint16_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR a char
*/
bool_t
xdr_char(XDR *xdrs, char *cp)
{
int i;
i = (*cp);
if (!xdr_int(xdrs, &i)) {
return (FALSE);
}
*cp = i;
return (TRUE);
}
/*
* XDR an unsigned char
*/
bool_t
xdr_u_char(XDR *xdrs, u_char *cp)
{
u_int u;
u = (*cp);
if (!xdr_u_int(xdrs, &u)) {
return (FALSE);
}
*cp = u;
return (TRUE);
}
/*
* XDR booleans
*/
bool_t
xdr_bool(XDR *xdrs, bool_t *bp)
{
long lb;
switch (xdrs->x_op) {
case XDR_ENCODE:
lb = *bp ? XDR_TRUE : XDR_FALSE;
return (XDR_PUTLONG(xdrs, &lb));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &lb)) {
return (FALSE);
}
*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR enumerations
*/
bool_t
xdr_enum(XDR *xdrs, enum_t *ep)
{
enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
/*
* enums are treated as ints
*/
/* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
return (xdr_long(xdrs, (long *)(void *)ep));
} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
return (xdr_int(xdrs, (int *)(void *)ep));
} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
return (xdr_short(xdrs, (short *)(void *)ep));
} else {
return (FALSE);
}
}
/*
* XDR opaque data
* Allows the specification of a fixed size sequence of opaque bytes.
* cp points to the opaque object and cnt gives the byte length.
*/
bool_t
xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
{
u_int rndup;
static int crud[BYTES_PER_XDR_UNIT];
/*
* if no data we are done
*/
if (cnt == 0)
return (TRUE);
/*
* round byte count to full xdr units
*/
rndup = cnt % BYTES_PER_XDR_UNIT;
if (rndup > 0)
rndup = BYTES_PER_XDR_UNIT - rndup;
if (xdrs->x_op == XDR_DECODE) {
if (!XDR_GETBYTES(xdrs, cp, cnt)) {
return (FALSE);
}
if (rndup == 0)
return (TRUE);
return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
}
if (xdrs->x_op == XDR_ENCODE) {
if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
return (FALSE);
}
if (rndup == 0)
return (TRUE);
return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
}
if (xdrs->x_op == XDR_FREE) {
return (TRUE);
}
return (FALSE);
}
/*
* XDR counted bytes
* *cpp is a pointer to the bytes, *sizep is the count.
* If *cpp is NULL maxsize bytes are allocated
*/
bool_t
xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
{
char *sp = *cpp; /* sp is the actual string pointer */
u_int nodesize;
bool_t ret, allocated = FALSE;
/*
* first deal with the length since xdr bytes are counted
*/
if (! xdr_u_int(xdrs, sizep)) {
return (FALSE);
}
nodesize = *sizep;
if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
return (FALSE);
}
/*
* now deal with the actual bytes
*/
switch (xdrs->x_op) {
case XDR_DECODE:
if (nodesize == 0) {
return (TRUE);
}
if (sp == NULL) {
*cpp = sp = mem_alloc(nodesize);
allocated = TRUE;
}
if (sp == NULL) {
printf("xdr_bytes: out of memory");
return (FALSE);
}
/* FALLTHROUGH */
case XDR_ENCODE:
ret = xdr_opaque(xdrs, sp, nodesize);
if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
if (allocated == TRUE) {
mem_free(sp, nodesize);
*cpp = NULL;
}
}
return (ret);
case XDR_FREE:
if (sp != NULL) {
mem_free(sp, nodesize);
*cpp = NULL;
}
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* Implemented here due to commonality of the object.
*/
bool_t
xdr_netobj(XDR *xdrs, struct netobj *np)
{
return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
}
/*
* XDR a descriminated union
* Support routine for discriminated unions.
* You create an array of xdrdiscrim structures, terminated with
* an entry with a null procedure pointer. The routine gets
* the discriminant value and then searches the array of xdrdiscrims
* looking for that value. It calls the procedure given in the xdrdiscrim
* to handle the discriminant. If there is no specific routine a default
* routine may be called.
* If there is no specific or default routine an error is returned.
*/
bool_t
xdr_union(XDR *xdrs,
enum_t *dscmp, /* enum to decide which arm to work on */
char *unp, /* the union itself */
const struct xdr_discrim *choices, /* [value, xdr proc] for each arm */
xdrproc_t dfault) /* default xdr routine */
{
enum_t dscm;
/*
* we deal with the discriminator; it's an enum
*/
if (! xdr_enum(xdrs, dscmp)) {
return (FALSE);
}
dscm = *dscmp;
/*
* search choices for a value that matches the discriminator.
* if we find one, execute the xdr routine for that value.
*/
for (; choices->proc != NULL_xdrproc_t; choices++) {
if (choices->value == dscm)
return ((*(choices->proc))(xdrs, unp));
}
/*
* no match - execute the default xdr routine if there is one
*/
return ((dfault == NULL_xdrproc_t) ? FALSE :
(*dfault)(xdrs, unp));
}
/*
* Non-portable xdr primitives.
* Care should be taken when moving these routines to new architectures.
*/
/*
* XDR null terminated ASCII strings
* xdr_string deals with "C strings" - arrays of bytes that are
* terminated by a NULL character. The parameter cpp references a
* pointer to storage; If the pointer is null, then the necessary
* storage is allocated. The last parameter is the max allowed length
* of the string as specified by a protocol.
*/
bool_t
xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
{
char *sp = *cpp; /* sp is the actual string pointer */
u_int size;
u_int nodesize;
bool_t ret, allocated = FALSE;
/*
* first deal with the length since xdr strings are counted-strings
*/
switch (xdrs->x_op) {
case XDR_FREE:
if (sp == NULL) {
return(TRUE); /* already free */
}
/* FALLTHROUGH */
case XDR_ENCODE:
size = strlen(sp);
break;
case XDR_DECODE:
break;
}
if (! xdr_u_int(xdrs, &size)) {
return (FALSE);
}
if (size > maxsize) {
return (FALSE);
}
nodesize = size + 1;
/*
* now deal with the actual bytes
*/
switch (xdrs->x_op) {
case XDR_DECODE:
if (nodesize == 0) {
return (TRUE);
}
if (sp == NULL) {
*cpp = sp = mem_alloc(nodesize);
allocated = TRUE;
}
if (sp == NULL) {
printf("xdr_string: out of memory");
return (FALSE);
}
sp[size] = 0;
/* FALLTHROUGH */
case XDR_ENCODE:
ret = xdr_opaque(xdrs, sp, size);
if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
if (allocated == TRUE) {
mem_free(sp, nodesize);
*cpp = NULL;
}
}
return (ret);
case XDR_FREE:
mem_free(sp, nodesize);
*cpp = NULL;
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* Wrapper for xdr_string that can be called directly from
* routines like clnt_call
*/
bool_t
xdr_wrapstring(XDR *xdrs, char **cpp)
{
return xdr_string(xdrs, cpp, RPC_MAXDATASIZE);
}
/*
* NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
* are in the "non-portable" section because they require that a `long long'
* be a 64-bit type.
*
* --thorpej@netbsd.org, November 30, 1999
*/
/*
* XDR 64-bit integers
*/
bool_t
xdr_int64_t(XDR *xdrs, int64_t *llp)
{
u_long ul[2];
switch (xdrs->x_op) {
case XDR_ENCODE:
ul[0] = (u_long)((uint64_t)*llp >> 32) & 0xffffffff;
ul[1] = (u_long)((uint64_t)*llp) & 0xffffffff;
if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
case XDR_DECODE:
if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
return (FALSE);
*llp = (int64_t)
(((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 64-bit integers
*/
bool_t
xdr_uint64_t(XDR *xdrs, uint64_t *ullp)
{
u_long ul[2];
switch (xdrs->x_op) {
case XDR_ENCODE:
ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
ul[1] = (u_long)(*ullp) & 0xffffffff;
if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
case XDR_DECODE:
if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
return (FALSE);
*ullp = (uint64_t)
(((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR hypers
*/
bool_t
xdr_hyper(XDR *xdrs, longlong_t *llp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_int64_t().
*/
return (xdr_int64_t(xdrs, (int64_t *)llp));
}
/*
* XDR unsigned hypers
*/
bool_t
xdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_uint64_t().
*/
return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
}
/*
* XDR longlong_t's
*/
bool_t
xdr_longlong_t(XDR *xdrs, longlong_t *llp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_int64_t().
*/
return (xdr_int64_t(xdrs, (int64_t *)llp));
}
/*
* XDR u_longlong_t's
*/
bool_t
xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_uint64_t().
*/
return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
}

155
freebsd/sys/xdr/xdr_array.c Normal file
View File

@ -0,0 +1,155 @@
/* $NetBSD: xdr_array.c,v 1.12 2000/01/22 22:19:18 mycroft Exp $ */
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* xdr_array.c, Generic XDR routines impelmentation.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* These are the "non-trivial" xdr primitives used to serialize and de-serialize
* arrays. See xdr.h for more info on the interface to xdr.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/limits.h>
#include <sys/malloc.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
/*
* XDR an array of arbitrary elements
* *addrp is a pointer to the array, *sizep is the number of elements.
* If addrp is NULL (*sizep * elsize) bytes are allocated.
* elsize is the size (in bytes) of each element, and elproc is the
* xdr procedure to call to handle each element of the array.
*/
bool_t
xdr_array(XDR *xdrs,
caddr_t *addrp, /* array pointer */
u_int *sizep, /* number of elements */
u_int maxsize, /* max numberof elements */
u_int elsize, /* size in bytes of each element */
xdrproc_t elproc) /* xdr routine to handle each element */
{
u_int i;
caddr_t target = *addrp;
u_int c; /* the actual element count */
bool_t stat = TRUE;
u_int nodesize;
/* like strings, arrays are really counted arrays */
if (!xdr_u_int(xdrs, sizep)) {
return (FALSE);
}
c = *sizep;
if ((c > maxsize || UINT_MAX/elsize < c) &&
(xdrs->x_op != XDR_FREE)) {
return (FALSE);
}
nodesize = c * elsize;
/*
* if we are deserializing, we may need to allocate an array.
* We also save time by checking for a null array if we are freeing.
*/
if (target == NULL)
switch (xdrs->x_op) {
case XDR_DECODE:
if (c == 0)
return (TRUE);
*addrp = target = mem_alloc(nodesize);
if (target == NULL) {
printf("xdr_array: out of memory");
return (FALSE);
}
memset(target, 0, nodesize);
break;
case XDR_FREE:
return (TRUE);
case XDR_ENCODE:
break;
}
/*
* now we xdr each element of array
*/
for (i = 0; (i < c) && stat; i++) {
stat = (*elproc)(xdrs, target);
target += elsize;
}
/*
* the array may need freeing
*/
if (xdrs->x_op == XDR_FREE) {
mem_free(*addrp, nodesize);
*addrp = NULL;
}
return (stat);
}
/*
* xdr_vector():
*
* XDR a fixed length array. Unlike variable-length arrays,
* the storage of fixed length arrays is static and unfreeable.
* > basep: base of the array
* > size: size of the array
* > elemsize: size of each element
* > xdr_elem: routine to XDR each element
*/
bool_t
xdr_vector(XDR *xdrs, char *basep, u_int nelem, u_int elemsize,
xdrproc_t xdr_elem)
{
u_int i;
char *elptr;
elptr = basep;
for (i = 0; i < nelem; i++) {
if (!(*xdr_elem)(xdrs, elptr)) {
return(FALSE);
}
elptr += elemsize;
}
return(TRUE);
}

307
freebsd/sys/xdr/xdr_mbuf.c Normal file
View File

@ -0,0 +1,307 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
static void xdrmbuf_destroy(XDR *);
static bool_t xdrmbuf_getlong(XDR *, long *);
static bool_t xdrmbuf_putlong(XDR *, const long *);
static bool_t xdrmbuf_getbytes(XDR *, char *, u_int);
static bool_t xdrmbuf_putbytes(XDR *, const char *, u_int);
/* XXX: w/64-bit pointers, u_int not enough! */
static u_int xdrmbuf_getpos(XDR *);
static bool_t xdrmbuf_setpos(XDR *, u_int);
static int32_t *xdrmbuf_inline(XDR *, u_int);
static const struct xdr_ops xdrmbuf_ops = {
xdrmbuf_getlong,
xdrmbuf_putlong,
xdrmbuf_getbytes,
xdrmbuf_putbytes,
xdrmbuf_getpos,
xdrmbuf_setpos,
xdrmbuf_inline,
xdrmbuf_destroy
};
/*
* The procedure xdrmbuf_create initializes a stream descriptor for a
* mbuf.
*/
void
xdrmbuf_create(XDR *xdrs, struct mbuf *m, enum xdr_op op)
{
KASSERT(m != NULL, ("xdrmbuf_create with NULL mbuf chain"));
xdrs->x_op = op;
xdrs->x_ops = &xdrmbuf_ops;
xdrs->x_base = (char *) m;
if (op == XDR_ENCODE) {
m = m_last(m);
xdrs->x_private = m;
xdrs->x_handy = m->m_len;
} else {
xdrs->x_private = m;
xdrs->x_handy = 0;
}
}
void
xdrmbuf_append(XDR *xdrs, struct mbuf *madd)
{
struct mbuf *m;
KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_ENCODE,
("xdrmbuf_append: invalid XDR stream"));
if (m_length(madd, NULL) == 0) {
m_freem(madd);
return;
}
m = (struct mbuf *) xdrs->x_private;
m->m_next = madd;
m = m_last(madd);
xdrs->x_private = m;
xdrs->x_handy = m->m_len;
}
struct mbuf *
xdrmbuf_getall(XDR *xdrs)
{
struct mbuf *m0, *m;
KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_DECODE,
("xdrmbuf_append: invalid XDR stream"));
m0 = (struct mbuf *) xdrs->x_base;
m = (struct mbuf *) xdrs->x_private;
if (m0 != m) {
while (m0->m_next != m)
m0 = m0->m_next;
m0->m_next = NULL;
xdrs->x_private = NULL;
} else {
xdrs->x_base = NULL;
xdrs->x_private = NULL;
}
if (m)
m_adj(m, xdrs->x_handy);
else
m = m_get(M_WAITOK, MT_DATA);
return (m);
}
static void
xdrmbuf_destroy(XDR *xdrs)
{
if (xdrs->x_op == XDR_DECODE && xdrs->x_base) {
m_freem((struct mbuf *) xdrs->x_base);
xdrs->x_base = NULL;
xdrs->x_private = NULL;
}
}
static bool_t
xdrmbuf_getlong(XDR *xdrs, long *lp)
{
int32_t *p;
int32_t t;
p = xdrmbuf_inline(xdrs, sizeof(int32_t));
if (p) {
t = *p;
} else {
xdrmbuf_getbytes(xdrs, (char *) &t, sizeof(int32_t));
}
*lp = ntohl(t);
return (TRUE);
}
static bool_t
xdrmbuf_putlong(xdrs, lp)
XDR *xdrs;
const long *lp;
{
int32_t *p;
int32_t t = htonl(*lp);
p = xdrmbuf_inline(xdrs, sizeof(int32_t));
if (p) {
*p = t;
return (TRUE);
} else {
return (xdrmbuf_putbytes(xdrs, (char *) &t, sizeof(int32_t)));
}
}
static bool_t
xdrmbuf_getbytes(XDR *xdrs, char *addr, u_int len)
{
struct mbuf *m = (struct mbuf *) xdrs->x_private;
size_t sz;
while (len > 0) {
/*
* Make sure we haven't hit the end.
*/
if (!m) {
return (FALSE);
}
/*
* See how much we can get from this mbuf.
*/
sz = m->m_len - xdrs->x_handy;
if (sz > len)
sz = len;
bcopy(mtod(m, const char *) + xdrs->x_handy, addr, sz);
addr += sz;
xdrs->x_handy += sz;
len -= sz;
if (xdrs->x_handy == m->m_len) {
m = m->m_next;
xdrs->x_private = (void *) m;
xdrs->x_handy = 0;
}
}
return (TRUE);
}
static bool_t
xdrmbuf_putbytes(XDR *xdrs, const char *addr, u_int len)
{
struct mbuf *m = (struct mbuf *) xdrs->x_private;
struct mbuf *n;
size_t sz;
while (len > 0) {
sz = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy);
if (sz > len)
sz = len;
bcopy(addr, mtod(m, char *) + xdrs->x_handy, sz);
addr += sz;
xdrs->x_handy += sz;
if (xdrs->x_handy > m->m_len)
m->m_len = xdrs->x_handy;
len -= sz;
if (xdrs->x_handy == m->m_len && M_TRAILINGSPACE(m) == 0) {
if (!m->m_next) {
if (m->m_flags & M_EXT)
n = m_getcl(M_WAITOK, m->m_type, 0);
else
n = m_get(M_WAITOK, m->m_type);
m->m_next = n;
}
m = m->m_next;
xdrs->x_private = (void *) m;
xdrs->x_handy = 0;
}
}
return (TRUE);
}
static u_int
xdrmbuf_getpos(XDR *xdrs)
{
struct mbuf *m0 = (struct mbuf *) xdrs->x_base;
struct mbuf *m = (struct mbuf *) xdrs->x_private;
u_int pos = 0;
while (m0 && m0 != m) {
pos += m0->m_len;
m0 = m0->m_next;
}
KASSERT(m0, ("Corrupted mbuf chain"));
return (pos + xdrs->x_handy);
}
static bool_t
xdrmbuf_setpos(XDR *xdrs, u_int pos)
{
struct mbuf *m = (struct mbuf *) xdrs->x_base;
while (m && pos > m->m_len) {
pos -= m->m_len;
m = m->m_next;
}
KASSERT(m, ("Corrupted mbuf chain"));
xdrs->x_private = (void *) m;
xdrs->x_handy = pos;
return (TRUE);
}
static int32_t *
xdrmbuf_inline(XDR *xdrs, u_int len)
{
struct mbuf *m = (struct mbuf *) xdrs->x_private;
size_t available;
char *p;
if (!m)
return (0);
if (xdrs->x_op == XDR_ENCODE) {
available = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy);
} else {
available = m->m_len - xdrs->x_handy;
}
if (available >= len) {
p = mtod(m, char *) + xdrs->x_handy;
if (((uintptr_t) p) & (sizeof(int32_t) - 1))
return (0);
xdrs->x_handy += len;
if (xdrs->x_handy > m->m_len)
m->m_len = xdrs->x_handy;
return ((int32_t *) p);
}
return (0);
}

275
freebsd/sys/xdr/xdr_mem.c Normal file
View File

@ -0,0 +1,275 @@
/* $NetBSD: xdr_mem.c,v 1.15 2000/01/22 22:19:18 mycroft Exp $ */
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* xdr_mem.h, XDR implementation using memory buffers.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* If you have some data to be interpreted as external data representation
* or to be converted to external data representation in a memory buffer,
* then this is the package for you.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
static void xdrmem_destroy(XDR *);
static bool_t xdrmem_getlong_aligned(XDR *, long *);
static bool_t xdrmem_putlong_aligned(XDR *, const long *);
static bool_t xdrmem_getlong_unaligned(XDR *, long *);
static bool_t xdrmem_putlong_unaligned(XDR *, const long *);
static bool_t xdrmem_getbytes(XDR *, char *, u_int);
static bool_t xdrmem_putbytes(XDR *, const char *, u_int);
/* XXX: w/64-bit pointers, u_int not enough! */
static u_int xdrmem_getpos(XDR *);
static bool_t xdrmem_setpos(XDR *, u_int);
static int32_t *xdrmem_inline_aligned(XDR *, u_int);
static int32_t *xdrmem_inline_unaligned(XDR *, u_int);
static bool_t xdrmem_control(XDR *xdrs, int request, void *info);
static const struct xdr_ops xdrmem_ops_aligned = {
xdrmem_getlong_aligned,
xdrmem_putlong_aligned,
xdrmem_getbytes,
xdrmem_putbytes,
xdrmem_getpos,
xdrmem_setpos,
xdrmem_inline_aligned,
xdrmem_destroy,
xdrmem_control
};
static const struct xdr_ops xdrmem_ops_unaligned = {
xdrmem_getlong_unaligned,
xdrmem_putlong_unaligned,
xdrmem_getbytes,
xdrmem_putbytes,
xdrmem_getpos,
xdrmem_setpos,
xdrmem_inline_unaligned,
xdrmem_destroy,
xdrmem_control
};
/*
* The procedure xdrmem_create initializes a stream descriptor for a
* memory buffer.
*/
void
xdrmem_create(XDR *xdrs, char *addr, u_int size, enum xdr_op op)
{
xdrs->x_op = op;
xdrs->x_ops = ((unsigned long)addr & (sizeof(int32_t) - 1))
? &xdrmem_ops_unaligned : &xdrmem_ops_aligned;
xdrs->x_private = xdrs->x_base = addr;
xdrs->x_handy = size;
}
/*ARGSUSED*/
static void
xdrmem_destroy(XDR *xdrs)
{
}
static bool_t
xdrmem_getlong_aligned(XDR *xdrs, long *lp)
{
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
*lp = ntohl(*(u_int32_t *)xdrs->x_private);
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_putlong_aligned(XDR *xdrs, const long *lp)
{
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
*(u_int32_t *)xdrs->x_private = htonl((u_int32_t)*lp);
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_getlong_unaligned(XDR *xdrs, long *lp)
{
u_int32_t l;
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
memmove(&l, xdrs->x_private, sizeof(int32_t));
*lp = ntohl(l);
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_putlong_unaligned(XDR *xdrs, const long *lp)
{
u_int32_t l;
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
l = htonl((u_int32_t)*lp);
memmove(xdrs->x_private, &l, sizeof(int32_t));
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_getbytes(XDR *xdrs, char *addr, u_int len)
{
if (xdrs->x_handy < len)
return (FALSE);
xdrs->x_handy -= len;
memmove(addr, xdrs->x_private, len);
xdrs->x_private = (char *)xdrs->x_private + len;
return (TRUE);
}
static bool_t
xdrmem_putbytes(XDR *xdrs, const char *addr, u_int len)
{
if (xdrs->x_handy < len)
return (FALSE);
xdrs->x_handy -= len;
memmove(xdrs->x_private, addr, len);
xdrs->x_private = (char *)xdrs->x_private + len;
return (TRUE);
}
static u_int
xdrmem_getpos(XDR *xdrs)
{
/* XXX w/64-bit pointers, u_int not enough! */
return (u_int)((u_long)xdrs->x_private - (u_long)xdrs->x_base);
}
static bool_t
xdrmem_setpos(XDR *xdrs, u_int pos)
{
char *newaddr = xdrs->x_base + pos;
char *lastaddr = (char *)xdrs->x_private + xdrs->x_handy;
if (newaddr > lastaddr)
return (FALSE);
xdrs->x_private = newaddr;
xdrs->x_handy = (u_int)(lastaddr - newaddr); /* XXX sizeof(u_int) <? sizeof(ptrdiff_t) */
return (TRUE);
}
static int32_t *
xdrmem_inline_aligned(XDR *xdrs, u_int len)
{
int32_t *buf = NULL;
if (xdrs->x_handy >= len) {
xdrs->x_handy -= len;
buf = (int32_t *)xdrs->x_private;
xdrs->x_private = (char *)xdrs->x_private + len;
}
return (buf);
}
/* ARGSUSED */
static int32_t *
xdrmem_inline_unaligned(XDR *xdrs, u_int len)
{
return (0);
}
static bool_t
xdrmem_control(XDR *xdrs, int request, void *info)
{
xdr_bytesrec *xptr;
int32_t *l;
int len;
switch (request) {
case XDR_GET_BYTES_AVAIL:
xptr = (xdr_bytesrec *)info;
xptr->xc_is_last_record = TRUE;
xptr->xc_num_avail = xdrs->x_handy;
return (TRUE);
case XDR_PEEK:
/*
* Return the next 4 byte unit in the XDR stream.
*/
if (xdrs->x_handy < sizeof (int32_t))
return (FALSE);
l = (int32_t *)info;
*l = (int32_t)ntohl((uint32_t)
(*((int32_t *)(xdrs->x_private))));
return (TRUE);
case XDR_SKIPBYTES:
/*
* Skip the next N bytes in the XDR stream.
*/
l = (int32_t *)info;
len = RNDUP((int)(*l));
if (xdrs->x_handy < len)
return (FALSE);
xdrs->x_handy -= len;
xdrs->x_private = (char *)xdrs->x_private + len;
return (TRUE);
}
return (FALSE);
}

View File

@ -0,0 +1,135 @@
/* $NetBSD: xdr_reference.c,v 1.13 2000/01/22 22:19:18 mycroft Exp $ */
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
static char *sccsid = "@(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* xdr_reference.c, Generic XDR routines impelmentation.
*
* Copyright (C) 1987, Sun Microsystems, Inc.
*
* These are the "non-trivial" xdr primitives used to serialize and de-serialize
* "pointers". See xdr.h for more info on the interface to xdr.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
/*
* XDR an indirect pointer
* xdr_reference is for recursively translating a structure that is
* referenced by a pointer inside the structure that is currently being
* translated. pp references a pointer to storage. If *pp is null
* the necessary storage is allocated.
* size is the sizeof the referneced structure.
* proc is the routine to handle the referenced structure.
*/
bool_t
xdr_reference(XDR *xdrs,
caddr_t *pp, /* the pointer to work on */
u_int size, /* size of the object pointed to */
xdrproc_t proc) /* xdr routine to handle the object */
{
caddr_t loc = *pp;
bool_t stat;
if (loc == NULL)
switch (xdrs->x_op) {
case XDR_FREE:
return (TRUE);
case XDR_DECODE:
*pp = loc = (caddr_t) mem_alloc(size);
if (loc == NULL) {
printf("xdr_reference: out of memory");
return (FALSE);
}
memset(loc, 0, size);
break;
case XDR_ENCODE:
break;
}
stat = (*proc)(xdrs, loc);
if (xdrs->x_op == XDR_FREE) {
mem_free(loc, size);
*pp = NULL;
}
return (stat);
}
/*
* xdr_pointer():
*
* XDR a pointer to a possibly recursive data structure. This
* differs with xdr_reference in that it can serialize/deserialiaze
* trees correctly.
*
* What's sent is actually a union:
*
* union object_pointer switch (boolean b) {
* case TRUE: object_data data;
* case FALSE: void nothing;
* }
*
* > objpp: Pointer to the pointer to the object.
* > obj_size: size of the object.
* > xdr_obj: routine to XDR an object.
*
*/
bool_t
xdr_pointer(XDR *xdrs, char **objpp, u_int obj_size, xdrproc_t xdr_obj)
{
bool_t more_data;
more_data = (*objpp != NULL);
if (! xdr_bool(xdrs,&more_data)) {
return (FALSE);
}
if (! more_data) {
*objpp = NULL;
return (TRUE);
}
return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
}

View File

@ -0,0 +1,162 @@
/*
* Sun RPC is a product of Sun Microsystems, Inc. and is provided for
* unrestricted use provided that this legend is included on all tape
* media and as a part of the software program in whole or part. Users
* may copy or modify Sun RPC without charge, but are not authorized
* to license or distribute it to anyone else except as part of a product or
* program developed by the user.
*
* SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* Sun RPC is provided with no support and without any obligation on the
* part of Sun Microsystems, Inc. to assist in its use, correction,
* modification or enhancement.
*
* SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
* OR ANY PART THEREOF.
*
* In no event will Sun Microsystems, Inc. be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Sun has been advised of the possibility of such damages.
*
* Sun Microsystems, Inc.
* 2550 Garcia Avenue
* Mountain View, California 94043
*/
/*
* xdr_sizeof.c
*
* Copyright 1990 Sun Microsystems, Inc.
*
* General purpose routine to see how much space something will use
* when serialized using XDR.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
/* ARGSUSED */
static bool_t
x_putlong(XDR *xdrs, const long *longp)
{
xdrs->x_handy += BYTES_PER_XDR_UNIT;
return (TRUE);
}
/* ARGSUSED */
static bool_t
x_putbytes(XDR *xdrs, const char *bp, u_int len)
{
xdrs->x_handy += len;
return (TRUE);
}
static u_int
x_getpostn(XDR *xdrs)
{
return (xdrs->x_handy);
}
/* ARGSUSED */
static bool_t
x_setpostn(XDR *xdrs, u_int pos)
{
/* This is not allowed */
return (FALSE);
}
static int32_t *
x_inline(XDR *xdrs, u_int len)
{
if (len == 0) {
return (NULL);
}
if (xdrs->x_op != XDR_ENCODE) {
return (NULL);
}
if (len < (u_int)(uintptr_t)xdrs->x_base) {
/* x_private was already allocated */
xdrs->x_handy += len;
return ((int32_t *) xdrs->x_private);
} else {
/* Free the earlier space and allocate new area */
if (xdrs->x_private)
free(xdrs->x_private, M_RPC);
if ((xdrs->x_private = (caddr_t) malloc(len, M_RPC, M_WAITOK)) == NULL) {
xdrs->x_base = 0;
return (NULL);
}
xdrs->x_base = (caddr_t)(uintptr_t) len;
xdrs->x_handy += len;
return ((int32_t *) xdrs->x_private);
}
}
static int
harmless(void)
{
/* Always return FALSE/NULL, as the case may be */
return (0);
}
static void
x_destroy(XDR *xdrs)
{
xdrs->x_handy = 0;
xdrs->x_base = 0;
if (xdrs->x_private) {
free(xdrs->x_private, M_RPC);
xdrs->x_private = NULL;
}
return;
}
unsigned long
xdr_sizeof(xdrproc_t func, void *data)
{
XDR x;
struct xdr_ops ops;
bool_t stat;
/* to stop ANSI-C compiler from complaining */
typedef bool_t (* dummyfunc1)(XDR *, long *);
typedef bool_t (* dummyfunc2)(XDR *, caddr_t, u_int);
ops.x_putlong = x_putlong;
ops.x_putbytes = x_putbytes;
ops.x_inline = x_inline;
ops.x_getpostn = x_getpostn;
ops.x_setpostn = x_setpostn;
ops.x_destroy = x_destroy;
/* the other harmless ones */
ops.x_getlong = (dummyfunc1) harmless;
ops.x_getbytes = (dummyfunc2) harmless;
x.x_op = XDR_ENCODE;
x.x_ops = &ops;
x.x_handy = 0;
x.x_private = (caddr_t) NULL;
x.x_base = (caddr_t) 0;
stat = func(&x, data);
if (x.x_private)
free(x.x_private, M_RPC);
return (stat == TRUE ? (unsigned) x.x_handy: 0);
}