1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 14 */ 15 16 /* 17 * This is the named pipe service for smbd. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 23 #include <stdio.h> 24 #include <strings.h> 25 #include <stdlib.h> 26 #include <synch.h> 27 #include <unistd.h> 28 #include <fcntl.h> 29 #include <door.h> 30 #include <errno.h> 31 #include <pthread.h> 32 #include <signal.h> 33 34 #include <smbsrv/libsmb.h> 35 #include <smbsrv/libmlsvc.h> 36 #include <smbsrv/smb_xdr.h> 37 #include "smbd.h" 38 39 struct pipe_listener { 40 const char *name; 41 int max_allowed; 42 int max_seen; 43 int current; 44 pthread_t tid; 45 }; 46 47 static void *pipesvc_listener(void *); 48 static void *pipesvc_worker(void *); 49 static int pipe_send(ndr_pipe_t *, void *, size_t); 50 static int pipe_recv(ndr_pipe_t *, void *, size_t); 51 52 mutex_t pipesvc_mutex = DEFAULTMUTEX; 53 int pipesvc_workers_max = 500; 54 int pipesvc_workers_cur = 0; 55 56 uint16_t pipe_max_msgsize = SMB_PIPE_MAX_MSGSIZE; 57 58 /* 59 * Allow more opens on SRVSVC because that's used by many clients 60 * to get the share list, etc. 61 */ 62 #define SRVSVC_MAX_OPENS 200 63 #define DEF_MAX_OPENS 50 64 65 #define NLISTENERS 11 66 static struct pipe_listener 67 pipe_listeners[NLISTENERS] = { 68 { "eventlog", DEF_MAX_OPENS, 0, 0 }, 69 { "lsarpc", DEF_MAX_OPENS, 0, 0 }, 70 { "lsass", DEF_MAX_OPENS, 0, 0 }, 71 { "netdfs", DEF_MAX_OPENS, 0, 0 }, 72 { "netlogon", DEF_MAX_OPENS, 0, 0 }, 73 { "samr", DEF_MAX_OPENS, 0, 0 }, 74 { "spoolss", DEF_MAX_OPENS, 0, 0 }, 75 { "srvsvc", SRVSVC_MAX_OPENS, 0, 0 }, 76 { "svcctl", DEF_MAX_OPENS, 0, 0 }, 77 { "winreg", DEF_MAX_OPENS, 0, 0 }, 78 { "wkssvc", DEF_MAX_OPENS, 0, 0 }, 79 }; 80 81 static ndr_pipe_t * 82 np_new(struct pipe_listener *pl, int fid) 83 { 84 ndr_pipe_t *np; 85 size_t len; 86 87 /* 88 * Allocating ndr_pipe_t + smb_netuserinfo_t as one. 89 * We could just make that part of ndr_pipe_t, but 90 * that struct is opaque to libmlrpc. 91 */ 92 len = sizeof (*np) + sizeof (smb_netuserinfo_t); 93 np = malloc(len); 94 if (np == NULL) 95 return (NULL); 96 97 bzero(np, len); 98 np->np_listener = pl; 99 np->np_endpoint = pl->name; 100 np->np_user = (void*)(np + 1); 101 np->np_send = pipe_send; 102 np->np_recv = pipe_recv; 103 np->np_fid = fid; 104 np->np_max_xmit_frag = pipe_max_msgsize; 105 np->np_max_recv_frag = pipe_max_msgsize; 106 107 return (np); 108 } 109 110 static void 111 np_free(ndr_pipe_t *np) 112 { 113 (void) close(np->np_fid); 114 free(np); 115 } 116 117 /* 118 * Create the smbd opipe door service. 119 * Returns the door descriptor on success. Otherwise returns -1. 120 */ 121 int 122 smbd_pipesvc_start(void) 123 { 124 pthread_t tid; 125 pthread_attr_t tattr; 126 struct pipe_listener *pl; 127 int i, rc; 128 129 if (mlsvc_init() != 0) { 130 smbd_report("msrpc initialization failed"); 131 return (-1); 132 } 133 134 (void) pthread_attr_init(&tattr); 135 (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 136 137 for (i = 0; i < NLISTENERS; i++) { 138 pl = &pipe_listeners[i]; 139 pl->max_seen = 0; 140 141 if (strcasecmp(pl->name, "spoolss") == 0 && 142 smb_config_getbool(SMB_CI_PRINT_ENABLE) == B_FALSE) 143 continue; 144 145 rc = pthread_create(&tid, &tattr, pipesvc_listener, pl); 146 if (rc != 0) 147 break; 148 pipe_listeners[i].tid = tid; 149 } 150 151 if (rc != 0) { 152 smbd_report("pipesvc pthread_create, %d", rc); 153 } 154 155 (void) pthread_attr_destroy(&tattr); 156 157 return (rc); 158 } 159 160 void 161 smbd_pipesvc_stop(void) 162 { 163 int i; 164 165 (void) mutex_lock(&pipesvc_mutex); 166 for (i = 0; i < NLISTENERS; i++) { 167 if (pipe_listeners[i].tid == 0) 168 continue; 169 (void) pthread_kill(pipe_listeners[i].tid, SIGTERM); 170 pipe_listeners[i].tid = 0; 171 } 172 (void) mutex_unlock(&pipesvc_mutex); 173 } 174 175 static void * 176 pipesvc_listener(void *varg) 177 { 178 struct sockaddr_un sa; 179 int err, listen_fd, newfd, snlen; 180 struct pipe_listener *pl = varg; 181 ndr_pipe_t *np; 182 pthread_t tid; 183 int rc; 184 185 listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); 186 if (listen_fd < 0) { 187 smbd_report("pipesvc_listener, so_create: %d", errno); 188 return (NULL); 189 } 190 191 bzero(&sa, sizeof (sa)); 192 sa.sun_family = AF_UNIX; 193 (void) snprintf(sa.sun_path, sizeof (sa.sun_path), 194 "%s/%s", SMB_PIPE_DIR, pl->name); 195 196 /* Bind it to a listening name. */ 197 (void) unlink(sa.sun_path); 198 if (bind(listen_fd, (struct sockaddr *)&sa, sizeof (sa)) < 0) { 199 smbd_report("pipesvc_listener, so_bind: %d", errno); 200 (void) close(listen_fd); 201 return (NULL); 202 } 203 204 if (listen(listen_fd, SOMAXCONN) < 0) { 205 smbd_report("pipesvc_listener, listen: %d", errno); 206 (void) close(listen_fd); 207 return (NULL); 208 } 209 210 for (;;) { 211 212 snlen = sizeof (sa); 213 newfd = accept(listen_fd, (struct sockaddr *)&sa, &snlen); 214 if (newfd < 0) { 215 err = errno; 216 switch (err) { 217 case ECONNABORTED: 218 continue; 219 case EINTR: 220 /* normal termination */ 221 goto out; 222 default: 223 smbd_report("pipesvc_listener, " 224 "accept failed: %d", errno); 225 } 226 smbd_report("pipesvc_listener, accept: %d", err); 227 break; 228 } 229 230 np = np_new(pl, newfd); 231 if (np == NULL) { 232 smbd_report("pipesvc_listener, alloc1 failed"); 233 (void) close(newfd); 234 continue; 235 } 236 237 rc = pthread_create(&tid, NULL, pipesvc_worker, np); 238 if (rc != 0) { 239 smbd_report("pipesvc_listener, pthread_create: %d", 240 errno); 241 np_free(np); 242 continue; 243 } 244 (void) pthread_detach(tid); 245 246 /* Note: np_free in pipesvc_worker */ 247 np = NULL; 248 } 249 250 out: 251 (void) close(listen_fd); 252 pl->tid = 0; 253 return (NULL); 254 } 255 256 static void * 257 pipesvc_worker(void *varg) 258 { 259 XDR xdrs; 260 smb_pipehdr_t phdr; 261 ndr_pipe_t *np = varg; 262 struct pipe_listener *pl = np->np_listener; 263 void *buf = NULL; 264 uint32_t status; 265 ssize_t rc; 266 267 (void) mutex_lock(&pipesvc_mutex); 268 if (pipesvc_workers_cur >= pipesvc_workers_max || 269 pl->current >= pl->max_allowed) { 270 (void) mutex_unlock(&pipesvc_mutex); 271 status = NT_STATUS_PIPE_NOT_AVAILABLE; 272 (void) send(np->np_fid, &status, sizeof (status), 0); 273 goto out_free_np; 274 } 275 pipesvc_workers_cur++; 276 pl->current++; 277 if (pl->max_seen < pl->current) 278 pl->max_seen = pl->current; 279 (void) mutex_unlock(&pipesvc_mutex); 280 281 /* 282 * The smbsrv kmod sends us one initial message containing an 283 * XDR encoded smb_netuserinfo_t that we read and decode here, 284 * all unbeknownst to libmlrpc. 285 * 286 * Might be nice to enhance getpeerucred() so it can give us 287 * all the info smb_netuserinfo_t carries, and then use that, 288 * which would allow using a more generic RPC service. 289 */ 290 rc = pipe_recv(np, &phdr, sizeof (phdr)); 291 if (rc != 0) { 292 smbd_report("pipesvc_worker, recv1: %d", rc); 293 goto out_decr; 294 } 295 if (phdr.ph_magic != SMB_PIPE_HDR_MAGIC || 296 phdr.ph_uilen > 8192) { 297 smbd_report("pipesvc_worker, bad hdr"); 298 goto out_decr; 299 } 300 buf = malloc(phdr.ph_uilen); 301 if (buf == NULL) { 302 smbd_report("pipesvc_worker, alloc1 failed"); 303 goto out_decr; 304 } 305 rc = pipe_recv(np, buf, phdr.ph_uilen); 306 if (rc != 0) { 307 smbd_report("pipesvc_worker, recv2: %d", rc); 308 goto out_decr; 309 } 310 311 xdrmem_create(&xdrs, buf, phdr.ph_uilen, XDR_DECODE); 312 if (!smb_netuserinfo_xdr(&xdrs, np->np_user)) { 313 smbd_report("pipesvc_worker, bad uinfo"); 314 goto out_free_buf; 315 } 316 317 /* 318 * Later, could disallow opens of some pipes by 319 * anonymous users, etc. For now, reply "OK". 320 */ 321 status = 0; 322 rc = pipe_send(np, &status, sizeof (status)); 323 if (rc != 0) { 324 smbd_report("pipesvc_worker, send1: %d", rc); 325 goto out_free_buf; 326 } 327 328 /* 329 * Run the RPC service loop worker, which 330 * returns when it sees the pipe close. 331 */ 332 ndr_pipe_worker(np); 333 334 xdrs.x_op = XDR_FREE; 335 (void) smb_netuserinfo_xdr(&xdrs, np->np_user); 336 337 out_free_buf: 338 free(buf); 339 xdr_destroy(&xdrs); 340 341 out_decr: 342 (void) mutex_lock(&pipesvc_mutex); 343 pipesvc_workers_cur--; 344 pl->current--; 345 (void) mutex_unlock(&pipesvc_mutex); 346 347 out_free_np: 348 /* Cleanup what came in by varg. */ 349 (void) shutdown(np->np_fid, SHUT_RDWR); 350 np_free(np); 351 return (NULL); 352 } 353 354 /* 355 * These are the transport get/put callback functions provided 356 * via the ndr_pipe_t object to the libmlrpc`ndr_pipe_worker. 357 * These are called only with known PDU sizes and should 358 * loop as needed to transfer the entire message. 359 */ 360 static int 361 pipe_recv(ndr_pipe_t *np, void *buf, size_t len) 362 { 363 int x; 364 365 while (len > 0) { 366 x = recv(np->np_fid, buf, len, 0); 367 if (x < 0) 368 return (errno); 369 if (x == 0) 370 return (EIO); 371 buf = (char *)buf + x; 372 len -= x; 373 } 374 375 return (0); 376 } 377 378 static int 379 pipe_send(ndr_pipe_t *np, void *buf, size_t len) 380 { 381 int x; 382 383 while (len > 0) { 384 x = send(np->np_fid, buf, len, 0); 385 if (x < 0) 386 return (errno); 387 if (x == 0) 388 return (EIO); 389 buf = (char *)buf + x; 390 len -= x; 391 } 392 393 return (0); 394 } 395