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 /* 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
51 #define VSF_SYSDEP_HAVE_PAM
53 #define VSF_SYSDEP_HAVE_SHADOW
54 #define VSF_SYSDEP_HAVE_USERSHELL
55 #define VSF_SYSDEP_HAVE_LIBCAP
56 #define VSF_SYSDEP_HAVE_UTMPX
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
77 #if (defined(__FreeBSD__) && __FreeBSD__ >= 3)
78 #define VSF_SYSDEP_HAVE_FREEBSD_SENDFILE
79 #define VSF_SYSDEP_HAVE_SETPROCTITLE
82 #if defined(__NetBSD__)
84 #define VSF_SYSDEP_HAVE_SETPROCTITLE
85 #include <sys/param.h>
86 #if __NetBSD_Version__ >= 106070000
87 #define WTMPX_FILE _PATH_WTMPX
89 #undef VSF_SYSDEP_HAVE_UTMPX
94 #include <sys/socket.h>
96 #define VSF_SYSDEP_HAVE_HPUX_SENDFILE
98 #include <sys/param.h>
99 #include <sys/pstat.h>
101 #define VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE
103 #undef VSF_SYSDEP_HAVE_UTMPX
107 #include <sys/mman.h>
109 #define VSF_SYSDEP_HAVE_MAP_ANON
113 #undef VSF_SYSDEP_HAVE_USERSHELL
114 #undef VSF_SYSDEP_HAVE_LIBCAP
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
130 #undef VSF_SYSDEP_HAVE_USERSHELL
133 #if (defined(__sgi) || defined(__hpux) || defined(__osf__))
134 #define VSF_SYSDEP_NEED_OLD_FD_PASSING
138 #define VSF_SYSDEP_HAVE_SOLARIS_SENDFILE
142 /* PAM support - we include our own dummy version if the system lacks this */
143 #include <security/pam_appl.h>
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 */
154 /* Prefer libcap based capabilities over raw syscall capabilities */
155 #include <sys/capability.h>
157 #if defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
158 #include <linux/unistd.h>
159 #include <linux/capability.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 */
166 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES */
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 */
178 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
180 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
181 #include <sys/types.h>
185 #ifdef VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK
186 extern char** environ
;
187 static unsigned int s_proctitle_space
= 0;
188 static int s_proctitle_inited
= 0;
189 static char* s_p_proctitle
= 0;
192 #ifndef VSF_SYSDEP_HAVE_MAP_ANON
193 #include <sys/types.h>
194 #include <sys/stat.h>
196 static int s_zero_fd
= -1;
199 /* File private functions/variables */
200 static int do_sendfile(const int out_fd
, const int in_fd
,
201 unsigned int num_send
, filesize_t start_pos
);
202 static void vsf_sysutil_setproctitle_internal(const char* p_text
);
203 static struct mystr s_proctitle_prefix_str
;
205 /* These two aren't static to avoid OpenBSD build warnings. */
206 void vsf_insert_uwtmp(const struct mystr
* p_user_str
,
207 const struct mystr
* p_host_str
);
208 void vsf_remove_uwtmp(void);
210 #ifndef VSF_SYSDEP_HAVE_PAM
212 vsf_sysdep_check_auth(const struct mystr
* p_user_str
,
213 const struct mystr
* p_pass_str
,
214 const struct mystr
* p_remote_host
)
216 const char* p_crypted
;
217 const struct passwd
* p_pwd
= getpwnam(str_getbuf(p_user_str
));
218 (void) p_remote_host
;
223 #ifdef VSF_SYSDEP_HAVE_USERSHELL
224 if (tunable_check_shell
)
227 while ((p_shell
= getusershell()) != NULL
)
229 if (!vsf_sysutil_strcmp(p_shell
, p_pwd
->pw_shell
))
241 #ifdef VSF_SYSDEP_HAVE_SHADOW
243 const struct spwd
* p_spwd
= getspnam(str_getbuf(p_user_str
));
248 vsf_sysutil_update_cached_time();
249 curr_time
= vsf_sysutil_get_cached_time_sec();
250 days
= curr_time
/ (60 * 60 * 24);
251 if (p_spwd
->sp_expire
> 0 && p_spwd
->sp_expire
< days
)
255 if (p_spwd
->sp_lstchg
> 0 && p_spwd
->sp_max
> 0 &&
256 p_spwd
->sp_lstchg
+ p_spwd
->sp_max
< days
)
260 p_crypted
= crypt(str_getbuf(p_pass_str
), p_spwd
->sp_pwdp
);
261 if (!vsf_sysutil_strcmp(p_crypted
, p_spwd
->sp_pwdp
))
267 #endif /* VSF_SYSDEP_HAVE_SHADOW */
268 p_crypted
= crypt(str_getbuf(p_pass_str
), p_pwd
->pw_passwd
);
269 if (!vsf_sysutil_strcmp(p_crypted
, p_pwd
->pw_passwd
))
276 #else /* VSF_SYSDEP_HAVE_PAM */
278 static pam_handle_t
* s_pamh
;
279 static struct mystr s_pword_str
;
280 static int pam_conv_func(int nmsg
, const struct pam_message
** p_msg
,
281 struct pam_response
** p_reply
, void* p_addata
);
282 static void vsf_auth_shutdown(void);
285 vsf_sysdep_check_auth(const struct mystr
* p_user_str
,
286 const struct mystr
* p_pass_str
,
287 const struct mystr
* p_remote_host
)
290 struct pam_conv the_conv
=
297 bug("vsf_sysdep_check_auth");
299 str_copy(&s_pword_str
, p_pass_str
);
300 retval
= pam_start(tunable_pam_service_name
,
301 str_getbuf(p_user_str
), &the_conv
, &s_pamh
);
302 if (retval
!= PAM_SUCCESS
)
308 retval
= pam_set_item(s_pamh
, PAM_RHOST
, str_getbuf(p_remote_host
));
309 if (retval
!= PAM_SUCCESS
)
311 (void) pam_end(s_pamh
, 0);
317 retval
= pam_set_item(s_pamh
, PAM_TTY
, "ftp");
318 if (retval
!= PAM_SUCCESS
)
320 (void) pam_end(s_pamh
, 0);
326 retval
= pam_set_item(s_pamh
, PAM_RUSER
, str_getbuf(p_user_str
));
327 if (retval
!= PAM_SUCCESS
)
329 (void) pam_end(s_pamh
, 0);
334 retval
= pam_authenticate(s_pamh
, 0);
335 if (retval
!= PAM_SUCCESS
)
337 (void) pam_end(s_pamh
, 0);
341 retval
= pam_acct_mgmt(s_pamh
, 0);
342 if (retval
!= PAM_SUCCESS
)
344 (void) pam_end(s_pamh
, 0);
348 retval
= pam_setcred(s_pamh
, PAM_ESTABLISH_CRED
);
349 if (retval
!= PAM_SUCCESS
)
351 (void) pam_end(s_pamh
, 0);
355 if (!tunable_session_support
)
357 /* You're in already! */
358 (void) pam_end(s_pamh
, 0);
362 /* Must do this BEFORE opening a session for pam_limits to count us */
363 vsf_insert_uwtmp(p_user_str
, p_remote_host
);
364 retval
= pam_open_session(s_pamh
, 0);
365 if (retval
!= PAM_SUCCESS
)
368 (void) pam_setcred(s_pamh
, PAM_DELETE_CRED
);
369 (void) pam_end(s_pamh
, 0);
373 /* We MUST ensure the PAM session, utmp, wtmp etc. are cleaned up, however
376 vsf_sysutil_set_exit_func(vsf_auth_shutdown
);
382 vsf_auth_shutdown(void)
386 bug("vsf_auth_shutdown");
388 (void) pam_close_session(s_pamh
, 0);
389 (void) pam_setcred(s_pamh
, PAM_DELETE_CRED
);
390 (void) pam_end(s_pamh
, 0);
396 pam_conv_func(int nmsg
, const struct pam_message
** p_msg
,
397 struct pam_response
** p_reply
, void* p_addata
)
400 struct pam_response
* p_resps
= 0;
404 bug("dodgy nmsg in pam_conv_func");
406 p_resps
= vsf_sysutil_malloc(sizeof(struct pam_response
) * nmsg
);
407 for (i
=0; i
<nmsg
; i
++)
409 switch (p_msg
[i
]->msg_style
)
411 case PAM_PROMPT_ECHO_OFF
:
412 p_resps
[i
].resp_retcode
= PAM_SUCCESS
;
413 p_resps
[i
].resp
= (char*) str_strdup(&s_pword_str
);
417 p_resps
[i
].resp_retcode
= PAM_SUCCESS
;
420 case PAM_PROMPT_ECHO_ON
:
422 vsf_sysutil_free(p_resps
);
431 #endif /* VSF_SYSDEP_HAVE_PAM */
433 /* Capabilities support (or lack thereof) */
435 vsf_sysdep_keep_capabilities(void)
437 if (!vsf_sysdep_has_capabilities_as_non_root())
439 bug("asked to keep capabilities, but no support exists");
441 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
443 int retval
= prctl(PR_SET_KEEPCAPS
, 1);
444 if (vsf_sysutil_retval_is_error(retval
))
449 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
451 #if !defined(VSF_SYSDEP_HAVE_CAPABILITIES) && !defined(VSF_SYSDEP_HAVE_LIBCAP)
454 vsf_sysdep_has_capabilities(void)
460 vsf_sysdep_has_capabilities_as_non_root(void)
466 vsf_sysdep_adopt_capabilities(unsigned int caps
)
469 bug("asked to adopt capabilities, but no support exists");
472 #else /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
474 static int do_checkcap(void);
477 vsf_sysdep_has_capabilities_as_non_root(void)
479 static int s_prctl_checked
;
480 static int s_runtime_prctl_works
;
481 if (!s_prctl_checked
)
483 #ifdef VSF_SYSDEP_HAVE_SETKEEPCAPS
484 /* Clarity: note embedded call to prctl() syscall */
485 if (!vsf_sysutil_retval_is_error(prctl(PR_SET_KEEPCAPS
, 0)))
487 s_runtime_prctl_works
= 1;
489 #endif /* VSF_SYSDEP_HAVE_SETKEEPCAPS */
492 return s_runtime_prctl_works
;
496 vsf_sysdep_has_capabilities(void)
498 /* Even though compiled with capabilities, the runtime system may lack them.
499 * Also, RH7.0 kernel headers advertise a 2.4.0 box, but on a 2.2.x kernel!
501 static int s_caps_checked
;
502 static int s_runtime_has_caps
;
505 s_runtime_has_caps
= do_checkcap();
508 return s_runtime_has_caps
;
511 #ifndef VSF_SYSDEP_HAVE_LIBCAP
515 /* EFAULT (EINVAL if page 0 mapped) vs. ENOSYS */
516 int retval
= capset(0, 0);
517 if (!vsf_sysutil_retval_is_error(retval
) ||
518 vsf_sysutil_get_error() != kVSFSysUtilErrNOSYS
)
526 vsf_sysdep_adopt_capabilities(unsigned int caps
)
528 /* n.b. yes I know I should be using libcap!! */
530 struct __user_cap_header_struct cap_head
;
531 struct __user_cap_data_struct cap_data
;
535 bug("asked to adopt no capabilities");
537 vsf_sysutil_memclr(&cap_head
, sizeof(cap_head
));
538 vsf_sysutil_memclr(&cap_data
, sizeof(cap_data
));
539 cap_head
.version
= _LINUX_CAPABILITY_VERSION
;
541 if (caps
& kCapabilityCAP_CHOWN
)
543 cap_mask
|= (1 << CAP_CHOWN
);
545 if (caps
& kCapabilityCAP_NET_BIND_SERVICE
)
547 cap_mask
|= (1 << CAP_NET_BIND_SERVICE
);
549 cap_data
.effective
= cap_data
.permitted
= cap_mask
;
550 cap_data
.inheritable
= 0;
551 retval
= capset(&cap_head
, &cap_data
);
558 #else /* VSF_SYSDEP_HAVE_LIBCAP */
562 cap_t current_caps
= cap_get_proc();
563 cap_free(current_caps
);
564 if (current_caps
!= NULL
)
572 vsf_sysdep_adopt_capabilities(unsigned int caps
)
575 cap_value_t cap_value
;
576 cap_t adopt_caps
= cap_init();
577 if (caps
& kCapabilityCAP_CHOWN
)
579 cap_value
= CAP_CHOWN
;
580 cap_set_flag(adopt_caps
, CAP_EFFECTIVE
, 1, &cap_value
, CAP_SET
);
581 cap_set_flag(adopt_caps
, CAP_PERMITTED
, 1, &cap_value
, CAP_SET
);
583 if (caps
& kCapabilityCAP_NET_BIND_SERVICE
)
585 cap_value
= CAP_NET_BIND_SERVICE
;
586 cap_set_flag(adopt_caps
, CAP_EFFECTIVE
, 1, &cap_value
, CAP_SET
);
587 cap_set_flag(adopt_caps
, CAP_PERMITTED
, 1, &cap_value
, CAP_SET
);
589 retval
= cap_set_proc(adopt_caps
);
594 cap_free(adopt_caps
);
597 #endif /* !VSF_SYSDEP_HAVE_LIBCAP */
598 #endif /* VSF_SYSDEP_HAVE_CAPABILITIES || VSF_SYSDEP_HAVE_LIBCAP */
601 vsf_sysutil_sendfile(const int out_fd
, const int in_fd
,
602 filesize_t
* p_offset
, filesize_t num_send
,
603 unsigned int max_chunk
)
605 /* Grr - why is off_t signed? */
606 if (*p_offset
< 0 || num_send
< 0)
608 die("invalid offset or send count in vsf_sysutil_sendfile");
617 unsigned int send_this_time
;
618 if (num_send
> max_chunk
)
620 send_this_time
= max_chunk
;
624 send_this_time
= (unsigned int) num_send
;
626 /* Keep input file position in line with sendfile() calls */
627 vsf_sysutil_lseek_to(in_fd
, *p_offset
);
628 retval
= do_sendfile(out_fd
, in_fd
, send_this_time
, *p_offset
);
629 if (vsf_sysutil_retval_is_error(retval
) || retval
== 0)
639 static int do_sendfile(const int out_fd
, const int in_fd
,
640 unsigned int num_send
, filesize_t start_pos
)
642 /* Probably should one day be shared with instance in ftpdataio.c */
643 static char* p_recvbuf
;
644 unsigned int total_written
= 0;
646 enum EVSFSysUtilError error
;
649 #if defined(VSF_SYSDEP_HAVE_LINUX_SENDFILE) || \
650 defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE) || \
651 defined(VSF_SYSDEP_HAVE_HPUX_SENDFILE) || \
652 defined(VSF_SYSDEP_HAVE_AIX_SENDFILE) || \
653 defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
654 if (tunable_use_sendfile
)
656 static int s_sendfile_checked
;
657 static int s_runtime_sendfile_works
;
658 if (!s_sendfile_checked
|| s_runtime_sendfile_works
)
662 #ifdef VSF_SYSDEP_HAVE_LINUX_SENDFILE
663 retval
= sendfile(out_fd
, in_fd
, NULL
, num_send
);
664 #elif defined(VSF_SYSDEP_HAVE_FREEBSD_SENDFILE)
666 /* XXX - start_pos will truncate on 32-bit machines - can we
667 * say "start from current pos"?
670 retval
= sendfile(in_fd
, out_fd
, start_pos
, num_send
, NULL
,
672 /* Translate to Linux-like retval */
675 retval
= (int) written
;
678 #elif defined(VSF_SYSDEP_HAVE_SOLARIS_SENDFILE)
681 struct sendfilevec the_vec
;
682 vsf_sysutil_memclr(&the_vec
, sizeof(the_vec
));
683 the_vec
.sfv_fd
= in_fd
;
684 the_vec
.sfv_off
= start_pos
;
685 the_vec
.sfv_len
= num_send
;
686 retval
= sendfilev(out_fd
, &the_vec
, 1, &written
);
687 /* Translate to Linux-like retval */
690 retval
= (int) written
;
693 #elif defined(VSF_SYSDEP_HAVE_AIX_SENDFILE)
695 struct sf_parms sf_iobuf
;
696 vsf_sysutil_memclr(&sf_iobuf
, sizeof(sf_iobuf
));
697 sf_iobuf
.header_data
= NULL
;
698 sf_iobuf
.header_length
= 0;
699 sf_iobuf
.trailer_data
= NULL
;
700 sf_iobuf
.trailer_length
= 0;
701 sf_iobuf
.file_descriptor
= in_fd
;
702 sf_iobuf
.file_offset
= start_pos
;
703 sf_iobuf
.file_bytes
= num_send
;
705 retval
= send_file((int*)&out_fd
, &sf_iobuf
, 0);
708 retval
= sf_iobuf
.bytes_sent
;
711 #else /* must be VSF_SYSDEP_HAVE_HPUX_SENDFILE */
713 retval
= sendfile(out_fd
, in_fd
, start_pos
, num_send
, NULL
, 0);
715 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE */
716 error
= vsf_sysutil_get_error();
717 vsf_sysutil_check_pending_actions(kVSFSysUtilIO
, retval
, out_fd
);
719 while (vsf_sysutil_retval_is_error(retval
) &&
720 error
== kVSFSysUtilErrINTR
);
721 if (!s_sendfile_checked
)
723 s_sendfile_checked
= 1;
724 if (!vsf_sysutil_retval_is_error(retval
) ||
725 error
!= kVSFSysUtilErrNOSYS
)
727 s_runtime_sendfile_works
= 1;
730 if (!vsf_sysutil_retval_is_error(retval
))
734 if (s_runtime_sendfile_works
&& error
!= kVSFSysUtilErrINVAL
&&
735 error
!= kVSFSysUtilErrOPNOTSUPP
)
739 /* Fall thru to normal implementation. We won't check again. NOTE -
740 * also falls through if sendfile() is OK but it returns EINVAL. For
741 * Linux this means the file was not page cache backed. Original
742 * complaint was trying to serve files from an NTFS filesystem!
746 #endif /* VSF_SYSDEP_HAVE_LINUX_SENDFILE || VSF_SYSDEP_HAVE_FREEBSD_SENDFILE */
749 vsf_secbuf_alloc(&p_recvbuf
, VSFTP_DATA_BUFSIZE
);
753 unsigned int num_read
;
754 unsigned int num_written
;
755 unsigned int num_read_this_time
= VSFTP_DATA_BUFSIZE
;
756 if (num_read_this_time
> num_send
)
758 num_read_this_time
= num_send
;
760 retval
= vsf_sysutil_read(in_fd
, p_recvbuf
, num_read_this_time
);
765 else if (retval
== 0)
769 num_read
= (unsigned int) retval
;
770 retval
= vsf_sysutil_write_loop(out_fd
, p_recvbuf
, num_read
);
775 num_written
= (unsigned int) retval
;
776 total_written
+= num_written
;
777 if (num_written
!= num_read
)
781 if (num_written
> num_send
)
783 bug("num_written bigger than num_send in do_sendfile");
785 num_send
-= num_written
;
789 return total_written
;
795 vsf_sysutil_set_proctitle_prefix(const struct mystr
* p_str
)
797 str_copy(&s_proctitle_prefix_str
, p_str
);
800 /* This delegation is common to all setproctitle() implementations */
802 vsf_sysutil_setproctitle_str(const struct mystr
* p_str
)
804 vsf_sysutil_setproctitle(str_getbuf(p_str
));
808 vsf_sysutil_setproctitle(const char* p_text
)
810 struct mystr proctitle_str
= INIT_MYSTR
;
811 str_copy(&proctitle_str
, &s_proctitle_prefix_str
);
812 if (!str_isempty(&proctitle_str
))
814 str_append_text(&proctitle_str
, ": ");
816 str_append_text(&proctitle_str
, p_text
);
817 vsf_sysutil_setproctitle_internal(str_getbuf(&proctitle_str
));
818 str_free(&proctitle_str
);
821 #ifdef VSF_SYSDEP_HAVE_SETPROCTITLE
823 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
830 vsf_sysutil_setproctitle_internal(const char* p_buf
)
832 setproctitle("%s", p_buf
);
834 #elif defined(VSF_SYSDEP_HAVE_HPUX_SETPROCTITLE)
836 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
843 vsf_sysutil_setproctitle_internal(const char* p_buf
)
845 struct mystr proctitle_str
= INIT_MYSTR
;
847 str_alloc_text(&proctitle_str
, "vsftpd: ");
848 str_append_text(&proctitle_str
, p_buf
);
849 p
.pst_command
= str_getbuf(&proctitle_str
);
850 pstat(PSTAT_SETCMD
, p
, 0, 0, 0);
851 str_free(&proctitle_str
);
853 #elif defined(VSF_SYSDEP_TRY_LINUX_SETPROCTITLE_HACK)
855 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
858 char** p_env
= environ
;
859 if (s_proctitle_inited
)
861 bug("vsf_sysutil_setproctitle_init called twice");
863 s_proctitle_inited
= 1;
866 die("no argv[0] in vsf_sysutil_setproctitle_init");
868 for (i
=0; i
<argc
; i
++)
870 s_proctitle_space
+= vsf_sysutil_strlen(argv
[i
]) + 1;
878 s_proctitle_space
+= vsf_sysutil_strlen(*p_env
) + 1;
883 s_p_proctitle
= (char*) argv
[0];
884 vsf_sysutil_memclr(s_p_proctitle
, s_proctitle_space
);
888 vsf_sysutil_setproctitle_internal(const char* p_buf
)
890 struct mystr proctitle_str
= INIT_MYSTR
;
891 unsigned int to_copy
;
892 if (!s_proctitle_inited
)
894 bug("vsf_sysutil_setproctitle: not initialized");
896 vsf_sysutil_memclr(s_p_proctitle
, s_proctitle_space
);
897 if (s_proctitle_space
< 32)
901 str_alloc_text(&proctitle_str
, "vsftpd: ");
902 str_append_text(&proctitle_str
, p_buf
);
903 to_copy
= str_getlen(&proctitle_str
);
904 if (to_copy
> s_proctitle_space
- 1)
906 to_copy
= s_proctitle_space
- 1;
908 vsf_sysutil_memcpy(s_p_proctitle
, str_getbuf(&proctitle_str
), to_copy
);
909 str_free(&proctitle_str
);
910 s_p_proctitle
[to_copy
] = '\0';
912 #else /* VSF_SYSDEP_HAVE_SETPROCTITLE */
914 vsf_sysutil_setproctitle_init(int argc
, const char* argv
[])
921 vsf_sysutil_setproctitle_internal(const char* p_buf
)
925 #endif /* VSF_SYSDEP_HAVE_SETPROCTITLE */
927 #ifdef VSF_SYSDEP_HAVE_MAP_ANON
929 vsf_sysutil_map_anon_pages_init(void)
934 vsf_sysutil_map_anon_pages(unsigned int length
)
936 char* retval
= mmap(0, length
, PROT_READ
| PROT_WRITE
,
937 MAP_PRIVATE
| MAP_ANON
, -1, 0);
938 if (retval
== MAP_FAILED
)
944 #else /* VSF_SYSDEP_HAVE_MAP_ANON */
946 vsf_sysutil_map_anon_pages_init(void)
950 bug("vsf_sysutil_map_anon_pages_init called twice");
952 s_zero_fd
= open("/dev/zero", O_RDWR
);
955 die("could not open /dev/zero");
960 vsf_sysutil_map_anon_pages(unsigned int length
)
962 char* retval
= mmap(0, length
, PROT_READ
| PROT_WRITE
,
963 MAP_PRIVATE
, s_zero_fd
, 0);
964 if (retval
== MAP_FAILED
)
970 #endif /* VSF_SYSDEP_HAVE_MAP_ANON */
972 #ifndef VSF_SYSDEP_NEED_OLD_FD_PASSING
975 vsf_sysutil_send_fd(int sock_fd
, int send_fd
)
979 struct cmsghdr
* p_cmsg
;
981 char cmsgbuf
[CMSG_SPACE(sizeof(send_fd
))];
984 msg
.msg_control
= cmsgbuf
;
985 msg
.msg_controllen
= sizeof(cmsgbuf
);
986 p_cmsg
= CMSG_FIRSTHDR(&msg
);
987 p_cmsg
->cmsg_level
= SOL_SOCKET
;
988 p_cmsg
->cmsg_type
= SCM_RIGHTS
;
989 p_cmsg
->cmsg_len
= CMSG_LEN(sizeof(send_fd
));
990 p_fds
= (int*)CMSG_DATA(p_cmsg
);
992 msg
.msg_controllen
= p_cmsg
->cmsg_len
;
998 /* "To pass file descriptors or credentials you need to send/read at
999 * least on byte" (man 7 unix)
1001 vec
.iov_base
= &sendchar
;
1002 vec
.iov_len
= sizeof(sendchar
);
1003 retval
= sendmsg(sock_fd
, &msg
, 0);
1011 vsf_sysutil_recv_fd(const int sock_fd
)
1018 char cmsgbuf
[CMSG_SPACE(sizeof(recv_fd
))];
1019 struct cmsghdr
* p_cmsg
;
1021 vec
.iov_base
= &recvchar
;
1022 vec
.iov_len
= sizeof(recvchar
);
1023 msg
.msg_name
= NULL
;
1024 msg
.msg_namelen
= 0;
1027 msg
.msg_control
= cmsgbuf
;
1028 msg
.msg_controllen
= sizeof(cmsgbuf
);
1030 /* In case something goes wrong, set the fd to -1 before the syscall */
1031 p_fd
= (int*)CMSG_DATA(CMSG_FIRSTHDR(&msg
));
1033 retval
= recvmsg(sock_fd
, &msg
, 0);
1038 p_cmsg
= CMSG_FIRSTHDR(&msg
);
1041 die("no passed fd");
1043 /* We used to verify the returned cmsg_level, cmsg_type and cmsg_len here,
1044 * but Linux 2.0 totally uselessly fails to fill these in.
1046 p_fd
= (int*)CMSG_DATA(p_cmsg
);
1050 die("no passed fd");
1055 #else /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1058 vsf_sysutil_send_fd(int sock_fd
, int send_fd
)
1064 vec
.iov_base
= &send_char
;
1066 msg
.msg_name
= NULL
;
1067 msg
.msg_namelen
= 0;
1070 msg
.msg_accrights
= (caddr_t
) &send_fd
;
1071 msg
.msg_accrightslen
= sizeof(send_fd
);
1072 retval
= sendmsg(sock_fd
, &msg
, 0);
1080 vsf_sysutil_recv_fd(int sock_fd
)
1087 vec
.iov_base
= &recv_char
;
1089 msg
.msg_name
= NULL
;
1090 msg
.msg_namelen
= 0;
1093 msg
.msg_accrights
= (caddr_t
) &recv_fd
;
1094 msg
.msg_accrightslen
= sizeof(recv_fd
);
1095 retval
= recvmsg(sock_fd
, &msg
, 0);
1102 die("no passed fd");
1107 #endif /* !VSF_SYSDEP_NEED_OLD_FD_PASSING */
1109 #ifndef VSF_SYSDEP_HAVE_UTMPX
1112 vsf_insert_uwtmp(const struct mystr
* p_user_str
,
1113 const struct mystr
* p_host_str
)
1120 vsf_remove_uwtmp(void)
1124 #else /* !VSF_SYSDEP_HAVE_UTMPX */
1126 /* IMHO, the pam_unix module REALLY should be doing this in its SM component */
1128 static int s_uwtmp_inserted
;
1129 static struct utmpx s_utent
;
1132 vsf_insert_uwtmp(const struct mystr
* p_user_str
,
1133 const struct mystr
* p_host_str
)
1135 if (sizeof(s_utent
.ut_line
) < 16)
1139 if (s_uwtmp_inserted
)
1141 bug("vsf_insert_uwtmp");
1144 struct mystr line_str
= INIT_MYSTR
;
1145 str_alloc_text(&line_str
, "vsftpd:");
1146 str_append_ulong(&line_str
, vsf_sysutil_getpid());
1147 if (str_getlen(&line_str
) >= sizeof(s_utent
.ut_line
))
1149 str_free(&line_str
);
1152 vsf_sysutil_strcpy(s_utent
.ut_line
, str_getbuf(&line_str
),
1153 sizeof(s_utent
.ut_line
));
1154 str_free(&line_str
);
1156 s_uwtmp_inserted
= 1;
1157 s_utent
.ut_type
= USER_PROCESS
;
1158 s_utent
.ut_pid
= vsf_sysutil_getpid();
1159 vsf_sysutil_strcpy(s_utent
.ut_user
, str_getbuf(p_user_str
),
1160 sizeof(s_utent
.ut_user
));
1161 vsf_sysutil_strcpy(s_utent
.ut_host
, str_getbuf(p_host_str
),
1162 sizeof(s_utent
.ut_host
));
1163 vsf_sysutil_update_cached_time();
1164 s_utent
.ut_tv
.tv_sec
= vsf_sysutil_get_cached_time_sec();
1166 (void) pututxline(&s_utent
);
1168 updwtmpx(WTMPX_FILE
, &s_utent
);
1172 vsf_remove_uwtmp(void)
1174 if (!s_uwtmp_inserted
)
1178 s_uwtmp_inserted
= 0;
1179 s_utent
.ut_type
= DEAD_PROCESS
;
1180 vsf_sysutil_memclr(s_utent
.ut_user
, sizeof(s_utent
.ut_user
));
1181 vsf_sysutil_memclr(s_utent
.ut_host
, sizeof(s_utent
.ut_host
));
1182 s_utent
.ut_tv
.tv_sec
= 0;
1184 (void) pututxline(&s_utent
);
1186 vsf_sysutil_update_cached_time();
1187 s_utent
.ut_tv
.tv_sec
= vsf_sysutil_get_cached_time_sec();
1188 updwtmpx(WTMPX_FILE
, &s_utent
);
1191 #endif /* !VSF_SYSDEP_HAVE_UTMPX */