1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Part of Very Secure FTPd 19 * Licence: GPL v2 20 * Author: Chris Evans 21 * sysdeputil.c 22 * 23 * Highly system dependent utilities - e.g. authentication, capabilities. 24 */ 25 26#include "sysdeputil.h" 27#include "str.h" 28#include "sysutil.h" 29#include "utility.h" 30#include "secbuf.h" 31#include "defs.h" 32#include "tunables.h" 33#include "builddefs.h" 34 35/* For Linux, this adds nothing :-) */ 36#include "port/porting_junk.h" 37 38#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) 39 #define _FILE_OFFSET_BITS 64 40 #define _LARGEFILE_SOURCE 1 41 #define _LARGEFILE64_SOURCE 1 42#endif 43 44/* For INT_MAX */ 45#include <limits.h> 46 47/* For fd passing */ 48#include <sys/types.h> 49#include <sys/socket.h> 50/* For FreeBSD */ 51#include <sys/param.h> 52#include <sys/uio.h> 53 54/* Configuration.. here are the possibilities */ 55#undef VSF_SYSDEP_HAVE_CAPABILITIES 56#undef VSF_SYSDEP_HAVE_SETKEEPCAPS 57#undef VSF_SYSDEP_HAVE_LINUX_SENDFILE 58#undef VSF_SYSDEP_HAVE_FREEBSD_SENDFILE 59#undef VSF_SYSDEP_HAVE_HPUX_SENDFILE 60#undef VSF_SYSDEP_HAVE_AIX_SENDFILE 61#undef VSF_SYSDEP_HAVE_SETPROCTITLE 62#undef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK 63#undef VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE 64#undef VSF_SYSDEP_HAVE_MAP_ANON 65#undef VSF_SYSDEP_NEED_OLD_FD_PASSING 66#ifdef VSF_BUILD_PAM 67 #define VSF_SYSDEP_HAVE_PAM 68#endif 69//#define VSF_SYSDEP_HAVE_SHADOW // Jiahao 70//#define VSF_SYSDEP_HAVE_USERSHELL // Jiahao 71//#define VSF_SYSDEP_HAVE_LIBCAP // Jiahao 72//#define VSF_SYSDEP_HAVE_UTMPX // Jiahao 73 74#define __USE_GNU 75//#include <utmpx.h> // Jiahao 76 77/* BEGIN config */ 78#if defined(__linux__) && !defined(__ia64__) && !defined(__s390__) 79 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK 80 #include <linux/version.h> 81 #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION) 82 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)) 83 #define VSF_SYSDEP_HAVE_CAPABILITIES 84 #define VSF_SYSDEP_HAVE_LINUX_SENDFILE 85 #include <sys/prctl.h> 86 #ifdef PR_SET_KEEPCAPS 87 #define VSF_SYSDEP_HAVE_SETKEEPCAPS 88 #endif 89 #endif 90 #endif 91#endif 92 93#if (defined(__FreeBSD__) && __FreeBSD__ >= 3) 94 #define VSF_SYSDEP_HAVE_FREEBSD_SENDFILE 95 #define VSF_SYSDEP_HAVE_SETPROCTITLE 96#endif 97 98#if defined(__NetBSD__) 99 #include <stdlib.h> 100 #define VSF_SYSDEP_HAVE_SETPROCTITLE 101 #include <sys/param.h> 102 #if __NetBSD_Version__ >= 106070000 103 #define WTMPX_FILE _PATH_WTMPX 104 #else 105 #undef VSF_SYSDEP_HAVE_UTMPX 106 #endif 107#endif 108 109#ifdef __hpux 110 #include <sys/socket.h> 111 #ifdef SF_DISCONNECT 112 #define VSF_SYSDEP_HAVE_HPUX_SENDFILE 113 #endif 114 #include <sys/param.h> 115 #include <sys/pstat.h> 116 #ifdef PSTAT_SETCMD 117 #define VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE 118 #endif 119 #undef VSF_SYSDEP_HAVE_UTMPX 120#endif 121 122#include <unistd.h> 123#include <sys/mman.h> 124#ifdef MAP_ANON 125 #define VSF_SYSDEP_HAVE_MAP_ANON 126#endif 127 128#ifdef __sgi 129 #undef VSF_SYSDEP_HAVE_USERSHELL 130 #undef VSF_SYSDEP_HAVE_LIBCAP 131#endif 132 133#ifdef _AIX 134 #undef VSF_SYSDEP_HAVE_USERSHELL 135 #undef VSF_SYSDEP_HAVE_LIBCAP 136 #undef VSF_SYSDEP_HAVE_UTMPX 137 #undef VSF_SYSDEP_HAVE_PAM 138 #undef VSF_SYSDEP_HAVE_SHADOW 139 #undef VSF_SYSDEP_HAVE_SETPROCTITLE 140 #define VSF_SYSDEP_HAVE_AIX_SENDFILE 141 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK 142 #define VSF_SYSDEP_HAVE_MAP_ANON 143#endif 144 145#ifdef __osf__ 146 #undef VSF_SYSDEP_HAVE_USERSHELL 147#endif 148 149#if (defined(__sgi) || defined(__hpux) || defined(__osf__)) 150 #define VSF_SYSDEP_NEED_OLD_FD_PASSING 151#endif 152 153#ifdef __sun 154 #define VSF_SYSDEP_HAVE_SOLARIS_SENDFILE 155#endif 156/* END config */ 157 158/* PAM support - we include our own dummy version if the system lacks this */ 159#include <security/pam_appl.h> 160 161/* No PAM? Try getspnam() with a getpwnam() fallback */ 162#ifndef VSF_SYSDEP_HAVE_PAM 163/* This may hit our own "dummy" include and undef VSF_SYSDEP_HAVE_SHADOW */ 164//#include <shadow.h> // Jiahao 165#include <pwd.h> 166#include <unistd.h> 167//#include <crypt.h> // Jiahao 168#endif 169 170/* Prefer libcap based capabilities over raw syscall capabilities */ 171#include <sys/capability.h> 172 173#if defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP) 174#include <linux/unistd.h> 175#include <linux/capability.h> 176#include <errno.h> 177#include <syscall.h> 178//_syscall2(int, capset, cap_user_header_t, header, const cap_user_data_t, data) 179/* Gross HACK to avoid warnings - linux headers overlap glibc headers */ 180#undef __NFDBITS 181#undef __FDMASK 182#endif /* VSF_SYSDEP_HAVE_CAPABILITIES */ 183 184#if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \ 185 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) 186#include <sys/sendfile.h> 187#elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) 188#include <sys/types.h> 189#include <sys/socket.h> 190#elif defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) 191#include <sys/socket.h> 192#else /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */ 193#include <unistd.h> 194#endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */ 195 196#ifdef VSF_SYSDEP_HAVE_SETPROCTITLE 197#include <sys/types.h> 198#include <unistd.h> 199#endif 200 201#ifdef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK 202extern char** environ; 203static unsigned int s_proctitle_space = 0; 204static int s_proctitle_inited = 0; 205static char* s_p_proctitle = 0; 206#endif 207 208#ifndef VSF_SYSDEP_HAVE_MAP_ANON 209#include <sys/types.h> 210#include <sys/stat.h> 211#include <fcntl.h> 212static int s_zero_fd = -1; 213#endif 214 215/* File private functions/variables */ 216static int do_sendfile(const int out_fd, const int in_fd, 217 unsigned int num_send, filesize_t start_pos); 218static void vsf_sysutil_setproctitle_internal(const char* p_text); 219static struct mystr s_proctitle_prefix_str; 220/* 221static void vsf_insert_uwtmp(const struct mystr* p_user_str, 222 const struct mystr* p_host_str); 223static void vsf_remove_uwtmp(void); 224*/ 225#ifndef VSF_SYSDEP_HAVE_PAM 226int // Jiahao 227vsf_sysdep_check_auth(const struct mystr* p_user_str, 228 const struct mystr* p_pass_str, 229 const struct mystr* p_remote_host) 230{ 231// const char* p_crypted; 232// const struct passwd* p_pwd = getpwnam(str_getbuf(p_user_str)); 233 const struct passwd* p_pwd = (struct passwd*)vsf_sysutil_getpwnam(str_getbuf(p_user_str)); 234 (void) p_remote_host; 235 if (p_pwd == NULL) 236 { 237 return 0; 238 } 239// #ifdef VSF_SYSDEP_HAVE_USERSHELL 240/* 241 if (tunable_check_shell) 242 { 243 const char* p_shell; 244 while ((p_shell = getusershell()) != NULL) 245 { 246 if (!vsf_sysutil_strcmp(p_shell, p_pwd->pw_shell)) 247 { 248 break; 249 } 250 } 251 endusershell(); 252 if (p_shell == NULL) 253 { 254 return 0; 255 } 256 } 257*/ 258// #endif 259// #ifdef VSF_SYSDEP_HAVE_SHADOW 260/* 261 { 262 const struct spwd* p_spwd = getspnam(str_getbuf(p_user_str)); 263 if (p_spwd != NULL) 264 { 265 long curr_time; 266 int days; 267 vsf_sysutil_update_cached_time(); 268 curr_time = vsf_sysutil_get_cached_time_sec(); 269 days = curr_time / (60 * 60 * 24); 270 if (p_spwd->sp_expire > 0 && p_spwd->sp_expire < days) 271 { 272 return 0; 273 } 274 if (p_spwd->sp_lstchg > 0 && p_spwd->sp_max > 0 && 275 p_spwd->sp_lstchg + p_spwd->sp_max < days) 276 { 277 return 0; 278 } 279 p_crypted = crypt(str_getbuf(p_pass_str), p_spwd->sp_pwdp); 280 if (!vsf_sysutil_strcmp(p_crypted, p_spwd->sp_pwdp)) 281 { 282 return 1; 283 } 284 } 285 } 286*/ 287// #endif /* VSF_SYSDEP_HAVE_SHADOW */ 288// p_crypted = crypt(str_getbuf(p_pass_str), p_pwd->pw_passwd); 289// if (!vsf_sysutil_strcmp(p_crypted, p_pwd->pw_passwd)) 290 if (!vsf_sysutil_strcmp(str_getbuf(p_pass_str), p_pwd->pw_passwd)) 291 { 292 return 1; 293 } 294 return 0; 295} 296 297#else /* VSF_SYSDEP_HAVE_PAM */ 298 299static pam_handle_t* s_pamh; 300static struct mystr s_pword_str; 301static int pam_conv_func(int nmsg, const struct pam_message** p_msg, 302 struct pam_response** p_reply, void* p_addata); 303static void vsf_auth_shutdown(void); 304 305int 306vsf_sysdep_check_auth(const struct mystr* p_user_str, 307 const struct mystr* p_pass_str, 308 const struct mystr* p_remote_host) 309{ 310 int retval; 311 struct pam_conv the_conv = 312 { 313 &pam_conv_func, 314 0 315 }; 316 if (s_pamh != 0) 317 { 318 bug("vsf_sysdep_check_auth"); 319 } 320 str_copy(&s_pword_str, p_pass_str); 321 retval = pam_start(tunable_pam_service_name, 322 str_getbuf(p_user_str), &the_conv, &s_pamh); 323 if (retval != PAM_SUCCESS) 324 { 325 s_pamh = 0; 326 return 0; 327 } 328#ifdef PAM_RHOST 329 retval = pam_set_item(s_pamh, PAM_RHOST, str_getbuf(p_remote_host)); 330 if (retval != PAM_SUCCESS) 331 { 332 (void) pam_end(s_pamh, 0); 333 s_pamh = 0; 334 return 0; 335 } 336#endif 337 retval = pam_authenticate(s_pamh, 0); 338 if (retval != PAM_SUCCESS) 339 { 340 (void) pam_end(s_pamh, 0); 341 s_pamh = 0; 342 return 0; 343 } 344 retval = pam_acct_mgmt(s_pamh, 0); 345 if (retval != PAM_SUCCESS) 346 { 347 (void) pam_end(s_pamh, 0); 348 s_pamh = 0; 349 return 0; 350 } 351 retval = pam_setcred(s_pamh, PAM_ESTABLISH_CRED); 352 if (retval != PAM_SUCCESS) 353 { 354 (void) pam_end(s_pamh, 0); 355 s_pamh = 0; 356 return 0; 357 } 358 if (!tunable_session_support) 359 { 360 /* You're in already! */ 361 (void) pam_end(s_pamh, 0); 362 s_pamh = 0; 363 return 1; 364 } 365 /* Must do this BEFORE opening a session for pam_limits to count us */ 366 vsf_insert_uwtmp(p_user_str, p_remote_host); 367 retval = pam_open_session(s_pamh, 0); 368 if (retval != PAM_SUCCESS) 369 { 370 vsf_remove_uwtmp(); 371 (void) pam_setcred(s_pamh, PAM_DELETE_CRED); 372 (void) pam_end(s_pamh, 0); 373 s_pamh = 0; 374 return 0; 375 } 376 /* We MUST ensure the PAM session, utmp, wtmp etc. are cleaned up, however 377 * we exit. 378 */ 379 vsf_sysutil_set_exit_func(vsf_auth_shutdown); 380 /* You're in dude */ 381 return 1; 382} 383 384static void 385vsf_auth_shutdown(void) 386{ 387 if (s_pamh == 0) 388 { 389 bug("vsf_auth_shutdown"); 390 } 391 (void) pam_close_session(s_pamh, 0); 392 (void) pam_setcred(s_pamh, PAM_DELETE_CRED); 393 (void) pam_end(s_pamh, 0); 394 s_pamh = 0; 395 vsf_remove_uwtmp(); 396} 397 398static int 399pam_conv_func(int nmsg, const struct pam_message** p_msg, 400 struct pam_response** p_reply, void* p_addata) 401{ 402 int i; 403 struct pam_response* p_resps = 0; 404 (void) p_addata; 405 if (nmsg < 0) 406 { 407 bug("dodgy nmsg in pam_conv_func"); 408 } 409 p_resps = vsf_sysutil_malloc(sizeof(struct pam_response) * nmsg); 410 for (i=0; i<nmsg; i++) 411 { 412 switch (p_msg[i]->msg_style) 413 { 414 case PAM_PROMPT_ECHO_OFF: 415 p_resps[i].resp_retcode = PAM_SUCCESS; 416 p_resps[i].resp = (char*) str_strdup(&s_pword_str); 417 break; 418 case PAM_TEXT_INFO: 419 case PAM_ERROR_MSG: 420 p_resps[i].resp_retcode = PAM_SUCCESS; 421 p_resps[i].resp = 0; 422 break; 423 case PAM_PROMPT_ECHO_ON: 424 default: 425 vsf_sysutil_free(p_resps); 426 return PAM_CONV_ERR; 427 break; 428 } 429 } 430 *p_reply = p_resps; 431 return PAM_SUCCESS; 432} 433 434#endif /* VSF_SYSDEP_HAVE_PAM */ 435 436/* Capabilities support (or lack thereof) */ 437void 438vsf_sysdep_keep_capabilities(void) 439{ 440 if (!vsf_sysdep_has_capabilities_as_non_root()) 441 { 442 bug("asked to keep capabilities, but no support exists"); 443 } 444#ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS 445 { 446 int retval = prctl(PR_SET_KEEPCAPS, 1); 447 if (vsf_sysutil_retval_is_error(retval)) 448 { 449 die("prctl"); 450 } 451 } 452#endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */ 453} 454#if !defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP) 455 456int 457vsf_sysdep_has_capabilities(void) 458{ 459 return 0; 460} 461 462int 463vsf_sysdep_has_capabilities_as_non_root(void) 464{ 465 return 0; 466} 467 468void 469vsf_sysdep_adopt_capabilities(unsigned int caps) 470{ 471 (void) caps; 472 bug("asked to adopt capabilities, but no support exists"); 473} 474 475#else /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */ 476 477static int do_checkcap(void); 478 479int 480vsf_sysdep_has_capabilities_as_non_root(void) 481{ 482 static int s_prctl_checked; 483 static int s_runtime_prctl_works; 484 if (!s_prctl_checked) 485 { 486 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS 487 /* Clarity: note embedded call to prctl() syscall */ 488 if (!vsf_sysutil_retval_is_error(prctl(PR_SET_KEEPCAPS, 0))) 489 { 490 s_runtime_prctl_works = 1; 491 } 492 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */ 493 s_prctl_checked = 1; 494 } 495 return s_runtime_prctl_works; 496} 497 498int 499vsf_sysdep_has_capabilities(void) 500{ 501 /* Even though compiled with capabilities, the runtime system may lack them. 502 * Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel! 503 */ 504 static int s_caps_checked; 505 static int s_runtime_has_caps; 506 if (!s_caps_checked) 507 { 508 s_runtime_has_caps = do_checkcap(); 509 s_caps_checked = 1; 510 } 511 return s_runtime_has_caps; 512} 513 514 #ifndef VSF_SYSDEP_HAVE_LIBCAP 515static int 516do_checkcap(void) 517{ 518 /* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */ 519 int retval = capset(0, 0); 520 if (!vsf_sysutil_retval_is_error(retval) || 521 vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS) 522 { 523 return 1; 524 } 525 return 0; 526} 527 528void 529vsf_sysdep_adopt_capabilities(unsigned int caps) 530{ 531 /* n.b. yes I know I should be using libcap!! */ 532 int retval; 533 struct __user_cap_header_struct cap_head; 534 struct __user_cap_data_struct cap_data; 535 __u32 cap_mask = 0; 536 if (!caps) 537 { 538 bug("asked to adopt no capabilities"); 539 } 540 vsf_sysutil_memclr(&cap_head, sizeof(cap_head)); 541 vsf_sysutil_memclr(&cap_data, sizeof(cap_data)); 542 cap_head.version = _LINUX_CAPABILITY_VERSION; 543 cap_head.pid = 0; 544 if (caps & kCapabilityCAP_CHOWN) 545 { 546 cap_mask |= (1 << CAP_CHOWN); 547 } 548 if (caps & kCapabilityCAP_NET_BIND_SERVICE) 549 { 550 cap_mask |= (1 << CAP_NET_BIND_SERVICE); 551 } 552 cap_data.effective = cap_data.permitted = cap_mask; 553 cap_data.inheritable = 0; 554 retval = capset(&cap_head, &cap_data); 555 if (retval != 0) 556 { 557 die("capset"); 558 } 559} 560 561 #else /* VSF_SYSDEP_HAVE_LIBCAP */ 562static int 563do_checkcap(void) 564{ 565 cap_t current_caps = cap_get_proc(); 566 cap_free(current_caps); 567 if (current_caps != NULL) 568 { 569 return 1; 570 } 571 return 0; 572} 573 574void 575vsf_sysdep_adopt_capabilities(unsigned int caps) 576{ 577 int retval; 578 cap_value_t cap_value; 579 cap_t adopt_caps = cap_init(); 580 if (caps & kCapabilityCAP_CHOWN) 581 { 582 cap_value = CAP_CHOWN; 583 cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET); 584 cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET); 585 } 586 if (caps & kCapabilityCAP_NET_BIND_SERVICE) 587 { 588 cap_value = CAP_NET_BIND_SERVICE; 589 cap_set_flag(adopt_caps, CAP_EFFECTIVE, 1, &cap_value, CAP_SET); 590 cap_set_flag(adopt_caps, CAP_PERMITTED, 1, &cap_value, CAP_SET); 591 } 592 retval = cap_set_proc(adopt_caps); 593 if (retval != 0) 594 { 595 die("cap_set_proc"); 596 } 597 cap_free(adopt_caps); 598} 599 600 #endif /* !VSF_SYSDEP_HAVE_LIBCAP */ 601#endif /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */ 602 603int 604vsf_sysutil_sendfile(const int out_fd, const int in_fd, 605 filesize_t* p_offset, filesize_t num_send, 606 unsigned int max_chunk) 607{ 608 /* Grr - why is off_t signed? */ 609 if (*p_offset < 0 || num_send < 0) 610 { 611 die("invalid offset or send count in vsf_sysutil_sendfile"); 612 } 613 if (max_chunk == 0) 614 { 615 max_chunk = INT_MAX; 616 } 617 while (num_send > 0) 618 { 619 int retval; 620 unsigned int send_this_time; 621 if (num_send > max_chunk) 622 { 623 send_this_time = max_chunk; 624 } 625 else 626 { 627 send_this_time = (unsigned int) num_send; 628 } 629 /* Keep input file position in line with sendfile() calls */ 630 vsf_sysutil_lseek_to(in_fd, *p_offset); 631 retval = do_sendfile(out_fd, in_fd, send_this_time, *p_offset); 632 if (vsf_sysutil_retval_is_error(retval) || retval == 0) 633 { 634 return retval; 635 } 636 num_send -= retval; 637 *p_offset += retval; 638 } 639 return 0; 640} 641 642static int do_sendfile(const int out_fd, const int in_fd, 643 unsigned int num_send, filesize_t start_pos) 644{ 645 /* Probably should one day be shared with instance in ftpdataio.c */ 646 static char* p_recvbuf; 647 unsigned int total_written = 0; 648 int retval; 649 enum EVSFSysUtilError error; 650 (void) start_pos; 651#if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \ 652 defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \ 653 defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \ 654 defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \ 655 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) 656 if (tunable_use_sendfile) 657 { 658 static int s_sendfile_checked; 659 static int s_runtime_sendfile_works; 660 if (!s_sendfile_checked || s_runtime_sendfile_works) 661 { 662 do 663 { 664 #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE 665 retval = sendfile(out_fd, in_fd, NULL, num_send); 666 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) 667 { 668 /* XXX - start_pos will truncate on 32-bit machines - can we 669 * say "start from current pos"? 670 */ 671 off_t written = 0; 672 retval = sendfile(in_fd, out_fd, start_pos, num_send, NULL, 673 &written, 0); 674 /* Translate to Linux-like retval */ 675 if (written > 0) 676 { 677 retval = (int) written; 678 } 679 } 680 #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE) 681 { 682 size_t written = 0; 683 struct sendfilevec the_vec; 684 vsf_sysutil_memclr(&the_vec, sizeof(the_vec)); 685 the_vec.sfv_fd = in_fd; 686 the_vec.sfv_off = start_pos; 687 the_vec.sfv_len = num_send; 688 retval = sendfilev(out_fd, &the_vec, 1, &written); 689 /* Translate to Linux-like retval */ 690 if (written > 0) 691 { 692 retval = (int) written; 693 } 694 } 695 #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) 696 { 697 struct sf_parms sf_iobuf; 698 vsf_sysutil_memclr(&sf_iobuf, sizeof(sf_iobuf)); 699 sf_iobuf.header_data = NULL; 700 sf_iobuf.header_length = 0; 701 sf_iobuf.trailer_data = NULL; 702 sf_iobuf.trailer_length = 0; 703 sf_iobuf.file_descriptor = in_fd; 704 sf_iobuf.file_offset = start_pos; 705 sf_iobuf.file_bytes = num_send; 706 707 retval = send_file((int*)&out_fd, &sf_iobuf, 0); 708 if (retval >= 0) 709 { 710 retval = sf_iobuf.bytes_sent; 711 } 712 } 713 #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */ 714 { 715 retval = sendfile(out_fd, in_fd, start_pos, num_send, NULL, 0); 716 } 717 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */ 718 error = vsf_sysutil_get_error(); 719 vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, out_fd); 720 } 721 while (vsf_sysutil_retval_is_error(retval) && 722 error == kVSFSysUtilErrINTR); 723 if (!s_sendfile_checked) 724 { 725 s_sendfile_checked = 1; 726 if (!vsf_sysutil_retval_is_error(retval) || 727 error != kVSFSysUtilErrNOSYS) 728 { 729 s_runtime_sendfile_works = 1; 730 } 731 } 732 if (!vsf_sysutil_retval_is_error(retval)) 733 { 734 return retval; 735 } 736 if (s_runtime_sendfile_works && error != kVSFSysUtilErrINVAL && 737 error != kVSFSysUtilErrOPNOTSUPP) 738 { 739 return retval; 740 } 741 /* Fall thru to normal implementation. We won't check again. NOTE - 742 * also falls through if sendfile() is OK but it returns EINVAL. For 743 * Linux this means the file was not page cache backed. Original 744 * complaint was trying to serve files from an NTFS filesystem! 745 */ 746 } 747 } 748#endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */ 749 if (p_recvbuf == 0) 750 { 751 vsf_secbuf_alloc(&p_recvbuf, VSFTP_DATA_BUFSIZE); 752 } 753 while (1) 754 { 755 unsigned int num_read; 756 unsigned int num_written; 757 unsigned int num_read_this_time = VSFTP_DATA_BUFSIZE; 758 if (num_read_this_time > num_send) 759 { 760 num_read_this_time = num_send; 761 } 762 retval = vsf_sysutil_read(in_fd, p_recvbuf, num_read_this_time); 763 if (retval < 0) 764 { 765 return retval; 766 } 767 else if (retval == 0) 768 { 769 return -1; 770 } 771 num_read = (unsigned int) retval; 772 retval = vsf_sysutil_write_loop(out_fd, p_recvbuf, num_read); 773 if (retval < 0) 774 { 775 return retval; 776 } 777 num_written = (unsigned int) retval; 778 total_written += num_written; 779 if (num_written != num_read) 780 { 781 return num_written; 782 } 783 if (num_written > num_send) 784 { 785 bug("num_written bigger than num_send in do_sendfile"); 786 } 787 num_send -= num_written; 788 if (num_send == 0) 789 { 790 /* Bingo! */ 791 return total_written; 792 } 793 } 794} 795 796void 797vsf_sysutil_set_proctitle_prefix(const struct mystr* p_str) 798{ 799 str_copy(&s_proctitle_prefix_str, p_str); 800} 801 802/* This delegation is common to all setproctitle() implementations */ 803void 804vsf_sysutil_setproctitle_str(const struct mystr* p_str) 805{ 806 vsf_sysutil_setproctitle(str_getbuf(p_str)); 807} 808 809void 810vsf_sysutil_setproctitle(const char* p_text) 811{ 812 struct mystr proctitle_str = INIT_MYSTR; 813 str_copy(&proctitle_str, &s_proctitle_prefix_str); 814 if (!str_isempty(&proctitle_str)) 815 { 816 str_append_text(&proctitle_str, ": "); 817 } 818 str_append_text(&proctitle_str, p_text); 819 vsf_sysutil_setproctitle_internal(str_getbuf(&proctitle_str)); 820 str_free(&proctitle_str); 821} 822 823#ifdef VSF_SYSDEP_HAVE_SETPROCTITLE 824void 825vsf_sysutil_setproctitle_init(int argc, const char* argv[]) 826{ 827 (void) argc; 828 (void) argv; 829} 830 831void 832vsf_sysutil_setproctitle_internal(const char* p_buf) 833{ 834 setproctitle("%s", p_buf); 835} 836#elif defined(VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE) 837void 838vsf_sysutil_setproctitle_init(int argc, const char* argv[]) 839{ 840 (void) argc; 841 (void) argv; 842} 843 844void 845vsf_sysutil_setproctitle_internal(const char* p_buf) 846{ 847 struct mystr proctitle_str = INIT_MYSTR; 848 union pstun p; 849 str_alloc_text(&proctitle_str, "vsftpd: "); 850 str_append_text(&proctitle_str, p_buf); 851 p.pst_command = str_getbuf(&proctitle_str); 852 pstat(PSTAT_SETCMD, p, 0, 0, 0); 853 str_free(&proctitle_str); 854} 855#elif defined(VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK) 856void 857vsf_sysutil_setproctitle_init(int argc, const char* argv[]) 858{ 859 int i; 860 char** p_env = environ; 861 if (s_proctitle_inited) 862 { 863 bug("vsf_sysutil_setproctitle_init called twice"); 864 } 865 s_proctitle_inited = 1; 866 if (argv[0] == 0) 867 { 868 die("no argv[0] in vsf_sysutil_setproctitle_init"); 869 } 870 for (i=0; i<argc; i++) 871 { 872 s_proctitle_space += vsf_sysutil_strlen(argv[i]) + 1; 873 if (i > 0) 874 { 875 argv[i] = 0; 876 } 877 } 878 while (*p_env != 0) 879 { 880 s_proctitle_space += vsf_sysutil_strlen(*p_env) + 1; 881 p_env++; 882 } 883 /* Oops :-) */ 884 environ = 0; 885 s_p_proctitle = (char*) argv[0]; 886 vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space); 887} 888 889void 890vsf_sysutil_setproctitle_internal(const char* p_buf) 891{ 892 struct mystr proctitle_str = INIT_MYSTR; 893 unsigned int to_copy; 894 if (!s_proctitle_inited) 895 { 896 bug("vsf_sysutil_setproctitle: not initialized"); 897 } 898 vsf_sysutil_memclr(s_p_proctitle, s_proctitle_space); 899 if (s_proctitle_space < 32) 900 { 901 return; 902 } 903 str_alloc_text(&proctitle_str, "vsftpd: "); 904 str_append_text(&proctitle_str, p_buf); 905 to_copy = str_getlen(&proctitle_str); 906 if (to_copy > s_proctitle_space - 1) 907 { 908 to_copy = s_proctitle_space - 1; 909 } 910 vsf_sysutil_memcpy(s_p_proctitle, str_getbuf(&proctitle_str), to_copy); 911 str_free(&proctitle_str); 912 s_p_proctitle[to_copy] = '\0'; 913} 914#else /* VSF_SYSDEP_HAVE_SETPROCTITLE */ 915void 916vsf_sysutil_setproctitle_init(int argc, const char* argv[]) 917{ 918 (void) argc; 919 (void) argv; 920} 921 922void 923vsf_sysutil_setproctitle_internal(const char* p_buf) 924{ 925 (void) p_buf; 926} 927#endif /* VSF_SYSDEP_HAVE_SETPROCTITLE */ 928 929#ifdef VSF_SYSDEP_HAVE_MAP_ANON 930void 931vsf_sysutil_map_anon_pages_init(void) 932{ 933} 934 935void* 936vsf_sysutil_map_anon_pages(unsigned int length) 937{ 938 char* retval = mmap(0, length, PROT_READ | PROT_WRITE, 939 MAP_PRIVATE | MAP_ANON, -1, 0); 940 if (retval == MAP_FAILED) 941 { 942 die("mmap"); 943 } 944 return retval; 945} 946#else /* VSF_SYSDEP_HAVE_MAP_ANON */ 947void 948vsf_sysutil_map_anon_pages_init(void) 949{ 950 if (s_zero_fd != -1) 951 { 952 bug("vsf_sysutil_map_anon_pages_init called twice"); 953 } 954 s_zero_fd = open("/dev/zero", O_RDWR); 955 if (s_zero_fd < 0) 956 { 957 die("could not open /dev/zero"); 958 } 959} 960 961void* 962vsf_sysutil_map_anon_pages(unsigned int length) 963{ 964 char* retval = mmap(0, length, PROT_READ | PROT_WRITE, 965 MAP_PRIVATE, s_zero_fd, 0); 966 if (retval == MAP_FAILED) 967 { 968 die("mmap"); 969 } 970 return retval; 971} 972#endif /* VSF_SYSDEP_HAVE_MAP_ANON */ 973 974#ifndef VSF_SYSDEP_NEED_OLD_FD_PASSING 975 976void 977vsf_sysutil_send_fd(int sock_fd, int send_fd) 978{ 979 int retval; 980 struct msghdr msg; 981 struct cmsghdr* p_cmsg; 982 struct iovec vec; 983 char cmsgbuf[CMSG_SPACE(sizeof(send_fd))]; 984 int* p_fds; 985 char sendchar = 0; 986 msg.msg_control = cmsgbuf; 987 msg.msg_controllen = sizeof(cmsgbuf); 988 p_cmsg = CMSG_FIRSTHDR(&msg); 989 p_cmsg->cmsg_level = SOL_SOCKET; 990 p_cmsg->cmsg_type = SCM_RIGHTS; 991 p_cmsg->cmsg_len = CMSG_LEN(sizeof(send_fd)); 992 p_fds = (int*)CMSG_DATA(p_cmsg); 993 *p_fds = send_fd; 994 msg.msg_controllen = p_cmsg->cmsg_len; 995 msg.msg_name = NULL; 996 msg.msg_namelen = 0; 997 msg.msg_iov = &vec; 998 msg.msg_iovlen = 1; 999 msg.msg_flags = 0; 1000 /* "To pass file descriptors or credentials you need to send/read at 1001 * least on byte" (man 7 unix) 1002 */ 1003 vec.iov_base = &sendchar; 1004 vec.iov_len = sizeof(sendchar); 1005 retval = sendmsg(sock_fd, &msg, 0); 1006 if (retval != 1) 1007 { 1008 die("sendmsg"); 1009 } 1010} 1011 1012int 1013vsf_sysutil_recv_fd(const int sock_fd) 1014{ 1015 int retval; 1016 struct msghdr msg; 1017 char recvchar; 1018 struct iovec vec; 1019 int recv_fd; 1020 char cmsgbuf[CMSG_SPACE(sizeof(recv_fd))]; 1021 struct cmsghdr* p_cmsg; 1022 int* p_fd; 1023 vec.iov_base = &recvchar; 1024 vec.iov_len = sizeof(recvchar); 1025 msg.msg_name = NULL; 1026 msg.msg_namelen = 0; 1027 msg.msg_iov = &vec; 1028 msg.msg_iovlen = 1; 1029 msg.msg_control = cmsgbuf; 1030 msg.msg_controllen = sizeof(cmsgbuf); 1031 msg.msg_flags = 0; 1032 /* In case something goes wrong, set the fd to -1 before the syscall */ 1033 p_fd = (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg)); 1034 *p_fd = -1; 1035 retval = recvmsg(sock_fd, &msg, 0); 1036 if (retval != 1) 1037 { 1038 die("recvmsg"); 1039 } 1040 p_cmsg = CMSG_FIRSTHDR(&msg); 1041 if (p_cmsg == NULL) 1042 { 1043 die("no passed fd"); 1044 } 1045 /* We used to verify the returned cmsg_level, cmsg_type and cmsg_len here, 1046 * but Linux 2.0 totally uselessly fails to fill these in. 1047 */ 1048 p_fd = (int*)CMSG_DATA(p_cmsg); 1049 recv_fd = *p_fd; 1050 if (recv_fd == -1) 1051 { 1052 die("no passed fd"); 1053 } 1054 return recv_fd; 1055} 1056 1057#else /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */ 1058 1059void 1060vsf_sysutil_send_fd(int sock_fd, int send_fd) 1061{ 1062 int retval; 1063 char send_char = 0; 1064 struct msghdr msg; 1065 struct iovec vec; 1066 vec.iov_base = &send_char; 1067 vec.iov_len = 1; 1068 msg.msg_name = NULL; 1069 msg.msg_namelen = 0; 1070 msg.msg_iov = &vec; 1071 msg.msg_iovlen = 1; 1072 msg.msg_accrights = (caddr_t) &send_fd; 1073 msg.msg_accrightslen = sizeof(send_fd); 1074 retval = sendmsg(sock_fd, &msg, 0); 1075 if (retval != 1) 1076 { 1077 die("sendmsg"); 1078 } 1079} 1080 1081int 1082vsf_sysutil_recv_fd(int sock_fd) 1083{ 1084 int retval; 1085 struct msghdr msg; 1086 struct iovec vec; 1087 char recv_char; 1088 int recv_fd = -1; 1089 vec.iov_base = &recv_char; 1090 vec.iov_len = 1; 1091 msg.msg_name = NULL; 1092 msg.msg_namelen = 0; 1093 msg.msg_iov = &vec; 1094 msg.msg_iovlen = 1; 1095 msg.msg_accrights = (caddr_t) &recv_fd; 1096 msg.msg_accrightslen = sizeof(recv_fd); 1097 retval = recvmsg(sock_fd, &msg, 0); 1098 if (retval != 1) 1099 { 1100 die("recvmsg"); 1101 } 1102 if (recv_fd == -1) 1103 { 1104 die("no passed fd"); 1105 } 1106 return recv_fd; 1107} 1108 1109#endif /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */ 1110 1111#ifndef VSF_SYSDEP_HAVE_UTMPX 1112/* 1113static void 1114vsf_insert_uwtmp(const struct mystr* p_user_str, 1115 const struct mystr* p_host_str) 1116{ 1117 (void) p_user_str; 1118 (void) p_host_str; 1119} 1120 1121static void 1122vsf_remove_uwtmp(void) 1123{ 1124} 1125*/ 1126#else /* !VSF_SYSDEP_HAVE_UTMPX */ 1127 1128/* IMHO, the pam_unix module REALLY should be doing this in its SM component */ 1129/* Statics */ 1130 1131static int s_uwtmp_inserted; 1132static struct utmpx s_utent; 1133 1134static void 1135vsf_insert_uwtmp(const struct mystr* p_user_str, 1136 const struct mystr* p_host_str) 1137{ 1138 if (sizeof(s_utent.ut_line) < 16) 1139 { 1140 return; 1141 } 1142 if (s_uwtmp_inserted) 1143 { 1144 bug("vsf_insert_uwtmp"); 1145 } 1146 { 1147 struct mystr line_str = INIT_MYSTR; 1148 str_alloc_text(&line_str, "vsftpd:"); 1149 str_append_ulong(&line_str, vsf_sysutil_getpid()); 1150 if (str_getlen(&line_str) >= sizeof(s_utent.ut_line)) 1151 { 1152 str_free(&line_str); 1153 return; 1154 } 1155 vsf_sysutil_strcpy(s_utent.ut_line, str_getbuf(&line_str), 1156 sizeof(s_utent.ut_line)); 1157 str_free(&line_str); 1158 } 1159 s_uwtmp_inserted = 1; 1160 s_utent.ut_type = USER_PROCESS; 1161 s_utent.ut_pid = vsf_sysutil_getpid(); 1162 vsf_sysutil_strcpy(s_utent.ut_user, str_getbuf(p_user_str), 1163 sizeof(s_utent.ut_user)); 1164 vsf_sysutil_strcpy(s_utent.ut_host, str_getbuf(p_host_str), 1165 sizeof(s_utent.ut_host)); 1166 vsf_sysutil_update_cached_time(); 1167 s_utent.ut_tv.tv_sec = vsf_sysutil_get_cached_time_sec(); 1168 setutxent(); 1169 (void) pututxline(&s_utent); 1170 endutxent(); 1171 updwtmpx(WTMPX_FILE, &s_utent); 1172} 1173 1174static void 1175vsf_remove_uwtmp(void) 1176{ 1177 if (!s_uwtmp_inserted) 1178 { 1179 return; 1180 } 1181 s_uwtmp_inserted = 0; 1182 s_utent.ut_type = DEAD_PROCESS; 1183 vsf_sysutil_memclr(s_utent.ut_user, sizeof(s_utent.ut_user)); 1184 vsf_sysutil_memclr(s_utent.ut_host, sizeof(s_utent.ut_host)); 1185 s_utent.ut_tv.tv_sec = 0; 1186 setutxent(); 1187 (void) pututxline(&s_utent); 1188 endutxent(); 1189 vsf_sysutil_update_cached_time(); 1190 s_utent.ut_tv.tv_sec = vsf_sysutil_get_cached_time_sec(); 1191 updwtmpx(WTMPX_FILE, &s_utent); 1192} 1193#endif /* !VSF_SYSDEP_HAVE_UTMPX */ 1194 1195