=head1	NAME

dksf - Interface to system functions

=head1	SYNOPSIS

  #include <dksf.h>

  int dksf_get_uname(char *buffer, size_t sz);
  int dksf_get_euname(char *buffer, size_t sz);
  int dksf_get_home(char *buffer, size_t sz);
  int dksf_get_ehome(char *buffer, size_t sz);
  int dksf_get_hostname(char *buffer, size_t sz);
  int dksf_get_domainname(char *buffer, size_t sz);
  int dksf_get_tempdir(char *buffer, size_t sz);
  int dksf_allowed_to_write(char *fn, int ignchk, int *rsn);
  FILE *dksf_msfo(char *fn, char *m, int ignchk, int *rsn);
  FILE *dksf_fopen(char *fn, char *mode);
  long dksf_get_maxpathlen(void);
  long dksf_get_maxfiles(void);
  int dksf_getcwd(char *buffer, size_t lgt);
  int dksf_get_executable(char *buf, size_t len, char *cd, char *pr);
  char *dksf_get_file_type_dot(char *name);
  int dksf_path_combine(char *buf, size_t len, char *p1, char *p2);
  int dksf_mkdir(char *path, int mode);
  int dksf_remove_file(char *filename);
  int dksf_remove_directory(char *filename);
  int dksf_chmod(char *path, int mode);
  int dksf_have_getuid(void);
  long dksf_getuid(void);
  int dksf_have_geteuid(void);
  long dksf_geteuid(void);
  int dksf_have_getgid(void);
  long dksf_getgid(void);
  int dksf_have_getegid(void);
  long dksf_getegid(void);
  int dksf_have_getpid(void);
  long dksf_getpid(void);
  int dksf_have_getppid(void);
  long dksf_getppid(void);
  int dksf_have_getpgrp(void);
  long dksf_getpgrp(void);
  int dksf_have_getpgid(void);
  long dksf_getpgid(long p);
  dk_stat_t *dkstat_open(char *filename);
  void dkstat_close(dk_stat_t *ptr);
  int dkstat_filetype(dk_stat_t *ptr);
  int dkstat_permissions(dk_stat_t *ptr);
  unsigned long dkstat_inode(dk_stat_t *ptr);
  unsigned long dkstat_device(dk_stat_t *ptr);
  unsigned long dkstat_rdevice(dk_stat_t *ptr);
  unsigned long dkstat_nlinks(dk_stat_t *ptr);
  dk_long_long_unsigned_t dkstat_size(dk_stat_t *ptr);
  dk_long_long_unsigned_t dkstat_size_ok(dk_stat_t *ptr, int *ok);
  long dkstat_uid(dk_stat_t *ptr);
  long dkstat_gid(dk_stat_t *ptr);
  char *dkstat_ctime(dk_stat_t *ptr);
  char *dkstat_mtime(dk_stat_t *ptr);
  char *dkstat_atime(dk_stat_t *ptr);
  dk_dir_t *dkdir_open(char *name);
  void dkdir_close(dk_dir_t *ptr);
  int dkdir_next(dk_dir_t *ptr);
  char *dkdir_get_fullname(dk_dir_t *ptr);
  char *dkdir_get_shortname(dk_dir_t *ptr);
  int dkdir_filetype(dk_stat_t *ptr);
  int dkdir_permissions(dk_stat_t *ptr);
  unsigned long dkdir_inode(dk_stat_t *ptr);
  unsigned long dkdir_device(dk_stat_t *ptr);
  unsigned long dkdir_rdevice(dk_stat_t *ptr);
  unsigned long dkdir_nlinks(dk_stat_t *ptr);
  dk_long_long_unsigned_t dkdir_size(dk_stat_t *ptr);
  dk_long_long_unsigned_t dkdir_size_ok(dk_stat_t *ptr, int *ok);
  long dkdir_uid(dk_stat_t *ptr);
  long dkdir_gid(dk_stat_t *ptr);
  char *dkdir_ctime(dk_stat_t *ptr);
  char *dkdir_mtime(dk_stat_t *ptr);
  char *dkdir_atime(dk_stat_t *ptr);
  dk_fne_t *dkfne_open(char *name, int files, int dirs);
  void dkfne_close(dk_fne_t *ptr);
  int dkfne_next(dk_fne_t *ptr);
  char *dkfne_get_fullname(dk_fne_t *ptr);
  char *dkfne_get_shortname(dk_fne_t *ptr);

=head1	DESCRIPTION

=over 2

=item	* int dksf_get_uname(char *buffer, size_t sz);

searches for the file name of the current user (the one who started the
process) and writes it to the I<buffer>. The I<sz> argument is the
size of the buffer in bytes.


=item	* int dksf_get_euname(char *buffer, size_t sz);

searches for the effective user name of the current user
and writes it to the I<buffer> of I<sz> bytes.

=item	* int dksf_get_home(char *buffer, size_t sz);

searches for the HOME directory of the current user and writes
it to the I<buffer> of I<sz> bytes.

=item	* int dksf_get_ehome(char *buffer, size_t sz);

searches for the HOME directory of the current effective user
and writes it to the buffer.

=item	* int dksf_get_hostname(char *buffer, size_t sz);

gets the host name of the current host and write it to the buffer.

=item	* int dksf_get_domainname(char *buffer, size_t sz);

gets the DNS domain name of the current host and writes it to the buffer.

=item	* int dksf_get_tempdir(char *buffer, size_t sz);

searches for a directory which can be used for temporary files and
writes it to the buffer.

The TMPDIR, TEMP and TMP environment variables are used in this search.

=item	* int dksf_allowed_to_write(char *fn, int ignchk, int *rsn);

checks whether or not writing to a file should be allowed. This is not
permission checking, this function was made to avoid symlink attacks.
The I<fn> argument is the filename. I<ignchk> contains a bit combinations
for checks to skip, normally this should be 0.
If writing is denied, the identifier of the failed test is written to
a variable I<rsn> points to (if I<rsn> != I<NULL>).

Write access is denied if I<fn> is a symbolic link and
any of the conditions below is fullfilled:

=over 4

=item	+ DK_SF_SEC_OWNER

The link owner is not the owner of the link destination file.

=item	+ DK_SF_SEC_WG

The link resides in a group writable directory.

=item	+ DK_SF_SEC_WO

The link resides in a world writable directory.

=back

=item	* FILE *dksf_msfo(char *fn, char *m, int ignchk, int *rsn);

should be used instead of fopen() when opening files for write
access. This function calls dksf_allowed_to_write() to inspect
whether we should really attempt to open the file for writing.
If this check is passed, the function calls fopen() to really open
the file.

The I<ignchk> and I<rsn> arguments are passed to dksf_allowed_to_write(),
I<m> is the mode used for fopen().

=item	* FILE *dksf_fopen(char *fn, char *mode);

is designed to replace fopen() calls in existing sources.

This function calls dksf_msfo(fn, mode, 0, NULL) to open a file.

=item	* long dksf_get_maxpathlen(void);

returns the maximum number of bytes in a file name.

=item	* long dksf_get_maxfiles(void);

returns the maximum number of open files.

=item	* int dksf_getcwd(char *buffer, size_t lgt);

estimates the current working directory and writes the path name
to the buffer.

=item	* int dksf_get_executable(char *buf, size_t len, char *cd, char *pr);

tries to find the full file name of the executable file currently running.
Output is written to the buffer I<buf> of length I<len>.

The I<cd> argument is the current working directory, I<pr> is  the command
as typed in at the prompt (argv[0]).

=item	* char *dksf_get_file_type_dot(char *name);

returns a pointer to the file name extension (pointer to the dot)
if an extensions exists, or I<NULL> if there is no extension.

=item	* int dksf_path_combine(char *buf, size_t len, char *p1, char *p2);

combines to file name paths I<p1> and I<p2> and writes the result
to the pointer I<buf> of length I<len>.

I<p1> must be an absolute path name, I<p2> may be absolute or relative
to I<p1>.

=item	* int dksf_mkdir(char *path, int mode);

creates a directory and sets permissions as specified in mode.

Note: It is strongly recommended to use a combination of
I<DK_PERM_...> constants.

=item	* int dksf_remove_file(char *filename);

removes a file.


=item	* int dksf_remove_directory(char *filename);

removes a directory and all the contents of the directory.
It is suggested to use this function with care.

=item	* int dksf_chmod(char *path, int mode);

changes access permissions to a file as specified in mode.

Note: It is stronlgy recommended to use the I<DK_PERM_...>
values here.

=item	* int dksf_have_getuid(void);

checks whether or not the dksf_getuid() will return a usefull
result (this requires a getuid() function or something
equivalent).

=item	* long dksf_getuid(void);

returns the UID of the current user (the user which owns
the process).

=item	* int dksf_have_geteuid(void);

checks whether or not the dksf_geteuid() function will
return a usefull result.

=item	* long dksf_geteuid(void);

returns the effective UID.

=item	* int dksf_have_getgid(void);

checks whether or not dksf_getgid() will return a usefull
result.

=item	* long dksf_getgid(void);

returns the GID of the current user.

=item	* int dksf_have_getegid(void);

checks whether or not dksf_getegid() will return a usefull
result.

=item	* long dksf_getegid(void);

returns the effective GID.

=item	* int dksf_have_getpid(void);

checks whether or not dksf_getpid() will return a usefull
result.

=item	* long dksf_getpid(void);

returns the PID of the current process.

=item	* int dksf_have_getppid(void);

checks whether or not dksf_getppid() will return a usefull
result.

=item	* long dksf_getppid(void);

returns the PID of the parent process.

=item	* int dksf_have_getpgrp(void);

checks whether or not dksf_getpgrp() will return a usefull
result.

=item	* long dksf_getpgrp(void);

returns the process group ID of the current process.

=item	* int dksf_have_getpgid(void);

checks whether or not dksf_getpgid() will return a usefull
result.

=item	* long dksf_getpgid(long p);

returns the process group ID of the process given by
PID I<p>.

=item	* Obtaining information about files

To obtain information about a file the dkstat_open() function
dynamically creates a I<dk_stat_t> and fills it with data.

After usage the I<dk_stat_t> must be released using
the dkstat_close() function.

The other functions are used to retrieve information from
the I<dk_stat_t>.

=over 4

=item	+ dk_stat_t *dkstat_open(char *filename);

allocates memory for a I<dk_stat_t> and writes information about
the file given by I<filename> into it.

The dkstat_close() function should be used to release the 
I<dk_stat_t> and the ressources assigned to it.


=item	+ void dkstat_close(dk_stat_t *ptr);

releases a I<dk_stat_t> allocated by dkstat_open().

=item	+ int dkstat_filetype(dk_stat_t *ptr);

returns the file type as a combination of
I<DK_FT_...> constants.

=item	+ int dkstat_permissions(dk_stat_t *ptr);

returns the permissions to the file as a combination
of I<DK_PERM_...> values.

=item	+ unsigned long dkstat_inode(dk_stat_t *ptr);

returns the inode number of the file.

=item	+ unsigned long dkstat_device(dk_stat_t *ptr);

returns the device number of the file.

=item	+ unsigned long dkstat_rdevice(dk_stat_t *ptr);

returns the relative device number of the file.

=item	+ unsigned long dkstat_nlinks(dk_stat_t *ptr);

returns the number of links.

=item	+ dk_long_long_unsigned_t dkstat_size(dk_stat_t *ptr);

returns the file size.

=item	+ dk_long_long_unsigned_t dkstat_size_ok(dk_stat_t *ptr, int *ok);

returns the file size.
The I<ok> parameter is a pointer to an I<int> variable. If an error occurs
during file size conversion, this variable is set to 1. Otherwise the
variable is unchanged.

=item	+ long dkstat_uid(dk_stat_t *ptr);

returns the file owner's UID.

=item	+ long dkstat_gid(dk_stat_t *ptr);

returns the file group's GID.

=item	+ char *dkstat_ctime(dk_stat_t *ptr);

returns a pointer to a string containing the file creation time
as i.e. "2003/11/25 20:44:23".

The string is stored inside the I<dk_stat_t>, after releasing
the I<dk_stat_t> it is no longer accessable.

=item	+ char *dkstat_mtime(dk_stat_t *ptr);

returns a pointer to a string containing the last modification
time stamp.

=item	+ char *dkstat_atime(dk_stat_t *ptr);

returns a pointer to a string containing the last access timestamp.

=back

=item	* Directory traversal

To traverse a directory, a I<dk_dir_t> structure is created by
calling dkdir_open(), the directory name is given as I<name>
parameter. After usage this structure and the assigned ressources
must be released using the dkdir_close() function.

Traversal is done by calling dkdir_next(). This function indicates
success if there was yet another directory entry found. When doing
recursive traversal take care of the "." and ".." entries.

If an entry was found, the functions
dkdir_get_fullname(),
dkdir_get_shortname(),
dkdir_filetype(),
dkdir_permissions(),
dkdir_inode(),
dkdir_device(),
dkdir_rdevice(),
dkdir_nlinks(),
dkdir_size(),
dkdir_size_ok(),
dkdir_uid(),
dkdir_gid(),
dkdir_ctime(),
dkdir_mtime() and
dkdir_atime()
can be used to obtain information about the entry.


=over	4

=item	+ dk_dir_t *dkdir_open(char *name);

creates a I<dk_dir_t> structure.

=item	+ void dkdir_close(dk_dir_t *ptr);

releases a I<dk_dir_t> structure.

=item	+ int dkdir_next(dk_dir_t *ptr);

tries to find a directory entry.

=item	+ char *dkdir_get_fullname(dk_dir_t *ptr);

returns the full name (complete path name) of the 
directory entry.

The buffer is overwritten by the next dkdir_next()
call and released by dkdir_close(). In both cases
the pointer can not longer be used.

=item	+ char *dkdir_get_shortname(dk_dir_t *ptr);

returns the short name (without the leading directory
path) of the directory entry.

The buffer is overwritten by the next dkdir_next()
call and released by dkdir_close(). In both cases
the pointer can not longer be used.

=item	+ int dkdir_filetype(dk_stat_t *ptr);

returns the file type as combination of
I<DK_FT_...> values.

=item	+ int dkdir_permissions(dk_stat_t *ptr);

returns the file permissions as a combination of
I<DK_PERM_...> values.

=item	+ unsigned long dkdir_inode(dk_stat_t *ptr);

returns the inode number.

=item	+ unsigned long dkdir_device(dk_stat_t *ptr);

returns the device number.

=item	+ unsigned long dkdir_rdevice(dk_stat_t *ptr);

returns the relative device number.

=item	+ unsigned long dkdir_nlinks(dk_stat_t *ptr);

returns the number of links.

=item	+ dk_long_long_unsigned_t dkdir_size(dk_stat_t *ptr);

returns the file size.

=item	+ dk_long_long_unsigned_t dkdir_size_ok(dk_stat_t *ptr, int *ok);

returns the file size. The I<ok> parameter is a pointer to an
I<int> variable. If size conversion to the long long type fails, this
variable is set to 1, otherwise it is unchanged.

=item	+ long dkdir_uid(dk_stat_t *ptr);

returns the file owner's UID.

=item	+ long dkdir_gid(dk_stat_t *ptr);

returns the file group's GID.

=item	+ char *dkdir_ctime(dk_stat_t *ptr);

returns a pointer to a buffer containing the file creation time
stamp as text.

The buffer is overwritten by the next dkdir_next()
call and released by dkdir_close(). In both cases
the pointer can not longer be used.

=item	+ char *dkdir_mtime(dk_stat_t *ptr);

returns a pointer to a buffer containing the file modification
timestamp as text.

The buffer is overwritten by the next dkdir_next()
call and released by dkdir_close(). In both cases
the pointer can not longer be used.

=item	+ char *dkdir_atime(dk_stat_t *ptr);

returns a pointer to a buffer containing the file access 
timestamp as text.

The buffer is overwritten by the next dkdir_next()
call and released by dkdir_close(). In both cases
the pointer can not longer be used.

=back

=item	* Expanding wildcards in file names

This expansion process is sometimes referred to as "globbing".

Some command interpreters (typically invoked by the commands
"COMMAND.COM" or "CMD.EXE") do not expand "?" and "*" wildcards
in file names as real shells do. They leave it up to each program
to deal with it.

To search for matching files and/or directories the
dkfne_open() function creates a I<dk_fne_t> structure for a
I<name> containing wildcards. The I<files> and I<dirs> parameter
are simple flags indicating by non-zero values that names for
files and/or directories are acceptable. In short: if you want
to have names of regular files only, set the I<dirs> parameter
to 0.
The dkfne_close() function must be used to release the
I<dk_fne_t> structure and the ressources assigned to it.

Finding names matching the pattern is done using the
dkfne_next() function. This function indicates success if there
is yet another directory entry matching the pattern and the
I<files>/I<dirs> criteria. In this case the
dkfne_get_fullname() and/or dkfne_get_shortname() functions
can be used to retrieve the directory entry name.

=over	4

=item	+ dk_fne_t *dkfne_open(char *name, int files, int dirs);

creates a I<dk_fne_t> structure and sets it up for the pattern
specified in I<name> and the search criteria given in
I<files> and I<dirs>. The dkfne_close() function must be
used to release the structure and assigned ressources when
the structure is no longer needed.

=item	+ void dkfne_close(dk_fne_t *ptr);

releases the I<dk_fne_t> structure and assigned ressources.

=item	+ int dkfne_next(dk_fne_t *ptr);

checks whether or not there is yet another directory entry
available matching the pattern and search criteria specified
as arguments to dkfne_opne().

=item	+ char *dkfne_get_fullname(dk_fne_t *ptr);

retrieves a "full" path name (which may be a relative name
if the I<name> argument was a relative path name).

=item	+ char *dkfne_get_shortname(dk_fne_t *ptr);

retrieves the short name.

=back

=back

=head1	RETURN VALUE

All functions returning an I<int> value return a non-zero value on
success and zero on error unless stated otherwise.

Functions returning pointers return a valid pointer on success,
I<NULL> on error.

=head1	SECURITY ISSUES

=head2	SUID/SGID programs

You should not use the following functions in SUID/SGID programs:

=over 2

=item	dksf_get_uname()

=item	dksf_get_euname()

=item	dksf_get_home()

=item	dksf_get_ehome()

=item	dksf_get_hostname()

=item	dksf_get_domainname()

=item	dksf_get_tempdir()

=item	dksf_get_executable()

=back

These functions use environment variables and/or retrieve data
from user writable parts in the Windows registry.
If they fail to retrieve settings in a traditional way the provide
fallback data. I.e. if dksf_get_tempdir() can not find a directory
for temporary files but there is information about the user's home
directory available, the home directory is used for temporary files
too (because we hope it is writable for the current user).

This behaviour is ok for "normal" programs because it allows to
recover from configuration problems but completely inacceptable
for SUID/SGID programs.

=head2	CHECK FOR AVAILABILITY

When using dksf_getpid(), dksf_getppid(), dksf_getuid(),
dksf_geteuid(), dksf_getgid(), dksf_getegid(), dksf_getpgrp()
or dksf_getpgid() it is recommended to use I<dksf_have_...()>
to check whether or not the functions return usefull values.

=head1	SEE ALSO

The dksfc.h header files contains definitions for the
I<DK_FT_...> and I<DK_PERM_...> values.

=head1	AUTHOR

Dirk Krause

=head1	COPYRIGHT AND LICENSE

Copyright (c) 2001-2008, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above
   copyright notice, this list of conditions and the
   following disclaimer.

 * Redistributions in binary form must reproduce the above
   copyright notice, this list of conditions and the following
   disclaimer in the documentation and/or other materials
   provided with the distribution.

 * Neither the name of the Dirk Krause nor the names of
   contributors may be used to endorse or promote products
   derived from this software without specific prior written
   permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
