1/* 2 Unix SMB/CIFS implementation. 3 4 a pass-thru NTVFS module to setup a security context using unix 5 uid/gid 6 7 Copyright (C) Andrew Tridgell 2004 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "system/filesys.h" 25#include "system/passwd.h" 26#include "auth/auth.h" 27#include "ntvfs/ntvfs.h" 28#include "libcli/wbclient/wbclient.h" 29#define TEVENT_DEPRECATED 30#include <tevent.h> 31 32struct unixuid_private { 33 struct wbc_context *wbc_ctx; 34 struct unix_sec_ctx *last_sec_ctx; 35 struct security_token *last_token; 36}; 37 38 39 40struct unix_sec_ctx { 41 uid_t uid; 42 gid_t gid; 43 uint_t ngroups; 44 gid_t *groups; 45}; 46 47/* 48 pull the current security context into a unix_sec_ctx 49*/ 50static struct unix_sec_ctx *save_unix_security(TALLOC_CTX *mem_ctx) 51{ 52 struct unix_sec_ctx *sec = talloc(mem_ctx, struct unix_sec_ctx); 53 if (sec == NULL) { 54 return NULL; 55 } 56 sec->uid = geteuid(); 57 sec->gid = getegid(); 58 sec->ngroups = getgroups(0, NULL); 59 if (sec->ngroups == -1) { 60 talloc_free(sec); 61 return NULL; 62 } 63 sec->groups = talloc_array(sec, gid_t, sec->ngroups); 64 if (sec->groups == NULL) { 65 talloc_free(sec); 66 return NULL; 67 } 68 69 if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) { 70 talloc_free(sec); 71 return NULL; 72 } 73 74 return sec; 75} 76 77/* 78 set the current security context from a unix_sec_ctx 79*/ 80static NTSTATUS set_unix_security(struct unix_sec_ctx *sec) 81{ 82 seteuid(0); 83 84 if (setgroups(sec->ngroups, sec->groups) != 0) { 85 return NT_STATUS_ACCESS_DENIED; 86 } 87 if (setegid(sec->gid) != 0) { 88 return NT_STATUS_ACCESS_DENIED; 89 } 90 if (seteuid(sec->uid) != 0) { 91 return NT_STATUS_ACCESS_DENIED; 92 } 93 return NT_STATUS_OK; 94} 95 96static int unixuid_nesting_level; 97 98/* 99 called at the start and end of a tevent nesting loop. Needs to save/restore 100 unix security context 101 */ 102static int unixuid_event_nesting_hook(struct tevent_context *ev, 103 void *private_data, 104 uint32_t level, 105 bool begin, 106 void *stack_ptr, 107 const char *location) 108{ 109 struct unix_sec_ctx *sec_ctx; 110 111 if (unixuid_nesting_level == 0) { 112 /* we don't need to do anything unless we are nested 113 inside of a call in this module */ 114 return 0; 115 } 116 117 if (begin) { 118 sec_ctx = save_unix_security(ev); 119 if (sec_ctx == NULL) { 120 DEBUG(0,("%s: Failed to save security context\n", location)); 121 return -1; 122 } 123 *(struct unix_sec_ctx **)stack_ptr = sec_ctx; 124 if (seteuid(0) != 0 || setegid(0) != 0) { 125 DEBUG(0,("%s: Failed to change to root\n", location)); 126 return -1; 127 } 128 } else { 129 /* called when we come out of a nesting level */ 130 NTSTATUS status; 131 132 sec_ctx = *(struct unix_sec_ctx **)stack_ptr; 133 if (sec_ctx == NULL) { 134 /* this happens the first time this function 135 is called, as we install the hook while 136 inside an event in unixuid_connect() */ 137 return 0; 138 } 139 140 sec_ctx = talloc_get_type_abort(sec_ctx, struct unix_sec_ctx); 141 status = set_unix_security(sec_ctx); 142 talloc_free(sec_ctx); 143 if (!NT_STATUS_IS_OK(status)) { 144 DEBUG(0,("%s: Failed to revert security context (%s)\n", 145 location, nt_errstr(status))); 146 return -1; 147 } 148 } 149 150 return 0; 151} 152 153 154/* 155 form a unix_sec_ctx from the current security_token 156*/ 157static NTSTATUS nt_token_to_unix_security(struct ntvfs_module_context *ntvfs, 158 struct ntvfs_request *req, 159 struct security_token *token, 160 struct unix_sec_ctx **sec) 161{ 162 struct unixuid_private *priv = ntvfs->private_data; 163 int i; 164 NTSTATUS status; 165 struct id_mapping *ids; 166 struct composite_context *ctx; 167 *sec = talloc(req, struct unix_sec_ctx); 168 169 /* we can't do unix security without a user and group */ 170 if (token->num_sids < 2) { 171 return NT_STATUS_ACCESS_DENIED; 172 } 173 174 ids = talloc_array(req, struct id_mapping, token->num_sids); 175 NT_STATUS_HAVE_NO_MEMORY(ids); 176 177 ids[0].unixid = NULL; 178 ids[0].sid = token->user_sid; 179 ids[0].status = NT_STATUS_NONE_MAPPED; 180 181 ids[1].unixid = NULL; 182 ids[1].sid = token->group_sid; 183 ids[1].status = NT_STATUS_NONE_MAPPED; 184 185 (*sec)->ngroups = token->num_sids - 2; 186 (*sec)->groups = talloc_array(*sec, gid_t, (*sec)->ngroups); 187 NT_STATUS_HAVE_NO_MEMORY((*sec)->groups); 188 189 for (i=0;i<(*sec)->ngroups;i++) { 190 ids[i+2].unixid = NULL; 191 ids[i+2].sid = token->sids[i+2]; 192 ids[i+2].status = NT_STATUS_NONE_MAPPED; 193 } 194 195 ctx = wbc_sids_to_xids_send(priv->wbc_ctx, ids, token->num_sids, ids); 196 NT_STATUS_HAVE_NO_MEMORY(ctx); 197 198 status = wbc_sids_to_xids_recv(ctx, &ids); 199 NT_STATUS_NOT_OK_RETURN(status); 200 201 if (ids[0].unixid->type == ID_TYPE_BOTH || 202 ids[0].unixid->type == ID_TYPE_UID) { 203 (*sec)->uid = ids[0].unixid->id; 204 } else { 205 return NT_STATUS_INVALID_SID; 206 } 207 208 if (ids[1].unixid->type == ID_TYPE_BOTH || 209 ids[1].unixid->type == ID_TYPE_GID) { 210 (*sec)->gid = ids[1].unixid->id; 211 } else { 212 return NT_STATUS_INVALID_SID; 213 } 214 215 for (i=0;i<(*sec)->ngroups;i++) { 216 if (ids[i+2].unixid->type == ID_TYPE_BOTH || 217 ids[i+2].unixid->type == ID_TYPE_GID) { 218 (*sec)->groups[i] = ids[i+2].unixid->id; 219 } else { 220 return NT_STATUS_INVALID_SID; 221 } 222 } 223 224 return NT_STATUS_OK; 225} 226 227/* 228 setup our unix security context according to the session authentication info 229*/ 230static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs, 231 struct ntvfs_request *req, struct unix_sec_ctx **sec) 232{ 233 struct unixuid_private *priv = ntvfs->private_data; 234 struct security_token *token; 235 struct unix_sec_ctx *newsec; 236 NTSTATUS status; 237 238 if (req->session_info == NULL) { 239 return NT_STATUS_ACCESS_DENIED; 240 } 241 242 token = req->session_info->security_token; 243 244 *sec = save_unix_security(ntvfs); 245 if (*sec == NULL) { 246 return NT_STATUS_NO_MEMORY; 247 } 248 249 if (token == priv->last_token) { 250 newsec = priv->last_sec_ctx; 251 } else { 252 status = nt_token_to_unix_security(ntvfs, req, token, &newsec); 253 if (!NT_STATUS_IS_OK(status)) { 254 talloc_free(*sec); 255 return status; 256 } 257 if (priv->last_sec_ctx) { 258 talloc_free(priv->last_sec_ctx); 259 } 260 priv->last_sec_ctx = newsec; 261 priv->last_token = token; 262 talloc_steal(priv, newsec); 263 } 264 265 status = set_unix_security(newsec); 266 if (!NT_STATUS_IS_OK(status)) { 267 talloc_free(*sec); 268 return status; 269 } 270 271 return NT_STATUS_OK; 272} 273 274/* 275 this pass through macro operates on request contexts 276*/ 277#define PASS_THRU_REQ(ntvfs, req, op, args) do { \ 278 NTSTATUS status2; \ 279 struct unix_sec_ctx *sec; \ 280 status = unixuid_setup_security(ntvfs, req, &sec); \ 281 NT_STATUS_NOT_OK_RETURN(status); \ 282 unixuid_nesting_level++; \ 283 status = ntvfs_next_##op args; \ 284 unixuid_nesting_level--; \ 285 status2 = set_unix_security(sec); \ 286 talloc_free(sec); \ 287 if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \ 288} while (0) 289 290 291 292/* 293 connect to a share - used when a tree_connect operation comes in. 294*/ 295static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs, 296 struct ntvfs_request *req, union smb_tcon *tcon) 297{ 298 struct unixuid_private *priv; 299 NTSTATUS status; 300 301 priv = talloc(ntvfs, struct unixuid_private); 302 if (!priv) { 303 return NT_STATUS_NO_MEMORY; 304 } 305 306 priv->wbc_ctx = wbc_init(priv, ntvfs->ctx->msg_ctx, 307 ntvfs->ctx->event_ctx); 308 if (priv->wbc_ctx == NULL) { 309 talloc_free(priv); 310 return NT_STATUS_INTERNAL_ERROR; 311 } 312 313 priv->last_sec_ctx = NULL; 314 priv->last_token = NULL; 315 ntvfs->private_data = priv; 316 317 tevent_loop_set_nesting_hook(ntvfs->ctx->event_ctx, 318 unixuid_event_nesting_hook, 319 &unixuid_nesting_level); 320 321 /* we don't use PASS_THRU_REQ here, as the connect operation runs with 322 root privileges. This allows the backends to setup any database 323 links they might need during the connect. */ 324 status = ntvfs_next_connect(ntvfs, req, tcon); 325 326 return status; 327} 328 329/* 330 disconnect from a share 331*/ 332static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs) 333{ 334 struct unixuid_private *priv = ntvfs->private_data; 335 NTSTATUS status; 336 337 talloc_free(priv); 338 ntvfs->private_data = NULL; 339 340 status = ntvfs_next_disconnect(ntvfs); 341 342 return status; 343} 344 345 346/* 347 delete a file 348*/ 349static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs, 350 struct ntvfs_request *req, 351 union smb_unlink *unl) 352{ 353 NTSTATUS status; 354 355 PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl)); 356 357 return status; 358} 359 360/* 361 ioctl interface 362*/ 363static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs, 364 struct ntvfs_request *req, union smb_ioctl *io) 365{ 366 NTSTATUS status; 367 368 PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io)); 369 370 return status; 371} 372 373/* 374 check if a directory exists 375*/ 376static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs, 377 struct ntvfs_request *req, 378 union smb_chkpath *cp) 379{ 380 NTSTATUS status; 381 382 PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp)); 383 384 return status; 385} 386 387/* 388 return info on a pathname 389*/ 390static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs, 391 struct ntvfs_request *req, union smb_fileinfo *info) 392{ 393 NTSTATUS status; 394 395 PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info)); 396 397 return status; 398} 399 400/* 401 query info on a open file 402*/ 403static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs, 404 struct ntvfs_request *req, union smb_fileinfo *info) 405{ 406 NTSTATUS status; 407 408 PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info)); 409 410 return status; 411} 412 413 414/* 415 set info on a pathname 416*/ 417static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs, 418 struct ntvfs_request *req, union smb_setfileinfo *st) 419{ 420 NTSTATUS status; 421 422 PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st)); 423 424 return status; 425} 426 427/* 428 open a file 429*/ 430static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs, 431 struct ntvfs_request *req, union smb_open *io) 432{ 433 NTSTATUS status; 434 435 PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io)); 436 437 return status; 438} 439 440/* 441 create a directory 442*/ 443static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs, 444 struct ntvfs_request *req, union smb_mkdir *md) 445{ 446 NTSTATUS status; 447 448 PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md)); 449 450 return status; 451} 452 453/* 454 remove a directory 455*/ 456static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs, 457 struct ntvfs_request *req, struct smb_rmdir *rd) 458{ 459 NTSTATUS status; 460 461 PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd)); 462 463 return status; 464} 465 466/* 467 rename a set of files 468*/ 469static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs, 470 struct ntvfs_request *req, union smb_rename *ren) 471{ 472 NTSTATUS status; 473 474 PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren)); 475 476 return status; 477} 478 479/* 480 copy a set of files 481*/ 482static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs, 483 struct ntvfs_request *req, struct smb_copy *cp) 484{ 485 NTSTATUS status; 486 487 PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp)); 488 489 return status; 490} 491 492/* 493 read from a file 494*/ 495static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs, 496 struct ntvfs_request *req, union smb_read *rd) 497{ 498 NTSTATUS status; 499 500 PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd)); 501 502 return status; 503} 504 505/* 506 write to a file 507*/ 508static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs, 509 struct ntvfs_request *req, union smb_write *wr) 510{ 511 NTSTATUS status; 512 513 PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr)); 514 515 return status; 516} 517 518/* 519 seek in a file 520*/ 521static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs, 522 struct ntvfs_request *req, 523 union smb_seek *io) 524{ 525 NTSTATUS status; 526 527 PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io)); 528 529 return status; 530} 531 532/* 533 flush a file 534*/ 535static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs, 536 struct ntvfs_request *req, 537 union smb_flush *io) 538{ 539 NTSTATUS status; 540 541 PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io)); 542 543 return status; 544} 545 546/* 547 close a file 548*/ 549static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs, 550 struct ntvfs_request *req, union smb_close *io) 551{ 552 NTSTATUS status; 553 554 PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io)); 555 556 return status; 557} 558 559/* 560 exit - closing files 561*/ 562static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs, 563 struct ntvfs_request *req) 564{ 565 NTSTATUS status; 566 567 PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req)); 568 569 return status; 570} 571 572/* 573 logoff - closing files 574*/ 575static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs, 576 struct ntvfs_request *req) 577{ 578 struct unixuid_private *priv = ntvfs->private_data; 579 NTSTATUS status; 580 581 PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req)); 582 583 priv->last_token = NULL; 584 585 return status; 586} 587 588/* 589 async setup 590*/ 591static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs, 592 struct ntvfs_request *req, 593 void *private_data) 594{ 595 NTSTATUS status; 596 597 PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data)); 598 599 return status; 600} 601 602/* 603 cancel an async request 604*/ 605static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs, 606 struct ntvfs_request *req) 607{ 608 NTSTATUS status; 609 610 PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req)); 611 612 return status; 613} 614 615/* 616 change notify 617*/ 618static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs, 619 struct ntvfs_request *req, union smb_notify *info) 620{ 621 NTSTATUS status; 622 623 PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info)); 624 625 return status; 626} 627 628/* 629 lock a byte range 630*/ 631static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs, 632 struct ntvfs_request *req, union smb_lock *lck) 633{ 634 NTSTATUS status; 635 636 PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck)); 637 638 return status; 639} 640 641/* 642 set info on a open file 643*/ 644static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs, 645 struct ntvfs_request *req, 646 union smb_setfileinfo *info) 647{ 648 NTSTATUS status; 649 650 PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info)); 651 652 return status; 653} 654 655 656/* 657 return filesystem space info 658*/ 659static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs, 660 struct ntvfs_request *req, union smb_fsinfo *fs) 661{ 662 NTSTATUS status; 663 664 PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs)); 665 666 return status; 667} 668 669/* 670 return print queue info 671*/ 672static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs, 673 struct ntvfs_request *req, union smb_lpq *lpq) 674{ 675 NTSTATUS status; 676 677 PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq)); 678 679 return status; 680} 681 682/* 683 list files in a directory matching a wildcard pattern 684*/ 685static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs, 686 struct ntvfs_request *req, union smb_search_first *io, 687 void *search_private, 688 bool (*callback)(void *, const union smb_search_data *)) 689{ 690 NTSTATUS status; 691 692 PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback)); 693 694 return status; 695} 696 697/* continue a search */ 698static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs, 699 struct ntvfs_request *req, union smb_search_next *io, 700 void *search_private, 701 bool (*callback)(void *, const union smb_search_data *)) 702{ 703 NTSTATUS status; 704 705 PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback)); 706 707 return status; 708} 709 710/* close a search */ 711static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs, 712 struct ntvfs_request *req, union smb_search_close *io) 713{ 714 NTSTATUS status; 715 716 PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io)); 717 718 return status; 719} 720 721/* SMBtrans - not used on file shares */ 722static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs, 723 struct ntvfs_request *req, struct smb_trans2 *trans2) 724{ 725 NTSTATUS status; 726 727 PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2)); 728 729 return status; 730} 731 732/* 733 initialise the unixuid backend, registering ourselves with the ntvfs subsystem 734 */ 735NTSTATUS ntvfs_unixuid_init(void) 736{ 737 NTSTATUS ret; 738 struct ntvfs_ops ops; 739 NTVFS_CURRENT_CRITICAL_SIZES(vers); 740 741 ZERO_STRUCT(ops); 742 743 /* fill in all the operations */ 744 ops.connect = unixuid_connect; 745 ops.disconnect = unixuid_disconnect; 746 ops.unlink = unixuid_unlink; 747 ops.chkpath = unixuid_chkpath; 748 ops.qpathinfo = unixuid_qpathinfo; 749 ops.setpathinfo = unixuid_setpathinfo; 750 ops.open = unixuid_open; 751 ops.mkdir = unixuid_mkdir; 752 ops.rmdir = unixuid_rmdir; 753 ops.rename = unixuid_rename; 754 ops.copy = unixuid_copy; 755 ops.ioctl = unixuid_ioctl; 756 ops.read = unixuid_read; 757 ops.write = unixuid_write; 758 ops.seek = unixuid_seek; 759 ops.flush = unixuid_flush; 760 ops.close = unixuid_close; 761 ops.exit = unixuid_exit; 762 ops.lock = unixuid_lock; 763 ops.setfileinfo = unixuid_setfileinfo; 764 ops.qfileinfo = unixuid_qfileinfo; 765 ops.fsinfo = unixuid_fsinfo; 766 ops.lpq = unixuid_lpq; 767 ops.search_first = unixuid_search_first; 768 ops.search_next = unixuid_search_next; 769 ops.search_close = unixuid_search_close; 770 ops.trans = unixuid_trans; 771 ops.logoff = unixuid_logoff; 772 ops.async_setup = unixuid_async_setup; 773 ops.cancel = unixuid_cancel; 774 ops.notify = unixuid_notify; 775 776 ops.name = "unixuid"; 777 778 /* we register under all 3 backend types, as we are not type specific */ 779 ops.type = NTVFS_DISK; 780 ret = ntvfs_register(&ops, &vers); 781 if (!NT_STATUS_IS_OK(ret)) goto failed; 782 783 ops.type = NTVFS_PRINT; 784 ret = ntvfs_register(&ops, &vers); 785 if (!NT_STATUS_IS_OK(ret)) goto failed; 786 787 ops.type = NTVFS_IPC; 788 ret = ntvfs_register(&ops, &vers); 789 if (!NT_STATUS_IS_OK(ret)) goto failed; 790 791failed: 792 return ret; 793} 794