1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
  29  * All rights reserved.
  30  */
  31 
  32 /*
  33  * Copyright 2018 Nexenta Systems, Inc.
  34  */
  35 
  36 #include <sys/types.h>
  37 #include <rpc/types.h>
  38 #include <sys/systm.h>
  39 #include <sys/vfs.h>
  40 #include <sys/errno.h>
  41 #include <sys/cred.h>
  42 #include <sys/policy.h>
  43 #include <sys/siginfo.h>
  44 #include <sys/proc.h>             /* for exit() declaration */
  45 #include <sys/kmem.h>
  46 #include <nfs/nfs4.h>
  47 #include <nfs/nfssys.h>
  48 #include <sys/thread.h>
  49 #include <rpc/auth.h>
  50 #include <rpc/rpcsys.h>
  51 #include <rpc/svc.h>
  52 
  53 /*
  54  * This is filled in with an appropriate address for the
  55  * function that will traverse the rfs4_client_t table
  56  * and mark any matching IP Address as "forced_expire".
  57  *
  58  * It is the server init() function that plops the
  59  * function pointer.
  60  */
  61 void (*rfs4_client_clrst)(struct nfs4clrst_args *) = NULL;
  62 
  63 /* This filled in by nfssrv:_init() */
  64 void (*nfs_srv_quiesce_func)(void) = NULL;
  65 
  66 extern void nfscmd_args(uint_t);
  67 
  68 /*
  69  * These will be reset by klmmod:lm_svc(), when lockd starts NLM service,
  70  * based on values read by lockd from /etc/default/nfs. Since nfssrv depends on
  71  * klmmod, the declarations need to be here (in nfs, on which both depend) so
  72  * that nfssrv can see the klmmod changes.
  73  * When the dependency of NFSv4 on NLM/lockd is removed, this will need to
  74  * be adjusted.
  75  */
  76 #define RFS4_LEASETIME 90                       /* seconds */
  77 time_t rfs4_lease_time = RFS4_LEASETIME;
  78 time_t rfs4_grace_period = RFS4_LEASETIME;
  79 
  80 /* DSS: distributed stable storage */
  81 size_t nfs4_dss_buflen = 0;
  82 /* This filled in by nfssrv:_init() */
  83 int (*nfs_srv_dss_func)(char *, size_t) = NULL;
  84 
  85 int
  86 nfs_export(void *arg)
  87 {
  88         STRUCT_DECL(exportfs_args, ea);
  89 
  90         STRUCT_INIT(ea, get_udatamodel());
  91         if (copyin(arg, STRUCT_BUF(ea), STRUCT_SIZE(ea)))
  92                 return (set_errno(EFAULT));
  93 
  94         return (exportfs(STRUCT_BUF(ea), get_udatamodel(), CRED()));
  95 }
  96 
  97 int
  98 nfssys(enum nfssys_op opcode, void *arg)
  99 {
 100         int error = 0;
 101 
 102         if (!(opcode == NFS_REVAUTH || opcode == NFS4_SVC) &&
 103             secpolicy_nfs(CRED()) != 0)
 104                 return (set_errno(EPERM));
 105 
 106         switch (opcode) {
 107         case NFS4_CLR_STATE: { /* Clear NFS4 client state */
 108                 struct nfs4clrst_args clr;
 109                 STRUCT_DECL(nfs4clrst_args, u_clr);
 110 
 111                 /*
 112                  * If the server is not loaded then no point in
 113                  * clearing nothing :-)
 114                  */
 115                 if (rfs4_client_clrst == NULL) {
 116                         break;
 117                 }
 118 
 119                 STRUCT_INIT(u_clr, get_udatamodel());
 120 
 121                 if (copyin(arg, STRUCT_BUF(u_clr), STRUCT_SIZE(u_clr)))
 122                         return (set_errno(EFAULT));
 123 
 124                 clr.vers = STRUCT_FGET(u_clr, vers);
 125 
 126                 if (clr.vers != NFS4_CLRST_VERSION)
 127                         return (set_errno(EINVAL));
 128 
 129                 clr.addr_type = STRUCT_FGET(u_clr, addr_type);
 130                 clr.ap = STRUCT_FGETP(u_clr, ap);
 131                 rfs4_client_clrst(&clr);
 132                 break;
 133         }
 134 
 135         case SVCPOOL_CREATE: { /* setup an RPC server thread pool */
 136                 struct svcpool_args p;
 137 
 138                 if (copyin(arg, &p, sizeof (p)))
 139                         return (set_errno(EFAULT));
 140 
 141                 error = svc_pool_create(&p);
 142                 break;
 143         }
 144 
 145         case SVCPOOL_WAIT: { /* wait in kernel for threads to be needed */
 146                 int id;
 147 
 148                 if (copyin(arg, &id, sizeof (id)))
 149                         return (set_errno(EFAULT));
 150 
 151                 error = svc_wait(id);
 152                 break;
 153         }
 154 
 155         case SVCPOOL_RUN: { /* give work to a runnable thread */
 156                 int id;
 157 
 158                 if (copyin(arg, &id, sizeof (id)))
 159                         return (set_errno(EFAULT));
 160 
 161                 error = svc_do_run(id);
 162                 break;
 163         }
 164 
 165         case RDMA_SVC_INIT: {
 166                 struct rdma_svc_args rsa;
 167                 char netstore[20] = "tcp";
 168 
 169                 if (get_udatamodel() != DATAMODEL_NATIVE) {
 170                         STRUCT_DECL(rdma_svc_args, ursa);
 171 
 172                         STRUCT_INIT(ursa, get_udatamodel());
 173                         if (copyin(arg, STRUCT_BUF(ursa), STRUCT_SIZE(ursa)))
 174                                 return (set_errno(EFAULT));
 175 
 176                         rsa.poolid = STRUCT_FGET(ursa, poolid);
 177                         rsa.nfs_versmin = STRUCT_FGET(ursa, nfs_versmin);
 178                         rsa.nfs_versmax = STRUCT_FGET(ursa, nfs_versmax);
 179                         rsa.delegation = STRUCT_FGET(ursa, delegation);
 180                 } else {
 181                         if (copyin(arg, &rsa, sizeof (rsa)))
 182                                 return (set_errno(EFAULT));
 183                 }
 184                 rsa.netid = netstore;
 185 
 186                 error = rdma_start(&rsa);
 187                 break;
 188         }
 189 
 190         case NFS_SVC: { /* NFS server daemon */
 191                 STRUCT_DECL(nfs_svc_args, nsa);
 192                 STRUCT_INIT(nsa, get_udatamodel());
 193 
 194                 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa)))
 195                         return (set_errno(EFAULT));
 196 
 197                 error = nfs_svc(STRUCT_BUF(nsa), get_udatamodel());
 198                 break;
 199         }
 200 
 201         case EXPORTFS: { /* export a file system */
 202                 error = nfs_export(arg);
 203                 break;
 204         }
 205 
 206         case NFS_GETFH: { /* get a file handle */
 207                 STRUCT_DECL(nfs_getfh_args, nga);
 208 
 209                 STRUCT_INIT(nga, get_udatamodel());
 210                 if (copyin(arg, STRUCT_BUF(nga), STRUCT_SIZE(nga)))
 211                         return (set_errno(EFAULT));
 212 
 213                 error = nfs_getfh(STRUCT_BUF(nga), get_udatamodel(), CRED());
 214                 break;
 215         }
 216 
 217         case NFS_REVAUTH: { /* revoke the cached credentials for the uid */
 218                 STRUCT_DECL(nfs_revauth_args, nra);
 219 
 220                 STRUCT_INIT(nra, get_udatamodel());
 221                 if (copyin(arg, STRUCT_BUF(nra), STRUCT_SIZE(nra)))
 222                         return (set_errno(EFAULT));
 223 
 224                 /* This call performs its own privilege checking */
 225                 error = sec_clnt_revoke(STRUCT_FGET(nra, authtype),
 226                     STRUCT_FGET(nra, uid), CRED(), NULL, get_udatamodel());
 227                 break;
 228         }
 229 
 230         case LM_SVC: { /* LM server daemon */
 231                 struct lm_svc_args lsa;
 232 
 233                 if (get_udatamodel() != DATAMODEL_NATIVE) {
 234                         STRUCT_DECL(lm_svc_args, ulsa);
 235 
 236                         STRUCT_INIT(ulsa, get_udatamodel());
 237                         if (copyin(arg, STRUCT_BUF(ulsa), STRUCT_SIZE(ulsa)))
 238                                 return (set_errno(EFAULT));
 239 
 240                         lsa.version = STRUCT_FGET(ulsa, version);
 241                         lsa.fd = STRUCT_FGET(ulsa, fd);
 242                         lsa.n_fmly = STRUCT_FGET(ulsa, n_fmly);
 243                         lsa.n_proto = STRUCT_FGET(ulsa, n_proto);
 244                         lsa.n_rdev = expldev(STRUCT_FGET(ulsa, n_rdev));
 245                         lsa.debug = STRUCT_FGET(ulsa, debug);
 246                         lsa.timout = STRUCT_FGET(ulsa, timout);
 247                         lsa.grace = STRUCT_FGET(ulsa, grace);
 248                         lsa.retransmittimeout = STRUCT_FGET(ulsa,
 249                             retransmittimeout);
 250                 } else {
 251                         if (copyin(arg, &lsa, sizeof (lsa)))
 252                                 return (set_errno(EFAULT));
 253                 }
 254 
 255                 error = lm_svc(&lsa);
 256                 break;
 257         }
 258 
 259         case KILL_LOCKMGR: {
 260                 error = lm_shutdown();
 261                 break;
 262         }
 263 
 264         case LOG_FLUSH: {       /* Flush log buffer and possibly rename */
 265                 STRUCT_DECL(nfsl_flush_args, nfa);
 266 
 267                 STRUCT_INIT(nfa, get_udatamodel());
 268                 if (copyin(arg, STRUCT_BUF(nfa), STRUCT_SIZE(nfa)))
 269                         return (set_errno(EFAULT));
 270 
 271                 error = nfsl_flush(STRUCT_BUF(nfa), get_udatamodel());
 272                 break;
 273         }
 274 
 275         case NFS4_SVC: { /* NFS client callback daemon */
 276 
 277                 STRUCT_DECL(nfs4_svc_args, nsa);
 278 
 279                 STRUCT_INIT(nsa, get_udatamodel());
 280 
 281                 if (copyin(arg, STRUCT_BUF(nsa), STRUCT_SIZE(nsa)))
 282                         return (set_errno(EFAULT));
 283 
 284                 error = nfs4_svc(STRUCT_BUF(nsa), get_udatamodel());
 285                 break;
 286         }
 287 
 288         /* Request that NFSv4 server quiesce on next shutdown */
 289         case NFS4_SVC_REQUEST_QUIESCE: {
 290                 int id;
 291 
 292                 /* check that nfssrv module is loaded */
 293                 if (nfs_srv_quiesce_func == NULL)
 294                         return (set_errno(ENOTSUP));
 295 
 296                 if (copyin(arg, &id, sizeof (id)))
 297                         return (set_errno(EFAULT));
 298 
 299                 error = svc_pool_control(id, SVCPSET_SHUTDOWN_PROC,
 300                     (void *)nfs_srv_quiesce_func);
 301                 break;
 302         }
 303 
 304         case NFS_IDMAP: {
 305                 struct nfsidmap_args idm;
 306 
 307                 if (copyin(arg, &idm, sizeof (idm)))
 308                         return (set_errno(EFAULT));
 309 
 310                 nfs_idmap_args(&idm);
 311                 error = 0;
 312                 break;
 313         }
 314 
 315         case NFS4_DSS_SETPATHS_SIZE: {
 316                 /* crosses ILP32/LP64 boundary */
 317                 uint32_t nfs4_dss_bufsize = 0;
 318 
 319                 if (copyin(arg, &nfs4_dss_bufsize, sizeof (nfs4_dss_bufsize)))
 320                         return (set_errno(EFAULT));
 321                 nfs4_dss_buflen = (long)nfs4_dss_bufsize;
 322                 error = 0;
 323                 break;
 324         }
 325 
 326         case NFS4_DSS_SETPATHS: {
 327                 char *nfs4_dss_bufp;
 328 
 329                 /* check that nfssrv module is loaded */
 330                 if (nfs_srv_dss_func == NULL)
 331                         return (set_errno(ENOTSUP));
 332 
 333                 /*
 334                  * NFS4_DSS_SETPATHS_SIZE must be called before
 335                  * NFS4_DSS_SETPATHS, to tell us how big a buffer we need
 336                  * to allocate.
 337                  */
 338                 if (nfs4_dss_buflen == 0)
 339                         return (set_errno(EINVAL));
 340                 nfs4_dss_bufp = kmem_alloc(nfs4_dss_buflen, KM_SLEEP);
 341                 if (nfs4_dss_bufp == NULL)
 342                         return (set_errno(ENOMEM));
 343 
 344                 if (copyin(arg, nfs4_dss_bufp, nfs4_dss_buflen)) {
 345                         kmem_free(nfs4_dss_bufp, nfs4_dss_buflen);
 346                         return (set_errno(EFAULT));
 347                 }
 348 
 349                 /* unpack the buffer and extract the pathnames */
 350                 error = nfs_srv_dss_func(nfs4_dss_bufp, nfs4_dss_buflen);
 351                 kmem_free(nfs4_dss_bufp, nfs4_dss_buflen);
 352 
 353                 break;
 354         }
 355 
 356         case NFS4_EPHEMERAL_MOUNT_TO: {
 357                 uint_t  mount_to;
 358 
 359                 /*
 360                  * Not a very complicated call.
 361                  */
 362                 if (copyin(arg, &mount_to, sizeof (mount_to)))
 363                         return (set_errno(EFAULT));
 364                 nfs4_ephemeral_set_mount_to(mount_to);
 365                 error = 0;
 366                 break;
 367         }
 368 
 369         case MOUNTD_ARGS: {
 370                 uint_t  did;
 371 
 372                 /*
 373                  * For now, only passing down the door fd; if we
 374                  * ever need to pass down more info, we can use
 375                  * a (properly aligned) struct.
 376                  */
 377                 if (copyin(arg, &did, sizeof (did)))
 378                         return (set_errno(EFAULT));
 379                 mountd_args(did);
 380                 error = 0;
 381                 break;
 382         }
 383 
 384         case NFSCMD_ARGS: {
 385                 uint_t  did;
 386 
 387                 /*
 388                  * For now, only passing down the door fd; if we
 389                  * ever need to pass down more info, we can use
 390                  * a (properly aligned) struct.
 391                  */
 392                 if (copyin(arg, &did, sizeof (did)))
 393                         return (set_errno(EFAULT));
 394                 nfscmd_args(did);
 395                 error = 0;
 396                 break;
 397         }
 398 
 399         default:
 400                 error = EINVAL;
 401                 break;
 402         }
 403 
 404         return ((error != 0) ? set_errno(error) : 0);
 405 }