3 * UNFS3 mount protocol procedures
4 * (C) 2004, Pascal Schmidt
5 * see file LICENSE for license details
10 #include <sys/types.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
30 #include "Config/exports.h"
35 # define PATH_MAX 4096
38 #define IS_SECURE(port) ((port) < 1024)
41 * number of active mounts
43 * only a guess since clients can crash and/or not sent UMNT calls
45 static int mount_cnt = 0;
47 /* list of currently mounted directories */
48 static mountlist mount_list = NULL;
50 static char nonce[32] = "";
53 * add entry to mount list
55 static void add_mount(const char *path, struct svc_req *rqstp)
61 new = malloc(sizeof(struct mountbody));
63 logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
67 host = inet_ntoa(get_remote(rqstp));
68 new->ml_hostname = malloc(strlen(host) + 1);
69 if (!new->ml_hostname) {
70 logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
75 new->ml_directory = malloc(strlen(path) + 1);
76 if (!new->ml_directory) {
77 logmsg(LOG_CRIT, "add_mount: Unable to allocate memory");
78 free(new->ml_hostname);
83 /* initialize the new entry */
85 strcpy(new->ml_hostname, host);
86 strcpy(new->ml_directory, path);
100 * remove entries from mount list
102 static void remove_mount(const char *path, struct svc_req *rqstp)
104 mountlist iter, next, prev = NULL;
107 host = inet_ntoa(get_remote(rqstp));
111 if (strcmp(iter->ml_hostname, host) == 0 &&
112 (!path || strcmp(iter->ml_directory, path) == 0)) {
114 prev->ml_next = iter->ml_next;
116 mount_list = iter->ml_next;
118 next = iter->ml_next;
120 free(iter->ml_hostname);
121 free(iter->ml_directory);
126 /* adjust mount count */
131 iter = iter->ml_next;
136 void *mountproc_null_3_svc(U(void *argp), U(struct svc_req *rqstp))
138 static void *result = NULL;
143 mountres3 *mountproc_mnt_3_svc(dirpath * argp, struct svc_req * rqstp)
146 static unfs3_fh_t fh;
147 static mountres3 result;
148 static int auth = AUTH_UNIX;
149 int authenticated = 0;
152 /* We need to modify the *argp pointer. Make a copy. */
155 /* error out if not version 3 */
156 if (rqstp->rq_vers != 3) {
158 "%s attempted mount with unsupported protocol version",
159 inet_ntoa(get_remote(rqstp)));
160 result.fhs_status = MNT3ERR_INVAL;
164 /* Check for "mount commands" */
165 if (strncmp(dpath, "@getnonce", sizeof("@getnonce") - 1) == 0) {
166 if (backend_gen_nonce(nonce) < 0) {
167 result.fhs_status = MNT3ERR_IO;
169 result.fhs_status = MNT3_OK;
170 result.mountres3_u.mountinfo.fhandle.fhandle3_len = 32;
171 result.mountres3_u.mountinfo.fhandle.fhandle3_val = nonce;
172 result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
173 result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val =
177 } else if (strncmp(dpath, "@password:", sizeof("@password:") - 1) == 0) {
178 char pw[PASSWORD_MAXLEN + 1];
180 mnt_cmd_argument(&dpath, "@password:", pw, PASSWORD_MAXLEN);
181 if (exports_options(dpath, rqstp, &password, NULL) != -1) {
182 authenticated = !strcmp(password, pw);
184 /* else leave authenticated unchanged */
185 } else if (strncmp(dpath, "@otp:", sizeof("@otp:") - 1) == 0) {
186 /* The otp from the client */
187 char otp[PASSWORD_MAXLEN + 1];
189 /* Our calculated otp */
192 mnt_cmd_argument(&dpath, "@otp:", otp, PASSWORD_MAXLEN);
193 if (exports_options(dpath, rqstp, &password, NULL) != -1) {
194 otp_digest(nonce, password, hexdigest);
196 /* Compare our calculated digest with what the client submitted */
197 authenticated = !strncmp(hexdigest, otp, 32);
200 backend_gen_nonce(nonce);
202 /* else leave authenticated unchanged */
205 if ((exports_opts & OPT_REMOVABLE) && export_point(dpath)) {
206 /* Removable media export point. Do not call realpath; simply copy
208 strncpy(buf, dpath, PATH_MAX);
209 } else if (!backend_realpath(dpath, buf)) {
210 /* the given path does not exist */
211 result.fhs_status = MNT3ERR_NOENT;
215 if (strlen(buf) + 1 > NFS_MAXPATHLEN) {
216 logmsg(LOG_INFO, "%s attempted to mount jumbo path",
217 inet_ntoa(get_remote(rqstp)));
218 result.fhs_status = MNT3ERR_NAMETOOLONG;
222 if ((exports_options(buf, rqstp, &password, NULL) == -1)
223 || (!authenticated && password[0])
224 || (!(exports_opts & OPT_INSECURE) &&
225 !IS_SECURE(ntohs(get_port(rqstp))))
227 /* not exported to this host or at all, or a password defined and not
229 result.fhs_status = MNT3ERR_ACCES;
233 fh = fh_comp(buf, rqstp, FH_DIR);
236 logmsg(LOG_INFO, "%s attempted to mount non-directory",
237 inet_ntoa(get_remote(rqstp)));
238 result.fhs_status = MNT3ERR_NOTDIR;
242 add_mount(dpath, rqstp);
244 result.fhs_status = MNT3_OK;
245 result.mountres3_u.mountinfo.fhandle.fhandle3_len = fh_length(&fh);
246 result.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *) &fh;
247 result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1;
248 result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = &auth;
253 mountlist *mountproc_dump_3_svc(U(void *argp), U(struct svc_req *rqstp))
258 void *mountproc_umnt_3_svc(dirpath * argp, struct svc_req *rqstp)
260 /* RPC times out if we use a NULL pointer */
261 static void *result = NULL;
263 remove_mount(*argp, rqstp);
265 /* if no more mounts are active, flush all open file descriptors */
272 void *mountproc_umntall_3_svc(U(void *argp), struct svc_req *rqstp)
274 /* RPC times out if we use a NULL pointer */
275 static void *result = NULL;
277 remove_mount(NULL, rqstp);
279 /* if no more mounts are active, flush all open file descriptors */
286 exports *mountproc_export_3_svc(U(void *argp), U(struct svc_req *rqstp))
288 return &exports_nfslist;