1 /*
   2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
  40 
  41 /* This file contains all the door server code */
  42 
  43 #include <syslog.h>
  44 #include <door.h>
  45 #include <alloca.h>
  46 #include <errno.h>
  47 #include <note.h>
  48 #include <libintl.h>
  49 #include <ndmpd_door.h>
  50 #include "ndmpd.h"
  51 
  52 /* static variables */
  53 static int      ndmp_door_fildes = -1;
  54 static mutex_t  ndmp_doorsrv_mutex;
  55 
  56 /* static routines */
  57 static void ndmp_door_server(void *cookie, char *ptr, size_t size,
  58     door_desc_t *dp, uint_t n_desc);
  59 
  60 /*
  61  * Statistics used in ndmpstat command
  62  */
  63 ndmp_stat_t ndstat;
  64 
  65 int
  66 ndmp_door_init(void)
  67 {
  68         int fd;
  69 
  70         (void) mutex_lock(&ndmp_doorsrv_mutex);
  71 
  72         if (ndmp_door_fildes != -1) {
  73                 syslog(LOG_ERR,
  74                     "ndmp_door_init: ndmpd service is already running.");
  75                 (void) mutex_unlock(&ndmp_doorsrv_mutex);
  76                 return (0);
  77         }
  78 
  79         if ((ndmp_door_fildes = door_create(ndmp_door_server,
  80             NULL, DOOR_UNREF)) < 0) {
  81                 syslog(LOG_ERR, "ndmp_door_init: Could not create door.");
  82                 (void) mutex_unlock(&ndmp_doorsrv_mutex);
  83                 return (-1);
  84         }
  85 
  86         (void) unlink(NDMP_DOOR_SVC);
  87 
  88         if ((fd = creat(NDMP_DOOR_SVC, 0444)) < 0) {
  89                 syslog(LOG_ERR, "ndmp_door_init: Can't create %s: %m.",
  90                     NDMP_DOOR_SVC);
  91                 (void) door_revoke(ndmp_door_fildes);
  92                 ndmp_door_fildes = -1;
  93                 (void) mutex_unlock(&ndmp_doorsrv_mutex);
  94                 return (-1);
  95         }
  96 
  97         (void) close(fd);
  98         (void) fdetach(NDMP_DOOR_SVC);
  99 
 100         if (fattach(ndmp_door_fildes, NDMP_DOOR_SVC) < 0) {
 101                 syslog(LOG_ERR, "ndmp_door_init: fattach failed %m");
 102                 (void) door_revoke(ndmp_door_fildes);
 103                 ndmp_door_fildes = -1;
 104                 (void) mutex_unlock(&ndmp_doorsrv_mutex);
 105                 return (-1);
 106         }
 107 
 108         syslog(LOG_DEBUG, "ndmp_door_init: Door server successfully started");
 109         (void) mutex_unlock(&ndmp_doorsrv_mutex);
 110         return (0);
 111 }
 112 
 113 void
 114 ndmp_door_fini(void)
 115 {
 116         (void) mutex_lock(&ndmp_doorsrv_mutex);
 117 
 118         if (ndmp_door_fildes != -1) {
 119                 (void) fdetach(NDMP_DOOR_SVC);
 120                 (void) door_revoke(ndmp_door_fildes);
 121                 ndmp_door_fildes = -1;
 122         }
 123 
 124         (void) mutex_unlock(&ndmp_doorsrv_mutex);
 125 }
 126 
 127 boolean_t
 128 ndmp_door_check(void)
 129 {
 130         door_info_t info;
 131         int door;
 132 
 133         if ((door = open(NDMP_DOOR_SVC, O_RDONLY)) < 0)
 134                 return (0);
 135 
 136         if (door_info(door, &info) < 0) {
 137                 (void) close(door);
 138                 return (0);
 139         }
 140 
 141         if (info.di_target > 0) {
 142                 syslog(LOG_ERR,
 143                     "Service already running: pid %ld", info.di_target);
 144                 (void) close(door);
 145                 return (1);
 146         }
 147 
 148         (void) close(door);
 149         return (0);
 150 }
 151 
 152 /* door server */
 153 /*ARGSUSED*/
 154 void
 155 ndmp_door_server(void *cookie, char *ptr, size_t size,
 156     door_desc_t *dp, uint_t n_desc)
 157 {
 158         NOTE(ARGUNUSED(cookie,dp,n_desc))
 159         int req_type;
 160         char *buf;
 161         int buflen;
 162         unsigned int used;
 163         ndmp_door_ctx_t *dec_ctx;
 164         ndmp_door_ctx_t *enc_ctx;
 165         unsigned int dec_status = EINVAL;
 166         unsigned int enc_status = EINVAL;
 167 
 168         dec_ctx = ndmp_door_decode_start(ptr, size);
 169         if (dec_ctx == 0)
 170                 return;
 171 
 172         req_type = ndmp_door_get_uint32(dec_ctx);
 173         buflen = NDMP_DOOR_SIZE;
 174 
 175         if ((buf = alloca(buflen)) == NULL) {
 176                 syslog(LOG_ERR, "Out of memory.");
 177                 (void) ndmp_door_decode_finish(dec_ctx);
 178                 return;
 179         }
 180 
 181         enc_ctx = ndmp_door_encode_start(buf, buflen);
 182         if (enc_ctx == 0) {
 183                 (void) ndmp_door_decode_finish(dec_ctx);
 184                 return;
 185         }
 186 
 187         if (req_type != NDMP_GET_STAT)
 188                 syslog(LOG_DEBUG, "ndmp_door_server: req_type=%d", req_type);
 189 
 190         switch (req_type) {
 191         case NDMP_GET_DOOR_STATUS: {
 192                 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
 193                 break;
 194                 }
 195         case NDMP_DEVICES_GET_INFO: {
 196                 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
 197                 ndmpd_get_devs(enc_ctx);
 198                 break;
 199                 }
 200         case NDMP_SHOW: {
 201                 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
 202                 ndmp_connect_list_get(enc_ctx);
 203                 break;
 204                 }
 205         case NDMP_TERMINATE_SESSION_ID: {
 206                 int status, id;
 207                 id = ndmp_door_get_int32(dec_ctx);
 208                 status = ndmpd_connect_kill_id(id);
 209                 if (status == -1) /* session not found */
 210                         ndmp_door_put_int32(enc_ctx,
 211                             NDMP_DOOR_SRV_SUCCESS);
 212                 else
 213                         ndmp_door_put_int32(enc_ctx,
 214                             NDMP_DOOR_SRV_SUCCESS);
 215                 ndmp_door_put_int32(enc_ctx, status);
 216                 break;
 217                 }
 218 
 219         case NDMP_GET_STAT:
 220                 ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_SUCCESS);
 221                 ndmp_door_put_uint32(enc_ctx, ndstat.ns_trun);
 222                 ndmp_door_put_uint32(enc_ctx, ndstat.ns_twait);
 223                 ndmp_door_put_uint32(enc_ctx, ndstat.ns_nbk);
 224                 ndmp_door_put_uint32(enc_ctx, ndstat.ns_nrs);
 225                 ndmp_door_put_uint32(enc_ctx, ndstat.ns_rfile);
 226                 ndmp_door_put_uint32(enc_ctx, ndstat.ns_wfile);
 227                 ndmp_door_put_uint64(enc_ctx, ndstat.ns_rdisk);
 228                 ndmp_door_put_uint64(enc_ctx, ndstat.ns_wdisk);
 229                 ndmp_door_put_uint64(enc_ctx, ndstat.ns_rtape);
 230                 ndmp_door_put_uint64(enc_ctx, ndstat.ns_wtape);
 231                 break;
 232 
 233         default:
 234                 syslog(LOG_ERR,
 235                     "ndmp_door_server: Invalid request type 0x%x", req_type);
 236                 goto decode_error;
 237         }
 238 
 239         if ((dec_status = ndmp_door_decode_finish(dec_ctx)) != 0)
 240                 goto decode_error;
 241 
 242         if ((enc_status = ndmp_door_encode_finish(enc_ctx, &used)) != 0)
 243                 goto encode_error;
 244 
 245         (void) door_return(buf, used, NULL, 0);
 246 
 247         return;
 248 
 249 decode_error:
 250         ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_ERROR);
 251         ndmp_door_put_uint32(enc_ctx, dec_status);
 252         (void) ndmp_door_encode_finish(enc_ctx, &used);
 253         (void) door_return(buf, used, NULL, 0);
 254         return;
 255 
 256 encode_error:
 257         enc_ctx = ndmp_door_encode_start(buf, buflen);
 258         ndmp_door_put_int32(enc_ctx, NDMP_DOOR_SRV_ERROR);
 259         ndmp_door_put_uint32(enc_ctx, enc_status);
 260         (void) ndmp_door_encode_finish(enc_ctx, &used);
 261         (void) door_return(buf, used, NULL, 0);
 262 }