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-2023 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 smbd_nomem(); 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 smbd_nomem(); 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 /* 261 * Decide whether we should trust the (in-band) user information 262 * that the client sends us over the named pipe. The (in-kernel) 263 * SMB service calls this with the credential of the logged-on 264 * SMB user. The privileges are normally: 265 * effective: basic,file_dac_search 266 * inheritable: basic 267 * permitted: basic,file_dac_search,sys_smb 268 * limit: all 269 * This tests the permitted set for the presence of PRIV_SYS_SMB, 270 * which should only be granted to the SMB server. 271 */ 272 static boolean_t 273 pipe_has_priv(ndr_pipe_t *np) 274 { 275 ucred_t *uc = NULL; 276 const priv_set_t *ps = NULL; 277 boolean_t ret = B_FALSE; 278 pid_t clpid; 279 280 if (getpeerucred(np->np_fid, &uc) != 0) { 281 smbd_report("pipesvc: getpeerucred err %d", errno); 282 return (B_FALSE); 283 } 284 clpid = ucred_getpid(uc); 285 ps = ucred_getprivset(uc, PRIV_PERMITTED); 286 if (ps == NULL) { 287 smbd_report("pipesvc: ucred_getprivset failed"); 288 goto out; 289 } 290 291 /* 292 * Require sys_smb priv. 293 */ 294 if (priv_ismember(ps, PRIV_SYS_SMB)) { 295 ret = B_TRUE; 296 goto out; 297 } 298 299 if (smbd.s_debug) { 300 smbd_report("pipesvc: non-privileged client " 301 "PID = %d UID = %d", 302 (int)clpid, ucred_getruid(uc)); 303 } 304 305 out: 306 /* ps is free'd with the ucred */ 307 if (uc != NULL) 308 ucred_free(uc); 309 310 return (ret); 311 } 312 #endif 313 314 static void * 315 pipesvc_worker(void *varg) 316 { 317 XDR xdrs; 318 smb_pipehdr_t phdr; 319 ndr_pipe_t *np = varg; 320 struct pipe_listener *pl = np->np_listener; 321 void *buf = NULL; 322 uint32_t status; 323 ssize_t rc; 324 325 (void) mutex_lock(&pipesvc_mutex); 326 if (pipesvc_workers_cur >= pipesvc_workers_max || 327 pl->current >= pl->max_allowed) { 328 (void) mutex_unlock(&pipesvc_mutex); 329 status = NT_STATUS_PIPE_NOT_AVAILABLE; 330 (void) send(np->np_fid, &status, sizeof (status), 0); 331 goto out_free_np; 332 } 333 pipesvc_workers_cur++; 334 pl->current++; 335 if (pl->max_seen < pl->current) 336 pl->max_seen = pl->current; 337 (void) mutex_unlock(&pipesvc_mutex); 338 339 /* 340 * The smbsrv kmod sends us one initial message containing an 341 * XDR encoded smb_netuserinfo_t that we read and decode here, 342 * all unbeknownst to libmlrpc. 343 * 344 * Might be nice to enhance getpeerucred() so it can give us 345 * all the info smb_netuserinfo_t carries, and then use that, 346 * which would allow using a more generic RPC service. 347 */ 348 rc = pipe_recv(np, &phdr, sizeof (phdr)); 349 if (rc != 0) { 350 smbd_report("pipesvc_worker, recv1: %d", rc); 351 goto out_decr; 352 } 353 if (phdr.ph_magic != SMB_PIPE_HDR_MAGIC || 354 phdr.ph_uilen > 8192) { 355 smbd_report("pipesvc_worker, bad hdr"); 356 goto out_decr; 357 } 358 buf = malloc(phdr.ph_uilen); 359 if (buf == NULL) { 360 smbd_report("pipesvc_worker, alloc1 failed"); 361 goto out_decr; 362 } 363 rc = pipe_recv(np, buf, phdr.ph_uilen); 364 if (rc != 0) { 365 smbd_report("pipesvc_worker, recv2: %d", rc); 366 goto out_decr; 367 } 368 369 xdrmem_create(&xdrs, buf, phdr.ph_uilen, XDR_DECODE); 370 if (!smb_netuserinfo_xdr(&xdrs, np->np_user)) { 371 smbd_report("pipesvc_worker, bad uinfo"); 372 goto out_free_buf; 373 } 374 375 /* 376 * Don't trust the netuserinfo unless the client side 377 * has the necessary privileges 378 */ 379 #ifndef FKSMBD 380 if (!pipe_has_priv(np)) { 381 np->np_user->ui_flags = SMB_ATF_ANON; 382 } 383 #endif 384 385 /* 386 * Later, could disallow opens of some pipes by 387 * anonymous users, etc. For now, reply "OK". 388 */ 389 status = 0; 390 rc = pipe_send(np, &status, sizeof (status)); 391 if (rc != 0) { 392 smbd_report("pipesvc_worker, send1: %d", rc); 393 goto out_free_buf; 394 } 395 396 /* 397 * Run the RPC service loop worker, which 398 * returns when it sees the pipe close. 399 */ 400 ndr_pipe_worker(np); 401 402 xdrs.x_op = XDR_FREE; 403 (void) smb_netuserinfo_xdr(&xdrs, np->np_user); 404 405 out_free_buf: 406 free(buf); 407 xdr_destroy(&xdrs); 408 409 out_decr: 410 (void) mutex_lock(&pipesvc_mutex); 411 pipesvc_workers_cur--; 412 pl->current--; 413 (void) mutex_unlock(&pipesvc_mutex); 414 415 out_free_np: 416 /* Cleanup what came in by varg. */ 417 (void) shutdown(np->np_fid, SHUT_RDWR); 418 np_free(np); 419 return (NULL); 420 } 421 422 /* 423 * These are the transport get/put callback functions provided 424 * via the ndr_pipe_t object to the libmlrpc`ndr_pipe_worker. 425 * These are called only with known PDU sizes and should 426 * loop as needed to transfer the entire message. 427 */ 428 static int 429 pipe_recv(ndr_pipe_t *np, void *buf, size_t len) 430 { 431 int x; 432 433 while (len > 0) { 434 x = recv(np->np_fid, buf, len, 0); 435 if (x < 0) 436 return (errno); 437 if (x == 0) 438 return (EIO); 439 buf = (char *)buf + x; 440 len -= x; 441 } 442 443 return (0); 444 } 445 446 static int 447 pipe_send(ndr_pipe_t *np, void *buf, size_t len) 448 { 449 int x; 450 451 while (len > 0) { 452 x = send(np->np_fid, buf, len, 0); 453 if (x < 0) 454 return (errno); 455 if (x == 0) 456 return (EIO); 457 buf = (char *)buf + x; 458 len -= x; 459 } 460 461 return (0); 462 } 463