2 * Part of Very Secure FTPd
7 * Highly system dependent utilities - e.g. authentication, capabilities.
10 #include "sysdeputil.h"
17 #include "builddefs.h"
19 /* For Linux, this adds nothing :-) */
20 #include "port/porting_junk.h"
22 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
23 #define _FILE_OFFSET_BITS 64
24 #define _LARGEFILE_SOURCE 1
25 #define _LARGEFILE64_SOURCE 1
32 #include <sys/types.h>
33 #include <sys/socket.h>
35 #include <sys/param.h>
38 #include <sys/prctl.h>
41 /* Configuration.. here are the possibilities */
42 #undef VSF_SYSDEP_HAVE_CAPABILITIES
43 #undef VSF_SYSDEP_HAVE_SETKEEPCAPS
44 #undef VSF_SYSDEP_HAVE_SETPDEATHSIG
45 #undef VSF_SYSDEP_HAVE_LINUX_SENDFILE
46 #undef VSF_SYSDEP_HAVE_FREEBSD_SENDFILE
47 #undef VSF_SYSDEP_HAVE_HPUX_SENDFILE
48 #undef VSF_SYSDEP_HAVE_AIX_SENDFILE
49 #undef VSF_SYSDEP_HAVE_SETPROCTITLE
50 #undef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
51 #undef VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
52 #undef VSF_SYSDEP_HAVE_MAP_ANON
53 #undef VSF_SYSDEP_NEED_OLD_FD_PASSING
54 #undef VSF_SYSDEP_HAVE_LINUX_CLONE
56 #define VSF_SYSDEP_HAVE_PAM
58 #define VSF_SYSDEP_HAVE_SHADOW
59 #define VSF_SYSDEP_HAVE_USERSHELL
60 #define VSF_SYSDEP_HAVE_LIBCAP
61 #define VSF_SYSDEP_HAVE_UTMPX
67 #if defined(__linux__)
70 #define VSF_SYSDEP_HAVE_LINUX_CLONE
73 #define CLONE_NEWPID 0x20000000
76 #define CLONE_NEWIPC 0x08000000
79 #define CLONE_NEWNET 0x40000000
81 #include <linux/unistd.h>
86 #if defined(__linux__) && !defined(__ia64__) && !defined(__s390__)
87 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
88 #include <linux/version.h>
89 #if defined(LINUX_VERSION_CODE) && defined(KERNEL_VERSION)
90 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0))
91 #define VSF_SYSDEP_HAVE_CAPABILITIES
92 #define VSF_SYSDEP_HAVE_LINUX_SENDFILE
93 #ifdef PR_SET_KEEPCAPS
94 #define VSF_SYSDEP_HAVE_SETKEEPCAPS
96 #ifdef PR_SET_PDEATHSIG
97 #define VSF_SYSDEP_HAVE_SETPDEATHSIG
103 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
104 #define VSF_SYSDEP_HAVE_FREEBSD_SENDFILE
105 #define VSF_SYSDEP_HAVE_SETPROCTITLE
108 #if defined(__NetBSD__)
110 #define VSF_SYSDEP_HAVE_SETPROCTITLE
111 #include <sys/param.h>
112 #if __NetBSD_Version__ >= 106070000
113 #define WTMPX_FILE _PATH_WTMPX
115 #undef VSF_SYSDEP_HAVE_UTMPX
120 #include <sys/socket.h>
122 #define VSF_SYSDEP_HAVE_HPUX_SENDFILE
124 #include <sys/param.h>
125 #include <sys/pstat.h>
127 #define VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
129 #undef VSF_SYSDEP_HAVE_UTMPX
133 #include <sys/mman.h>
135 #define VSF_SYSDEP_HAVE_MAP_ANON
139 #undef VSF_SYSDEP_HAVE_USERSHELL
140 #undef VSF_SYSDEP_HAVE_LIBCAP
144 #undef VSF_SYSDEP_HAVE_USERSHELL
145 #undef VSF_SYSDEP_HAVE_LIBCAP
146 #undef VSF_SYSDEP_HAVE_UTMPX
147 #undef VSF_SYSDEP_HAVE_PAM
148 #undef VSF_SYSDEP_HAVE_SHADOW
149 #undef VSF_SYSDEP_HAVE_SETPROCTITLE
150 #define VSF_SYSDEP_HAVE_AIX_SENDFILE
151 #define VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
152 #define VSF_SYSDEP_HAVE_MAP_ANON
156 #undef VSF_SYSDEP_HAVE_USERSHELL
159 #if (defined(__sgi) || defined(__hpux) || defined(__osf__))
160 #define VSF_SYSDEP_NEED_OLD_FD_PASSING
164 #define VSF_SYSDEP_HAVE_SOLARIS_SENDFILE
168 /* PAM support - we include our own dummy version if the system lacks this */
169 #include <security/pam_appl.h>
171 /* No PAM? Try getspnam() with a getpwnam() fallback */
172 #ifndef VSF_SYSDEP_HAVE_PAM
173 /* This may hit our own "dummy" include and undef VSF_SYSDEP_HAVE_SHADOW */
180 /* Prefer libcap based capabilities over raw syscall capabilities */
181 #include <sys/capability.h>
183 #if defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
184 #include <linux/unistd.h>
185 #include <linux/capability.h>
188 int capset(cap_user_header_t header
, const cap_user_data_t data
)
190 return syscall(__NR_capset
, header
, data
);
192 /* Gross HACK to avoid warnings - linux headers overlap glibc headers */
195 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES */
197 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
198 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
199 #include <sys/sendfile.h>
200 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
201 #include <sys/types.h>
202 #include <sys/socket.h>
203 #elif defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE)
204 #include <sys/socket.h>
205 #else /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
207 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
209 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
210 #include <sys/types.h>
214 #ifdef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
215 extern char** environ
;
216 static unsigned int s_proctitle_space
= 0;
217 static int s_proctitle_inited
= 0;
218 static char* s_p_proctitle
= 0;
221 #ifndef VSF_SYSDEP_HAVE_MAP_ANON
222 #include <sys/types.h>
223 #include <sys/stat.h>
225 static int s_zero_fd
= -1;
228 /* File private functions/variables */
229 static int do_sendfile(const int out_fd
, const int in_fd
,
230 unsigned int num_send
, filesize_t start_pos
);
231 static void vsf_sysutil_setproctitle_internal(const char* p_text
);
232 static struct mystr s_proctitle_prefix_str
;
234 /* These two aren't static to avoid OpenBSD build warnings. */
235 void vsf_insert_uwtmp(const struct mystr
* p_user_str
,
236 const struct mystr
* p_host_str
);
237 void vsf_remove_uwtmp(void);
239 #ifndef VSF_SYSDEP_HAVE_PAM
241 vsf_sysdep_check_auth(struct mystr
* p_user_str
,
242 const struct mystr
* p_pass_str
,
243 const struct mystr
* p_remote_host
)
245 const char* p_crypted
;
246 const struct passwd
* p_pwd
= getpwnam(str_getbuf(p_user_str
));
247 (void) p_remote_host
;
252 #ifdef VSF_SYSDEP_HAVE_USERSHELL
253 if (tunable_check_shell
)
256 while ((p_shell
= getusershell()) != NULL
)
258 if (!vsf_sysutil_strcmp(p_shell
, p_pwd
->pw_shell
))
270 #ifdef VSF_SYSDEP_HAVE_SHADOW
272 const struct spwd
* p_spwd
= getspnam(str_getbuf(p_user_str
));
275 long curr_time
= vsf_sysutil_get_time_sec();
277 days
= curr_time
/ (60 * 60 * 24);
278 if (p_spwd
->sp_expire
> 0 && p_spwd
->sp_expire
< days
)
282 if (p_spwd
->sp_lstchg
> 0 && p_spwd
->sp_max
> 0 &&
283 p_spwd
->sp_lstchg
+ p_spwd
->sp_max
< days
)
287 p_crypted
= crypt(str_getbuf(p_pass_str
), p_spwd
->sp_pwdp
);
288 if (!vsf_sysutil_strcmp(p_crypted
, p_spwd
->sp_pwdp
))
294 #endif /* VSF_SYSDEP_HAVE_SHADOW */
295 p_crypted
= crypt(str_getbuf(p_pass_str
), p_pwd
->pw_passwd
);
296 if (!vsf_sysutil_strcmp(p_crypted
, p_pwd
->pw_passwd
))
303 #else /* VSF_SYSDEP_HAVE_PAM */
305 #if (defined(__sun) || defined(__hpux)) && \
306 !defined(LINUX_PAM) && !defined(_OPENPAM)
307 /* Sun's PAM doesn't use const here, while Linux-PAM and OpenPAM do */
310 #define lo_const const
312 typedef lo_const
void* pam_item_t
;
314 static pam_handle_t
* s_pamh
;
315 static struct mystr s_pword_str
;
316 static int pam_conv_func(int nmsg
, const struct pam_message
** p_msg
,
317 struct pam_response
** p_reply
, void* p_addata
);
318 static void vsf_auth_shutdown(void);
321 vsf_sysdep_check_auth(struct mystr
* p_user_str
,
322 const struct mystr
* p_pass_str
,
323 const struct mystr
* p_remote_host
)
327 const char* pam_user_name
= 0;
328 struct pam_conv the_conv
=
335 bug("vsf_sysdep_check_auth");
337 str_copy(&s_pword_str
, p_pass_str
);
338 retval
= pam_start(tunable_pam_service_name
,
339 str_getbuf(p_user_str
), &the_conv
, &s_pamh
);
340 if (retval
!= PAM_SUCCESS
)
346 retval
= pam_set_item(s_pamh
, PAM_RHOST
, str_getbuf(p_remote_host
));
347 if (retval
!= PAM_SUCCESS
)
349 (void) pam_end(s_pamh
, retval
);
355 retval
= pam_set_item(s_pamh
, PAM_TTY
, "ftp");
356 if (retval
!= PAM_SUCCESS
)
358 (void) pam_end(s_pamh
, retval
);
364 retval
= pam_set_item(s_pamh
, PAM_RUSER
, str_getbuf(p_user_str
));
365 if (retval
!= PAM_SUCCESS
)
367 (void) pam_end(s_pamh
, retval
);
372 retval
= pam_authenticate(s_pamh
, 0);
373 if (retval
!= PAM_SUCCESS
)
375 (void) pam_end(s_pamh
, retval
);
380 retval
= pam_get_item(s_pamh
, PAM_USER
, &item
);
381 if (retval
!= PAM_SUCCESS
)
383 (void) pam_end(s_pamh
, retval
);
387 pam_user_name
= item
;
388 str_alloc_text(p_user_str
, pam_user_name
);
390 retval
= pam_acct_mgmt(s_pamh
, 0);
391 if (retval
!= PAM_SUCCESS
)
393 (void) pam_end(s_pamh
, retval
);
397 retval
= pam_setcred(s_pamh
, PAM_ESTABLISH_CRED
);
398 if (retval
!= PAM_SUCCESS
)
400 (void) pam_end(s_pamh
, retval
);
404 if (!tunable_session_support
)
406 /* You're in already! */
407 (void) pam_end(s_pamh
, retval
);
411 /* Must do this BEFORE opening a session for pam_limits to count us */
412 vsf_insert_uwtmp(p_user_str
, p_remote_host
);
413 retval
= pam_open_session(s_pamh
, 0);
414 if (retval
!= PAM_SUCCESS
)
417 (void) pam_setcred(s_pamh
, PAM_DELETE_CRED
);
418 (void) pam_end(s_pamh
, retval
);
422 /* We MUST ensure the PAM session, utmp, wtmp etc. are cleaned up, however
425 vsf_sysutil_set_exit_func(vsf_auth_shutdown
);
431 vsf_auth_shutdown(void)
435 bug("vsf_auth_shutdown");
437 (void) pam_close_session(s_pamh
, 0);
438 (void) pam_setcred(s_pamh
, PAM_DELETE_CRED
);
439 (void) pam_end(s_pamh
, PAM_SUCCESS
);
445 pam_conv_func(int nmsg
, const struct pam_message
** p_msg
,
446 struct pam_response
** p_reply
, void* p_addata
)
449 struct pam_response
* p_resps
= 0;
453 bug("dodgy nmsg in pam_conv_func");
455 p_resps
= vsf_sysutil_malloc(sizeof(struct pam_response
) * nmsg
);
456 for (i
=0; i
<nmsg
; i
++)
458 switch (p_msg
[i
]->msg_style
)
460 case PAM_PROMPT_ECHO_OFF
:
461 p_resps
[i
].resp_retcode
= PAM_SUCCESS
;
462 p_resps
[i
].resp
= (char*) str_strdup(&s_pword_str
);
466 p_resps
[i
].resp_retcode
= PAM_SUCCESS
;
469 case PAM_PROMPT_ECHO_ON
:
471 vsf_sysutil_free(p_resps
);
480 #endif /* VSF_SYSDEP_HAVE_PAM */
482 /* Capabilities support (or lack thereof) */
484 vsf_sysdep_keep_capabilities(void)
486 if (!vsf_sysdep_has_capabilities_as_non_root())
488 bug("asked to keep capabilities, but no support exists");
490 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
492 int retval
= prctl(PR_SET_KEEPCAPS
, 1);
493 if (vsf_sysutil_retval_is_error(retval
))
498 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
500 #if !defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
503 vsf_sysdep_has_capabilities(void)
509 vsf_sysdep_has_capabilities_as_non_root(void)
515 vsf_sysdep_adopt_capabilities(unsigned int caps
)
518 bug("asked to adopt capabilities, but no support exists");
521 #else /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
523 static int do_checkcap(void);
526 vsf_sysdep_has_capabilities_as_non_root(void)
528 static int s_prctl_checked
;
529 static int s_runtime_prctl_works
;
530 if (!s_prctl_checked
)
532 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
533 /* Clarity: note embedded call to prctl() syscall */
534 if (!vsf_sysutil_retval_is_error(prctl(PR_SET_KEEPCAPS
, 0)))
536 s_runtime_prctl_works
= 1;
538 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
541 return s_runtime_prctl_works
;
545 vsf_sysdep_has_capabilities(void)
547 /* Even though compiled with capabilities, the runtime system may lack them.
548 * Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel!
550 static int s_caps_checked
;
551 static int s_runtime_has_caps
;
554 s_runtime_has_caps
= do_checkcap();
557 return s_runtime_has_caps
;
560 #ifndef VSF_SYSDEP_HAVE_LIBCAP
564 /* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */
565 int retval
= capset(0, 0);
566 if (!vsf_sysutil_retval_is_error(retval
) ||
567 vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS
)
575 vsf_sysdep_adopt_capabilities(unsigned int caps
)
577 /* n.b. yes I know I should be using libcap!! */
579 struct __user_cap_header_struct cap_head
;
580 struct __user_cap_data_struct cap_data
;
584 bug("asked to adopt no capabilities");
586 vsf_sysutil_memclr(&cap_head
, sizeof(cap_head
));
587 vsf_sysutil_memclr(&cap_data
, sizeof(cap_data
));
588 cap_head
.version
= _LINUX_CAPABILITY_VERSION
;
590 if (caps
& kCapabilityCAP_CHOWN
)
592 cap_mask
|= (1 << CAP_CHOWN
);
594 if (caps
& kCapabilityCAP_NET_BIND_SERVICE
)
596 cap_mask
|= (1 << CAP_NET_BIND_SERVICE
);
598 cap_data
.effective
= cap_data
.permitted
= cap_mask
;
599 cap_data
.inheritable
= 0;
600 retval
= capset(&cap_head
, &cap_data
);
607 #else /* VSF_SYSDEP_HAVE_LIBCAP */
611 cap_t current_caps
= cap_get_proc();
612 cap_free(current_caps
);
613 if (current_caps
!= NULL
)
621 vsf_sysdep_adopt_capabilities(unsigned int caps
)
624 cap_value_t cap_value
;
625 cap_t adopt_caps
= cap_init();
626 if (caps
& kCapabilityCAP_CHOWN
)
628 cap_value
= CAP_CHOWN
;
629 cap_set_flag(adopt_caps
, CAP_EFFECTIVE
, 1, &cap_value
, CAP_SET
);
630 cap_set_flag(adopt_caps
, CAP_PERMITTED
, 1, &cap_value
, CAP_SET
);
632 if (caps
& kCapabilityCAP_NET_BIND_SERVICE
)
634 cap_value
= CAP_NET_BIND_SERVICE
;
635 cap_set_flag(adopt_caps
, CAP_EFFECTIVE
, 1, &cap_value
, CAP_SET
);
636 cap_set_flag(adopt_caps
, CAP_PERMITTED
, 1, &cap_value
, CAP_SET
);
638 retval
= cap_set_proc(adopt_caps
);
643 cap_free(adopt_caps
);
646 #endif /* !VSF_SYSDEP_HAVE_LIBCAP */
647 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
650 vsf_sysutil_sendfile(const int out_fd
, const int in_fd
,
651 filesize_t
* p_offset
, filesize_t num_send
,
652 unsigned int max_chunk
)
654 /* Grr - why is off_t signed? */
655 if (*p_offset
< 0 || num_send
< 0)
657 die("invalid offset or send count in vsf_sysutil_sendfile");
666 unsigned int send_this_time
;
667 if (num_send
> max_chunk
)
669 send_this_time
= max_chunk
;
673 send_this_time
= (unsigned int) num_send
;
675 /* Keep input file position in line with sendfile() calls */
676 vsf_sysutil_lseek_to(in_fd
, *p_offset
);
677 retval
= do_sendfile(out_fd
, in_fd
, send_this_time
, *p_offset
);
678 if (vsf_sysutil_retval_is_error(retval
) || retval
== 0)
688 static int do_sendfile(const int out_fd
, const int in_fd
,
689 unsigned int num_send
, filesize_t start_pos
)
691 /* Probably should one day be shared with instance in ftpdataio.c */
692 static char* p_recvbuf
;
693 unsigned int total_written
= 0;
695 enum EVSFSysUtilError error
;
698 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
699 defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \
700 defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \
701 defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \
702 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
703 if (tunable_use_sendfile
)
705 static int s_sendfile_checked
;
706 static int s_runtime_sendfile_works
;
707 if (!s_sendfile_checked
|| s_runtime_sendfile_works
)
711 #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE
712 retval
= sendfile(out_fd
, in_fd
, NULL
, num_send
);
713 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
715 /* XXX - start_pos will truncate on 32-bit machines - can we
716 * say "start from current pos"?
719 retval
= sendfile(in_fd
, out_fd
, start_pos
, num_send
, NULL
,
721 /* Translate to Linux-like retval */
724 retval
= (int) written
;
727 #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
730 struct sendfilevec the_vec
;
731 vsf_sysutil_memclr(&the_vec
, sizeof(the_vec
));
732 the_vec
.sfv_fd
= in_fd
;
733 the_vec
.sfv_off
= start_pos
;
734 the_vec
.sfv_len
= num_send
;
735 retval
= sendfilev(out_fd
, &the_vec
, 1, &written
);
736 /* Translate to Linux-like retval */
739 retval
= (int) written
;
742 #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE)
744 struct sf_parms sf_iobuf
;
745 vsf_sysutil_memclr(&sf_iobuf
, sizeof(sf_iobuf
));
746 sf_iobuf
.header_data
= NULL
;
747 sf_iobuf
.header_length
= 0;
748 sf_iobuf
.trailer_data
= NULL
;
749 sf_iobuf
.trailer_length
= 0;
750 sf_iobuf
.file_descriptor
= in_fd
;
751 sf_iobuf
.file_offset
= start_pos
;
752 sf_iobuf
.file_bytes
= num_send
;
754 retval
= send_file((int*)&out_fd
, &sf_iobuf
, 0);
757 retval
= sf_iobuf
.bytes_sent
;
760 #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */
762 retval
= sendfile(out_fd
, in_fd
, start_pos
, num_send
, NULL
, 0);
764 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
765 error
= vsf_sysutil_get_error();
766 vsf_sysutil_check_pending_actions(kVSFSysUtilIO
, retval
, out_fd
);
768 while (vsf_sysutil_retval_is_error(retval
) &&
769 error
== kVSFSysUtilErrINTR
);
770 if (!s_sendfile_checked
)
772 s_sendfile_checked
= 1;
773 if (!vsf_sysutil_retval_is_error(retval
) ||
774 error
!= kVSFSysUtilErrNOSYS
)
776 s_runtime_sendfile_works
= 1;
779 if (!vsf_sysutil_retval_is_error(retval
))
783 if (s_runtime_sendfile_works
&& error
!= kVSFSysUtilErrINVAL
&&
784 error
!= kVSFSysUtilErrOPNOTSUPP
)
788 /* Fall thru to normal implementation. We won't check again. NOTE -
789 * also falls through if sendfile() is OK but it returns EINVAL. For
790 * Linux this means the file was not page cache backed. Original
791 * complaint was trying to serve files from an NTFS filesystem!
795 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */
798 vsf_secbuf_alloc(&p_recvbuf
, VSFTP_DATA_BUFSIZE
);
802 unsigned int num_read
;
803 unsigned int num_written
;
804 unsigned int num_read_this_time
= VSFTP_DATA_BUFSIZE
;
805 if (num_read_this_time
> num_send
)
807 num_read_this_time
= num_send
;
809 retval
= vsf_sysutil_read(in_fd
, p_recvbuf
, num_read_this_time
);
814 else if (retval
== 0)
818 num_read
= (unsigned int) retval
;
819 retval
= vsf_sysutil_write_loop(out_fd
, p_recvbuf
, num_read
);
824 num_written
= (unsigned int) retval
;
825 total_written
+= num_written
;
826 if (num_written
!= num_read
)
830 if (num_written
> num_send
)
832 bug("num_written bigger than num_send in do_sendfile");
834 num_send
-= num_written
;
838 return total_written
;
844 vsf_sysutil_set_proctitle_prefix(const struct mystr
* p_str
)
846 str_copy(&s_proctitle_prefix_str
, p_str
);
849 /* This delegation is common to all setproctitle() implementations */
851 vsf_sysutil_setproctitle_str(const struct mystr
* p_str
)
853 vsf_sysutil_setproctitle(str_getbuf(p_str
));
857 vsf_sysutil_setproctitle(const char* p_text
)
859 struct mystr proctitle_str
= INIT_MYSTR
;
860 str_copy(&proctitle_str
, &s_proctitle_prefix_str
);
861 if (!str_isempty(&proctitle_str
))
863 str_append_text(&proctitle_str
, ": ");
865 str_append_text(&proctitle_str
, p_text
);
866 vsf_sysutil_setproctitle_internal(str_getbuf(&proctitle_str
));
867 str_free(&proctitle_str
);
870 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
872 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
879 vsf_sysutil_setproctitle_internal(const char* p_buf
)
881 setproctitle("%s", p_buf
);
883 #elif defined(VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE)
885 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
892 vsf_sysutil_setproctitle_internal(const char* p_buf
)
894 struct mystr proctitle_str
= INIT_MYSTR
;
896 str_alloc_text(&proctitle_str
, "vsftpd: ");
897 str_append_text(&proctitle_str
, p_buf
);
898 p
.pst_command
= str_getbuf(&proctitle_str
);
899 pstat(PSTAT_SETCMD
, p
, 0, 0, 0);
900 str_free(&proctitle_str
);
902 #elif defined(VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK)
904 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
907 char** p_env
= environ
;
908 if (s_proctitle_inited
)
910 bug("vsf_sysutil_setproctitle_init called twice");
912 s_proctitle_inited
= 1;
915 die("no argv[0] in vsf_sysutil_setproctitle_init");
917 for (i
=0; i
<argc
; i
++)
919 s_proctitle_space
+= vsf_sysutil_strlen(argv
[i
]) + 1;
927 s_proctitle_space
+= vsf_sysutil_strlen(*p_env
) + 1;
932 s_p_proctitle
= (char*) argv
[0];
933 vsf_sysutil_memclr(s_p_proctitle
, s_proctitle_space
);
937 vsf_sysutil_setproctitle_internal(const char* p_buf
)
939 struct mystr proctitle_str
= INIT_MYSTR
;
940 unsigned int to_copy
;
941 if (!s_proctitle_inited
)
943 bug("vsf_sysutil_setproctitle: not initialized");
945 vsf_sysutil_memclr(s_p_proctitle
, s_proctitle_space
);
946 if (s_proctitle_space
< 32)
950 str_alloc_text(&proctitle_str
, "vsftpd: ");
951 str_append_text(&proctitle_str
, p_buf
);
952 to_copy
= str_getlen(&proctitle_str
);
953 if (to_copy
> s_proctitle_space
- 1)
955 to_copy
= s_proctitle_space
- 1;
957 vsf_sysutil_memcpy(s_p_proctitle
, str_getbuf(&proctitle_str
), to_copy
);
958 str_free(&proctitle_str
);
959 s_p_proctitle
[to_copy
] = '\0';
961 #else /* VSF_SYSDEP_HAVE_SETPROCTITLE */
963 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
970 vsf_sysutil_setproctitle_internal(const char* p_buf
)
974 #endif /* VSF_SYSDEP_HAVE_SETPROCTITLE */
976 #ifdef VSF_SYSDEP_HAVE_MAP_ANON
978 vsf_sysutil_map_anon_pages_init(void)
983 vsf_sysutil_map_anon_pages(unsigned int length
)
985 char* retval
= mmap(0, length
, PROT_READ
| PROT_WRITE
,
986 MAP_PRIVATE
| MAP_ANON
, -1, 0);
987 if (retval
== MAP_FAILED
)
993 #else /* VSF_SYSDEP_HAVE_MAP_ANON */
995 vsf_sysutil_map_anon_pages_init(void)
999 bug("vsf_sysutil_map_anon_pages_init called twice");
1001 s_zero_fd
= open("/dev/zero", O_RDWR
);
1004 die("could not open /dev/zero");
1009 vsf_sysutil_map_anon_pages(unsigned int length
)
1011 char* retval
= mmap(0, length
, PROT_READ
| PROT_WRITE
,
1012 MAP_PRIVATE
, s_zero_fd
, 0);
1013 if (retval
== MAP_FAILED
)
1019 #endif /* VSF_SYSDEP_HAVE_MAP_ANON */
1021 #ifndef VSF_SYSDEP_NEED_OLD_FD_PASSING
1024 vsf_sysutil_send_fd(int sock_fd
, int send_fd
)
1028 struct cmsghdr
* p_cmsg
;
1030 char cmsgbuf
[CMSG_SPACE(sizeof(send_fd
))];
1033 msg
.msg_control
= cmsgbuf
;
1034 msg
.msg_controllen
= sizeof(cmsgbuf
);
1035 p_cmsg
= CMSG_FIRSTHDR(&msg
);
1036 p_cmsg
->cmsg_level
= SOL_SOCKET
;
1037 p_cmsg
->cmsg_type
= SCM_RIGHTS
;
1038 p_cmsg
->cmsg_len
= CMSG_LEN(sizeof(send_fd
));
1039 p_fds
= (int*)CMSG_DATA(p_cmsg
);
1041 msg
.msg_controllen
= p_cmsg
->cmsg_len
;
1042 msg
.msg_name
= NULL
;
1043 msg
.msg_namelen
= 0;
1047 /* "To pass file descriptors or credentials you need to send/read at
1048 * least on byte" (man 7 unix)
1050 vec
.iov_base
= &sendchar
;
1051 vec
.iov_len
= sizeof(sendchar
);
1052 retval
= sendmsg(sock_fd
, &msg
, 0);
1060 vsf_sysutil_recv_fd(const int sock_fd
)
1067 char cmsgbuf
[CMSG_SPACE(sizeof(recv_fd
))];
1068 struct cmsghdr
* p_cmsg
;
1070 vec
.iov_base
= &recvchar
;
1071 vec
.iov_len
= sizeof(recvchar
);
1072 msg
.msg_name
= NULL
;
1073 msg
.msg_namelen
= 0;
1076 msg
.msg_control
= cmsgbuf
;
1077 msg
.msg_controllen
= sizeof(cmsgbuf
);
1079 /* In case something goes wrong, set the fd to -1 before the syscall */
1080 p_fd
= (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg
));
1082 retval
= recvmsg(sock_fd
, &msg
, 0);
1087 p_cmsg
= CMSG_FIRSTHDR(&msg
);
1090 die("no passed fd");
1092 /* We used to verify the returned cmsg_level, cmsg_type and cmsg_len here,
1093 * but Linux 2.0 totally uselessly fails to fill these in.
1095 p_fd
= (int*)CMSG_DATA(p_cmsg
);
1099 die("no passed fd");
1104 #else /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1107 vsf_sysutil_send_fd(int sock_fd
, int send_fd
)
1113 vec
.iov_base
= &send_char
;
1115 msg
.msg_name
= NULL
;
1116 msg
.msg_namelen
= 0;
1119 msg
.msg_accrights
= (caddr_t
) &send_fd
;
1120 msg
.msg_accrightslen
= sizeof(send_fd
);
1121 retval
= sendmsg(sock_fd
, &msg
, 0);
1129 vsf_sysutil_recv_fd(int sock_fd
)
1136 vec
.iov_base
= &recv_char
;
1138 msg
.msg_name
= NULL
;
1139 msg
.msg_namelen
= 0;
1142 msg
.msg_accrights
= (caddr_t
) &recv_fd
;
1143 msg
.msg_accrightslen
= sizeof(recv_fd
);
1144 retval
= recvmsg(sock_fd
, &msg
, 0);
1151 die("no passed fd");
1156 #endif /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1158 #ifndef VSF_SYSDEP_HAVE_UTMPX
1161 vsf_insert_uwtmp(const struct mystr
* p_user_str
,
1162 const struct mystr
* p_host_str
)
1169 vsf_remove_uwtmp(void)
1173 #else /* !VSF_SYSDEP_HAVE_UTMPX */
1175 /* IMHO, the pam_unix module REALLY should be doing this in its SM component */
1177 static int s_uwtmp_inserted
;
1178 static struct utmpx s_utent
;
1181 vsf_insert_uwtmp(const struct mystr
* p_user_str
,
1182 const struct mystr
* p_host_str
)
1184 if (sizeof(s_utent
.ut_line
) < 16)
1188 if (s_uwtmp_inserted
)
1190 bug("vsf_insert_uwtmp");
1193 struct mystr line_str
= INIT_MYSTR
;
1194 str_alloc_text(&line_str
, "vsftpd:");
1195 str_append_ulong(&line_str
, vsf_sysutil_getpid());
1196 if (str_getlen(&line_str
) >= sizeof(s_utent
.ut_line
))
1198 str_free(&line_str
);
1201 vsf_sysutil_strcpy(s_utent
.ut_line
, str_getbuf(&line_str
),
1202 sizeof(s_utent
.ut_line
));
1203 str_free(&line_str
);
1205 s_uwtmp_inserted
= 1;
1206 s_utent
.ut_type
= USER_PROCESS
;
1207 s_utent
.ut_pid
= vsf_sysutil_getpid();
1208 vsf_sysutil_strcpy(s_utent
.ut_user
, str_getbuf(p_user_str
),
1209 sizeof(s_utent
.ut_user
));
1210 vsf_sysutil_strcpy(s_utent
.ut_host
, str_getbuf(p_host_str
),
1211 sizeof(s_utent
.ut_host
));
1212 s_utent
.ut_tv
.tv_sec
= vsf_sysutil_get_time_sec();
1214 (void) pututxline(&s_utent
);
1216 updwtmpx(WTMPX_FILE
, &s_utent
);
1220 vsf_remove_uwtmp(void)
1222 if (!s_uwtmp_inserted
)
1226 s_uwtmp_inserted
= 0;
1227 s_utent
.ut_type
= DEAD_PROCESS
;
1228 vsf_sysutil_memclr(s_utent
.ut_user
, sizeof(s_utent
.ut_user
));
1229 vsf_sysutil_memclr(s_utent
.ut_host
, sizeof(s_utent
.ut_host
));
1230 s_utent
.ut_tv
.tv_sec
= 0;
1232 (void) pututxline(&s_utent
);
1234 s_utent
.ut_tv
.tv_sec
= vsf_sysutil_get_time_sec();
1235 updwtmpx(WTMPX_FILE
, &s_utent
);
1238 #endif /* !VSF_SYSDEP_HAVE_UTMPX */
1241 vsf_set_die_if_parent_dies()
1243 #ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
1244 if (prctl(PR_SET_PDEATHSIG
, SIGKILL
, 0, 0, 0) != 0)
1252 vsf_set_term_if_parent_dies()
1254 #ifdef VSF_SYSDEP_HAVE_SETPDEATHSIG
1255 if (prctl(PR_SET_PDEATHSIG
, SIGTERM
, 0, 0, 0) != 0)
1263 vsf_sysutil_fork_isolate_all_failok()
1265 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1266 static int cloneflags_work
= 1;
1267 if (cloneflags_work
)
1269 int ret
= syscall(__NR_clone
,
1270 CLONE_NEWPID
| CLONE_NEWIPC
| CLONE_NEWNET
| SIGCHLD
,
1272 if (ret
!= -1 || (errno
!= EINVAL
&& errno
!= EPERM
))
1276 vsf_sysutil_post_fork();
1280 cloneflags_work
= 0;
1283 return vsf_sysutil_fork_isolate_failok();
1287 vsf_sysutil_fork_isolate_failok()
1289 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1290 static int cloneflags_work
= 1;
1291 if (cloneflags_work
)
1293 int ret
= syscall(__NR_clone
, CLONE_NEWPID
| CLONE_NEWIPC
| SIGCHLD
, NULL
);
1294 if (ret
!= -1 || (errno
!= EINVAL
&& errno
!= EPERM
))
1298 vsf_sysutil_post_fork();
1302 cloneflags_work
= 0;
1305 return vsf_sysutil_fork_failok();
1309 vsf_sysutil_fork_newnet()
1311 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1312 static int cloneflags_work
= 1;
1313 if (cloneflags_work
)
1315 int ret
= syscall(__NR_clone
, CLONE_NEWNET
| SIGCHLD
, NULL
);
1316 if (ret
!= -1 || (errno
!= EINVAL
&& errno
!= EPERM
))
1320 vsf_sysutil_post_fork();
1324 cloneflags_work
= 0;
1327 return vsf_sysutil_fork();
1331 vsf_sysutil_getpid_nocache(void)
1333 #ifdef VSF_SYSDEP_HAVE_LINUX_CLONE
1334 /* Need to defeat the glibc pid caching because we need to hit a raw
1335 * sys_clone() above.
1337 return syscall(__NR_getpid
);