xref: /illumos-gate/usr/src/uts/common/rpc/rpcsec_gss.h (revision 0a701b1e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0a701b1eSRobert Gordon  * Common Development and Distribution License (the "License").
6*0a701b1eSRobert Gordon  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*0a701b1eSRobert Gordon  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * rpcsec_gss.h, RPCSEC_GSS security service interface.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #ifndef	_RPCSEC_GSS_H
357c478bd9Sstevel@tonic-gate #define	_RPCSEC_GSS_H
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
387c478bd9Sstevel@tonic-gate extern "C" {
397c478bd9Sstevel@tonic-gate #endif
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
427c478bd9Sstevel@tonic-gate #include <rpc/clnt.h>
437c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Interface definitions.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate #define	MAX_NAME_LEN			 64
497c478bd9Sstevel@tonic-gate #define	MAX_GSS_MECH			128
507c478bd9Sstevel@tonic-gate #define	MAX_GSS_NAME			128
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate typedef enum {
537c478bd9Sstevel@tonic-gate 	rpc_gss_svc_default = 0,
547c478bd9Sstevel@tonic-gate 	rpc_gss_svc_none = 1,
557c478bd9Sstevel@tonic-gate 	rpc_gss_svc_integrity = 2,
567c478bd9Sstevel@tonic-gate 	rpc_gss_svc_privacy = 3
577c478bd9Sstevel@tonic-gate } rpc_gss_service_t;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * GSS-API based security mechanism type specified as
617c478bd9Sstevel@tonic-gate  * object identifiers (OIDs).
627c478bd9Sstevel@tonic-gate  * This type is derived from gss_OID_desc/gss_OID.
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate #define	rpc_gss_OID_s	gss_OID_desc_struct
657c478bd9Sstevel@tonic-gate typedef struct rpc_gss_OID_s rpc_gss_OID_desc, *rpc_gss_OID;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * Interface data.
697c478bd9Sstevel@tonic-gate  * This is already suitable for both LP64 and ILP32.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate typedef struct rpc_gss_principal {
727c478bd9Sstevel@tonic-gate 	int	len;
737c478bd9Sstevel@tonic-gate 	char	name[1];
747c478bd9Sstevel@tonic-gate } *rpc_gss_principal_t;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate typedef struct {
777c478bd9Sstevel@tonic-gate 	int			req_flags;
787c478bd9Sstevel@tonic-gate 	int			time_req;
797c478bd9Sstevel@tonic-gate 	gss_cred_id_t		my_cred;
807c478bd9Sstevel@tonic-gate 	gss_channel_bindings_t	input_channel_bindings;
817c478bd9Sstevel@tonic-gate } rpc_gss_options_req_t;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate typedef struct {
847c478bd9Sstevel@tonic-gate 	int			major_status;
857c478bd9Sstevel@tonic-gate 	int			minor_status;
867c478bd9Sstevel@tonic-gate 	uint_t			rpcsec_version;
877c478bd9Sstevel@tonic-gate 	int			ret_flags;
887c478bd9Sstevel@tonic-gate 	int			time_ret;
897c478bd9Sstevel@tonic-gate 	gss_ctx_id_t		gss_context;
907c478bd9Sstevel@tonic-gate #ifdef _KERNEL
917c478bd9Sstevel@tonic-gate 	rpc_gss_OID		actual_mechanism;
927c478bd9Sstevel@tonic-gate #else
937c478bd9Sstevel@tonic-gate 	char			actual_mechanism[MAX_GSS_MECH];
947c478bd9Sstevel@tonic-gate #endif
957c478bd9Sstevel@tonic-gate } rpc_gss_options_ret_t;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * raw credentials
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate typedef struct {
1017c478bd9Sstevel@tonic-gate 	uint_t			version;
1027c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1037c478bd9Sstevel@tonic-gate 	rpc_gss_OID		mechanism;
1047c478bd9Sstevel@tonic-gate 	uint_t			qop;
1057c478bd9Sstevel@tonic-gate #else
1067c478bd9Sstevel@tonic-gate 	char			*mechanism;
1077c478bd9Sstevel@tonic-gate 	char			*qop;
1087c478bd9Sstevel@tonic-gate #endif
1097c478bd9Sstevel@tonic-gate 	rpc_gss_principal_t	client_principal;
1107c478bd9Sstevel@tonic-gate 	char	*svc_principal;	/* service@server, e.g. nfs@caribe */
1117c478bd9Sstevel@tonic-gate 	rpc_gss_service_t	service;
1127c478bd9Sstevel@tonic-gate } rpc_gss_rawcred_t;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * unix credentials
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate typedef struct {
1187c478bd9Sstevel@tonic-gate 	uid_t			uid;
1197c478bd9Sstevel@tonic-gate 	gid_t			gid;
1207c478bd9Sstevel@tonic-gate 	short			gidlen;
1217c478bd9Sstevel@tonic-gate 	gid_t			*gidlist;
1227c478bd9Sstevel@tonic-gate } rpc_gss_ucred_t;
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate /*
1257c478bd9Sstevel@tonic-gate  * for callback routine
1267c478bd9Sstevel@tonic-gate  */
1277c478bd9Sstevel@tonic-gate typedef struct {
1287c478bd9Sstevel@tonic-gate 	uint_t			program;
1297c478bd9Sstevel@tonic-gate 	uint_t			version;
1307c478bd9Sstevel@tonic-gate 	bool_t			(*callback)();
1317c478bd9Sstevel@tonic-gate } rpc_gss_callback_t;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate  * lock used for the callback routine
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate typedef struct {
1377c478bd9Sstevel@tonic-gate 	bool_t			locked;
1387c478bd9Sstevel@tonic-gate 	rpc_gss_rawcred_t	*raw_cred;
1397c478bd9Sstevel@tonic-gate } rpc_gss_lock_t;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate  * This is for user RPC applications.
1447c478bd9Sstevel@tonic-gate  * Structure used to fetch the error code when one of
1457c478bd9Sstevel@tonic-gate  * the rpc_gss_* routines fails.
1467c478bd9Sstevel@tonic-gate  */
1477c478bd9Sstevel@tonic-gate typedef struct {
1487c478bd9Sstevel@tonic-gate 	int	rpc_gss_error;
1497c478bd9Sstevel@tonic-gate 	int	system_error;
1507c478bd9Sstevel@tonic-gate } rpc_gss_error_t;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate #define	RPC_GSS_ER_SUCCESS	0	/* no error */
1537c478bd9Sstevel@tonic-gate #define	RPC_GSS_ER_SYSTEMERROR	1	/* system error */
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32
1577c478bd9Sstevel@tonic-gate struct gss_clnt_data32 {
1587c478bd9Sstevel@tonic-gate 	gss_OID_desc32	mechanism;
1597c478bd9Sstevel@tonic-gate 	rpc_gss_service_t	service;
1607c478bd9Sstevel@tonic-gate 	char		uname[MAX_NAME_LEN];	/* server's service name */
1617c478bd9Sstevel@tonic-gate 	char		inst[MAX_NAME_LEN];	/* server's instance name */
1627c478bd9Sstevel@tonic-gate 	char		realm[MAX_NAME_LEN];	/* server's realm */
1637c478bd9Sstevel@tonic-gate 	uint_t		qop;
1647c478bd9Sstevel@tonic-gate };
1657c478bd9Sstevel@tonic-gate #endif
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * This is for Kernel RPC applications.
1697c478bd9Sstevel@tonic-gate  * RPCSEC_GSS flavor specific data in sec_data opaque field.
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate typedef struct gss_clnt_data {
1727c478bd9Sstevel@tonic-gate 	rpc_gss_OID_desc	mechanism;
1737c478bd9Sstevel@tonic-gate 	rpc_gss_service_t	service;
1747c478bd9Sstevel@tonic-gate 	char		uname[MAX_NAME_LEN];	/* server's service name */
1757c478bd9Sstevel@tonic-gate 	char		inst[MAX_NAME_LEN];	/* server's instance name */
1767c478bd9Sstevel@tonic-gate 	char		realm[MAX_NAME_LEN];	/* server's realm */
1777c478bd9Sstevel@tonic-gate 	uint_t		qop;
1787c478bd9Sstevel@tonic-gate } gss_clntdata_t;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate struct svc_req;
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate  *  KERNEL rpc_gss_* interfaces.
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate #ifdef _KERNEL
1867c478bd9Sstevel@tonic-gate int rpc_gss_secget(CLIENT *, char *, rpc_gss_OID,
1877c478bd9Sstevel@tonic-gate 			rpc_gss_service_t, uint_t, rpc_gss_options_req_t *,
1887c478bd9Sstevel@tonic-gate 			rpc_gss_options_ret_t *, void *, cred_t *, AUTH **);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate void rpc_gss_secfree(AUTH *);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate int rpc_gss_seccreate(CLIENT *, char *, rpc_gss_OID,
1937c478bd9Sstevel@tonic-gate 			rpc_gss_service_t, uint_t, rpc_gss_options_req_t *,
1947c478bd9Sstevel@tonic-gate 			rpc_gss_options_ret_t *, cred_t *, AUTH **);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate int rpc_gss_revauth(uid_t, rpc_gss_OID);
1977c478bd9Sstevel@tonic-gate void rpc_gss_secpurge(void *);
1987c478bd9Sstevel@tonic-gate enum auth_stat __svcrpcsec_gss(struct svc_req *,
1997c478bd9Sstevel@tonic-gate 			struct rpc_msg *, bool_t *);
2007c478bd9Sstevel@tonic-gate bool_t rpc_gss_set_defaults(AUTH *, rpc_gss_service_t, uint_t);
201*0a701b1eSRobert Gordon rpc_gss_service_t rpc_gss_get_service_type(AUTH *);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate #else
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate  *  USER rpc_gss_* public interfaces
2077c478bd9Sstevel@tonic-gate  */
2087c478bd9Sstevel@tonic-gate AUTH *
2097c478bd9Sstevel@tonic-gate rpc_gss_seccreate(
2107c478bd9Sstevel@tonic-gate 	CLIENT			*clnt,		/* associated client handle */
2117c478bd9Sstevel@tonic-gate 	char			*principal,	/* server service principal */
2127c478bd9Sstevel@tonic-gate 	char			*mechanism,	/* security mechanism */
2137c478bd9Sstevel@tonic-gate 	rpc_gss_service_t	service_type,	/* security service */
2147c478bd9Sstevel@tonic-gate 	char			*qop,		/* requested QOP */
2157c478bd9Sstevel@tonic-gate 	rpc_gss_options_req_t	*options_req,	/* requested options */
2167c478bd9Sstevel@tonic-gate 	rpc_gss_options_ret_t   *options_ret    /* returned options */
2177c478bd9Sstevel@tonic-gate );
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate bool_t
2207c478bd9Sstevel@tonic-gate rpc_gss_get_principal_name(
2217c478bd9Sstevel@tonic-gate 	rpc_gss_principal_t	*principal,
2227c478bd9Sstevel@tonic-gate 	char			*mechanism,
2237c478bd9Sstevel@tonic-gate 	char			*user_name,
2247c478bd9Sstevel@tonic-gate 	char			*node,
2257c478bd9Sstevel@tonic-gate 	char			*secdomain
2267c478bd9Sstevel@tonic-gate );
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate char **rpc_gss_get_mechanisms();
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate char **rpc_gss_get_mech_info(
2317c478bd9Sstevel@tonic-gate 	char			*mechanism,
2327c478bd9Sstevel@tonic-gate 	rpc_gss_service_t	*service
2337c478bd9Sstevel@tonic-gate );
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate bool_t
2367c478bd9Sstevel@tonic-gate rpc_gss_is_installed(
2377c478bd9Sstevel@tonic-gate 	char	*mechanism
2387c478bd9Sstevel@tonic-gate );
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate bool_t
2417c478bd9Sstevel@tonic-gate rpc_gss_mech_to_oid(
2427c478bd9Sstevel@tonic-gate 	char		*mech,
2437c478bd9Sstevel@tonic-gate 	rpc_gss_OID	*oid
2447c478bd9Sstevel@tonic-gate );
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate bool_t
2477c478bd9Sstevel@tonic-gate rpc_gss_qop_to_num(
2487c478bd9Sstevel@tonic-gate 	char	*qop,
2497c478bd9Sstevel@tonic-gate 	char	*mech,
2507c478bd9Sstevel@tonic-gate 	uint_t	*num
2517c478bd9Sstevel@tonic-gate );
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate bool_t
2547c478bd9Sstevel@tonic-gate rpc_gss_set_svc_name(
2557c478bd9Sstevel@tonic-gate 	char			*principal,
2567c478bd9Sstevel@tonic-gate 	char			*mechanism,
2577c478bd9Sstevel@tonic-gate 	uint_t			req_time,
2587c478bd9Sstevel@tonic-gate 	uint_t			program,
2597c478bd9Sstevel@tonic-gate 	uint_t			version
2607c478bd9Sstevel@tonic-gate );
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate bool_t
2637c478bd9Sstevel@tonic-gate rpc_gss_set_defaults(
2647c478bd9Sstevel@tonic-gate 	AUTH			*auth,
2657c478bd9Sstevel@tonic-gate 	rpc_gss_service_t	service,
2667c478bd9Sstevel@tonic-gate 	char			*qop
2677c478bd9Sstevel@tonic-gate );
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate void
2707c478bd9Sstevel@tonic-gate rpc_gss_get_error(
2717c478bd9Sstevel@tonic-gate 	rpc_gss_error_t		*error
2727c478bd9Sstevel@tonic-gate );
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * User level private interfaces
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate enum auth_stat __svcrpcsec_gss();
2787c478bd9Sstevel@tonic-gate bool_t	__rpc_gss_wrap();
2797c478bd9Sstevel@tonic-gate bool_t	__rpc_gss_unwrap();
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate #endif
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
2847c478bd9Sstevel@tonic-gate  *  USER and KERNEL rpc_gss_* interfaces.
2857c478bd9Sstevel@tonic-gate  */
2867c478bd9Sstevel@tonic-gate bool_t
2877c478bd9Sstevel@tonic-gate rpc_gss_set_callback(
2887c478bd9Sstevel@tonic-gate 	rpc_gss_callback_t	*cb
2897c478bd9Sstevel@tonic-gate );
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate bool_t
2927c478bd9Sstevel@tonic-gate rpc_gss_getcred(
2937c478bd9Sstevel@tonic-gate 	struct svc_req		*req,
2947c478bd9Sstevel@tonic-gate 	rpc_gss_rawcred_t	**rcred,
2957c478bd9Sstevel@tonic-gate 	rpc_gss_ucred_t		**ucred,
2967c478bd9Sstevel@tonic-gate 	void			**cookie
2977c478bd9Sstevel@tonic-gate );
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate int
3007c478bd9Sstevel@tonic-gate rpc_gss_max_data_length(
3017c478bd9Sstevel@tonic-gate 	AUTH			*rpcgss_handle,
3027c478bd9Sstevel@tonic-gate 	int			max_tp_unit_len
3037c478bd9Sstevel@tonic-gate );
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate int
3067c478bd9Sstevel@tonic-gate rpc_gss_svc_max_data_length(
3077c478bd9Sstevel@tonic-gate 	struct	svc_req		*req,
3087c478bd9Sstevel@tonic-gate 	int			max_tp_unit_len
3097c478bd9Sstevel@tonic-gate );
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate bool_t
3127c478bd9Sstevel@tonic-gate rpc_gss_get_versions(
3137c478bd9Sstevel@tonic-gate 	uint_t	*vers_hi,
3147c478bd9Sstevel@tonic-gate 	uint_t	*vers_lo
3157c478bd9Sstevel@tonic-gate );
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate #define	RPCSEC_GSS_REFRESH_ATTEMPTS 	20
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate /*
3207c478bd9Sstevel@tonic-gate  * Protocol data.
3217c478bd9Sstevel@tonic-gate  *
3227c478bd9Sstevel@tonic-gate  * The reason to put these definition in this header file
3237c478bd9Sstevel@tonic-gate  * is for 2.6 snoop to handle the RPCSEC_GSS protocol
3247c478bd9Sstevel@tonic-gate  * interpretation.
3257c478bd9Sstevel@tonic-gate  */
3267c478bd9Sstevel@tonic-gate #define	RPCSEC_GSS_DATA			0
3277c478bd9Sstevel@tonic-gate #define	RPCSEC_GSS_INIT			1
3287c478bd9Sstevel@tonic-gate #define	RPCSEC_GSS_CONTINUE_INIT	2
3297c478bd9Sstevel@tonic-gate #define	RPCSEC_GSS_DESTROY		3
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate #define	RPCSEC_GSS_VERSION		1
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate #endif
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate #endif	/* !_RPCSEC_GSS_H */
338