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