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