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