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