1    	/*
2    	 * vim:noexpandtab:shiftwidth=8:tabstop=8:
3    	 *
4    	 * Copyright CEA/DAM/DIF  (2008)
5    	 * contributeur : Philippe DENIEL   philippe.deniel@cea.fr
6    	 *                Thomas LEIBOVICI  thomas.leibovici@cea.fr
7    	 *
8    	 *
9    	 * This program is free software; you can redistribute it and/or
10   	 * modify it under the terms of the GNU Lesser General Public License
11   	 * as published by the Free Software Foundation; either version 3 of
12   	 * the License, or (at your option) any later version.
13   	 *
14   	 * This program is distributed in the hope that it will be useful, but
15   	 * WITHOUT ANY WARRANTY; without even the implied warranty of
16   	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   	 * Lesser General Public License for more details.
18   	 *
19   	 * You should have received a copy of the GNU Lesser General Public
20   	 * License along with this library; if not, write to the Free Software
21   	 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22   	 * 02110-1301 USA
23   	 *
24   	 * ---------------------------------------
25   	 */
26   	
27   	/**
28   	 * @file nfs4_op_secinfo_no_name.c
29   	 * @brief Routines used for managing the NFS4 COMPOUND functions.
30   	 *
31   	 * Routines used for managing the NFS4 COMPOUND functions.
32   	 */
33   	#include "config.h"
34   	#include "fsal.h"
35   	#include "nfs_core.h"
36   	#include "nfs_exports.h"
37   	#include "nfs_proto_functions.h"
38   	#include "nfs_proto_tools.h"
39   	#include "sal_functions.h"
40   	#include "export_mgr.h"
41   	
42   	#ifdef _HAVE_GSSAPI
43   	/* flavor, oid len, qop, service */
44   	#define GSS_RESP_SIZE (4 * BYTES_PER_XDR_UNIT)
45   	#endif
46   	/* nfsstat4, resok_len, 2 flavors
47   	 * NOTE this requires space for up to 2 extra xdr units if the export doesn't
48   	 * allow AUTH_NONE and/or AUTH_UNIX. The response size is overall so small
49   	 * this op should never be the cause of overflow of maxrespsize...
50   	 */
51   	#define RESP_SIZE (4 * BYTES_PER_XDR_UNIT)
52   	
53   	/**
54   	 * @brief NFSv4 SECINFO_NO_NAME operation
55   	 *
56   	 * This function impelments the NFSv4 SECINFO_NO_NAME operation.
57   	 *
58   	 * @param[in]     op   Operation reqest
59   	 * @param[in,out] data Compound data
60   	 * @param[out]    resp Response
61   	 *
62   	 * @return NFS status codes.
63   	 */
64   	
65   	enum nfs_req_result nfs4_op_secinfo_no_name(struct nfs_argop4 *op,
66   						    compound_data_t *data,
67   						    struct nfs_resop4 *resp)
68   	{
69   		SECINFO_NO_NAME4res * const res_SECINFO_NO_NAME4 =
70   		    &resp->nfs_resop4_u.opsecinfo_no_name;
71   		secinfo4 *resok_val;
72   	#ifdef _HAVE_GSSAPI
73   		sec_oid4 v5oid = { krb5oid.length, (char *)krb5oid.elements };
74   	#endif /* _HAVE_GSSAPI */
75   		int num_entry = 0;
76   		uint32_t resp_size = RESP_SIZE;
77   	
78   		res_SECINFO_NO_NAME4->status = NFS4_OK;
79   	
80   		/* Do basic checks on a filehandle */
81   		res_SECINFO_NO_NAME4->status =
82   		    nfs4_sanity_check_FH(data, NO_FILE_TYPE, false);
83   	
84   		if (res_SECINFO_NO_NAME4->status != NFS4_OK)
(1) Event branch_past_initialization: transfer of control bypasses initialization of:
(2) Event caretline: ^
(3) Event name_at_decl_position: variable "idx" (declared at line 141)
85   			goto out;
86   	
87   		if (op->nfs_argop4_u.opsecinfo_no_name == SECINFO_STYLE4_PARENT) {
88   			/* Use LOOKUPP to get the parent into CurrentFH. Note that all
89   			 * ops have status in the same location, so if there is an error
90   			 * we just need to set the resop and return the result.
91   			 */
92   			enum nfs_req_result result = nfs4_op_lookupp(op, data, resp);
93   	
94   			if (result != NFS_REQ_OK) {
95   				resp->resop = NFS4_OP_SECINFO_NO_NAME;
96   				return result;
97   			}
98   		}
99   	
100  		/* Get the number of entries */
101  	#ifdef _HAVE_GSSAPI
102  		if (op_ctx->export_perms->options &
103  		    EXPORT_OPTION_RPCSEC_GSS_NONE)
104  			num_entry++;
105  	
106  		if (op_ctx->export_perms->options &
107  		    EXPORT_OPTION_RPCSEC_GSS_INTG)
108  			num_entry++;
109  	
110  		if (op_ctx->export_perms->options &
111  		    EXPORT_OPTION_RPCSEC_GSS_PRIV)
112  			num_entry++;
113  	
114  		resp_size += (RNDUP(krb5oid.length) + GSS_RESP_SIZE) * num_entry;
115  	#endif
116  	
117  		if (op_ctx->export_perms->options & EXPORT_OPTION_AUTH_NONE)
118  			num_entry++;
119  	
120  		if (op_ctx->export_perms->options & EXPORT_OPTION_AUTH_UNIX)
121  			num_entry++;
122  	
123  		/* Check for space in response. */
124  		res_SECINFO_NO_NAME4->status = check_resp_room(data, resp_size);
125  	
126  		if (res_SECINFO_NO_NAME4->status != NFS4_OK)
127  			goto out;
128  	
129  		data->op_resp_size = resp_size;
130  	
131  		resok_val = gsh_calloc(num_entry, sizeof(secinfo4));
132  	
133  		res_SECINFO_NO_NAME4->SECINFO4res_u.resok4.SECINFO4resok_val
134  			= resok_val;
135  	
136  		/**
137  		 * @todo We give here the order in which the client should try
138  		 * different authentifications. Might want to give it in the
139  		 * order given in the config.
140  		 */
141  		int idx = 0;
142  	
143  	#ifdef _HAVE_GSSAPI
144  		if (op_ctx->export_perms->options &
145  		    EXPORT_OPTION_RPCSEC_GSS_PRIV) {
146  			resok_val[idx].flavor = RPCSEC_GSS;
147  			resok_val[idx].secinfo4_u.flavor_info.service =
148  				RPCSEC_GSS_SVC_PRIVACY;
149  			resok_val[idx].secinfo4_u.flavor_info.qop = GSS_C_QOP_DEFAULT;
150  			resok_val[idx++].secinfo4_u.flavor_info.oid = v5oid;
151  		}
152  	
153  		if (op_ctx->export_perms->options &
154  		    EXPORT_OPTION_RPCSEC_GSS_INTG) {
155  			resok_val[idx].flavor = RPCSEC_GSS;
156  			resok_val[idx].secinfo4_u.flavor_info.service =
157  				RPCSEC_GSS_SVC_INTEGRITY;
158  			resok_val[idx].secinfo4_u.flavor_info.qop = GSS_C_QOP_DEFAULT;
159  			resok_val[idx++].secinfo4_u.flavor_info.oid = v5oid;
160  		}
161  	
162  		if (op_ctx->export_perms->options &
163  		    EXPORT_OPTION_RPCSEC_GSS_NONE) {
164  			resok_val[idx].flavor = RPCSEC_GSS;
165  			resok_val[idx].secinfo4_u.flavor_info.service =
166  				RPCSEC_GSS_SVC_NONE;
167  			resok_val[idx].secinfo4_u.flavor_info.qop = GSS_C_QOP_DEFAULT;
168  			resok_val[idx++].secinfo4_u.flavor_info.oid = v5oid;
169  		}
170  	#endif /* _HAVE_GSSAPI */
171  	
172  		if (op_ctx->export_perms->options & EXPORT_OPTION_AUTH_UNIX)
173  			resok_val[idx++].flavor = AUTH_UNIX;
174  	
175  		if (op_ctx->export_perms->options & EXPORT_OPTION_AUTH_NONE)
176  			resok_val[idx++].flavor = AUTH_NONE;
177  	
178  		res_SECINFO_NO_NAME4->SECINFO4res_u.resok4.SECINFO4resok_len = idx;
179  	
180  		/* Need to clear out CurrentFH */
181  		set_current_entry(data, NULL);
182  	
183  		data->currentFH.nfs_fh4_len = 0;
184  	
185  		/* Release CurrentFH reference to export. */
186  		if (op_ctx->ctx_export) {
187  			put_gsh_export(op_ctx->ctx_export);
188  			op_ctx->ctx_export = NULL;
189  			op_ctx->fsal_export = NULL;
190  		}
191  	
192  		res_SECINFO_NO_NAME4->status = NFS4_OK;
193  	
194  	 out:
195  	
196  		resp->resop = NFS4_OP_SECINFO_NO_NAME;
197  	
198  		return nfsstat4_to_nfs_req_result(res_SECINFO_NO_NAME4->status);
199  	}				/* nfs4_op_secinfo_no_name */
200  	
201  	/**
202  	 * @brief Free memory allocated for SECINFO_NO_NAME result
203  	 *
204  	 * This function frees any memory allocated for the result of the
205  	 * NFS4_OP_SECINFO_NO_NAME operation.
206  	 *
207  	 * @param[in,out] resp nfs4_op results
208  	 */
209  	void nfs4_op_secinfo_no_name_Free(nfs_resop4 *res)
210  	{
211  		SECINFO_NO_NAME4res *resp = &res->nfs_resop4_u.opsecinfo_no_name;
212  	
213  		if ((resp->status == NFS4_OK)
214  		    && (resp->SECINFO4res_u.resok4.SECINFO4resok_val)) {
215  			gsh_free(resp->SECINFO4res_u.resok4.SECINFO4resok_val);
216  			resp->SECINFO4res_u.resok4.SECINFO4resok_val = NULL;
217  		}
218  	}
219