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