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