netatalk  4.6.0
Free and Open Source Apple Filing Protocol (AFP) Server
Loading...
Searching...
No Matches
netatalk_conf.c File Reference
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <inttypes.h>
#include <stdbool.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pwd.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <time.h>
#include <utime.h>
#include <bstrlib.h>
#include <iniparser.h>
#include <atalk/afp.h>
#include <atalk/util.h>
#include <atalk/logger.h>
#include <atalk/ea.h>
#include <atalk/globals.h>
#include <atalk/iniparser_util.h>
#include <atalk/errchk.h>
#include <atalk/unix.h>
#include <atalk/cnid.h>
#include <atalk/dsi.h>
#include <atalk/asp.h>
#include <atalk/uuid.h>
#include <atalk/netatalk_conf.h>

Macros

#define VOLPASSLEN   8
#define UUID_PRINTABLE_STRING_LENGTH   37
#define IS_VAR(a, b)
#define EABUFSZ   4
#define MAXPRESETLEN   100
#define MAXVAL   1024

Functions

void conf_testutil_set_lastvid (uint16_t vid)
 Test seam: set the volume-id counter.
static int rewrite_vol_uuid_conf (AFPObj *obj, struct vol *Volumes)
static char * get_vol_uuid (const AFPObj *obj, const char *volname)
 Get a volume's UUID from the config file.
static int do_check_ea_support (const struct vol *vol)
 Check if the underlying filesystem supports EAs.
static void check_ea_support (struct vol *vol)
static int check_vol_acl_support (const struct vol *vol)
 Check whether a volume supports ACLs.
static char * volxlate (const AFPObj *obj, char *dest, size_t destlen, const char *src, const struct passwd *pwd, const char *path, const char *volname)
 Handle variable substitutions.
static int accessvol (const AFPObj *obj, const char *args, const char *name)
 check user access list for volume
static int hostaccessvol (const AFPObj *obj, const char *volname, const char *args)
 check host access list for volume
int netatalk_readbuf_clamp (int readbuf, uint32_t quantum, uint64_t limit)
static const char * getoption_str (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, const char *defval)
 Get option string from config, use default value if not set.
static char * getoption_strdup (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, const char *defval)
 Get option string from config, use default value if not set.
static char * getoption_strdup_alias (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *alias, const char *defsec, const char *defval, const char *alias_warn, bool *alias_used)
 Get a string option with a deprecated alias.
static int conf_parse_bool (const char *opt, const char *val)
 Parse one boolean config value strictly.
static int conf_key_present (INIPARSER_DICTIONARY *conf, const char *opt)
 Whether a [Global] key is present with a non-empty value.
static int conf_int_key_usable (INIPARSER_DICTIONARY *conf, const char *opt, int min, int max)
 Whether a [Global] int key holds a value within bounds.
static int getoption_bool (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, int defval)
 Get boolean option from config, use default value if not set.
int safe_atoi (const char *str, const char *param_name, int min_val, int max_val, int default_val)
 Safe string to integer conversion with bounds checking.
static int getoption_int (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, int defval)
 Get integer option from config, use default value if not set.
static uint32_t getoption_uint32_strict (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, uint32_t minval, uint32_t maxval, uint32_t defval)
 Get uint32 option from config, use default value if unset or invalid.
static int vdgoption_bool (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, int defval)
 Get boolean option from volume, default section or global - use default value if not set.
static const char * vdgoption_str (INIPARSER_DICTIONARY *conf, const char *vol, const char *opt, const char *defsec, const char *defval)
 Get string option from volume, default section or global - use default value if not set.
static void apply_multiprotocol_defaults (AFPObj *obj, const char *volname)
 Apply the multi protocol coherency defaults to the process options.
static void log_ea_format_advice (const struct vol *volume, const char *ea_setting)
 Log the storage-format implications of the coherency posture.
static struct volcreatvol (AFPObj *obj, const struct passwd *pwd, const char *section, const char *name, const char *path_in, const char *preset)
 Create volume struct.
static int volfile_changed (AFPObj *obj)
static int vol_section (const char *sec)
static int readvolfile (AFPObj *obj, const struct passwd *pwent)
 Read volumes from iniconfig and add the volumes contained within to the global volume list.
static int setextmap (char *ext, char *type, char *creator)
static int extmap_cmp (const void *map1, const void *map2)
static void sortextmap (void)
static void free_extmap (void)
static int ext_cmp_key (const void *key, const void *obj)
struct extmapgetextmap (const char *path)
struct extmapgetdefextmap (void)
static int readextmap (const char *file)
void volume_unlink (struct vol *volume)
void volume_free (struct vol *vol)
 Free all resources allocated in a struct vol in load_afp_conf_vols().
int load_charset (struct vol *vol)
int load_afp_conf_vols (AFPObj *obj, lv_flags_t flags)
 Initialize volumes and load ini configfile.
void unload_volumes (AFPObj *obj)
struct volgetvolumes (void)
int conf_cnid_scheme_in_use (const AFPObj *obj, const char *scheme)
 Whether any configured volume resolves to the given CNID scheme.
struct volgetvolbyvid (const uint16_t vid)
static char * getuserbypath (const char *path)
 get username by path
struct volgetvolbypath (AFPObj *obj, const char *path)
 Search volume by path, creating user home vols as necessary.
struct volgetvolbyname (const char *name)
int afp_config_parse (AFPObj *AFPObj, char *processname)
void afp_config_free (AFPObj *obj)

Variables

static const char UUID_FILE_HEADER []
static int have_uservol = 0
static struct volVolumes = NULL
static uint16_t lastvid = 0
static struct extmapExtmap = NULL
static struct extmapDefextmap = NULL
static int Extmap_cnt

Macro Definition Documentation

◆ EABUFSZ

#define EABUFSZ   4

◆ IS_VAR

#define IS_VAR ( a,
b )
Value:
(strncmp((a), (b), 2) == 0)

◆ MAXPRESETLEN

#define MAXPRESETLEN   100

◆ MAXVAL

#define MAXVAL   1024

◆ UUID_PRINTABLE_STRING_LENGTH

#define UUID_PRINTABLE_STRING_LENGTH   37

◆ VOLPASSLEN

#define VOLPASSLEN   8

Function Documentation

◆ accessvol()

int accessvol ( const AFPObj * obj,
const char * args,
const char * name )
static

check user access list for volume

This function wants a string consisting of names seperated by comma or space. Names may be quoted within a pair of quotes. Groups are denoted by a leading @ symbol.

Example:

user1 user2, user3, @group1, @group2, @group3, "user name1", "@group name1"
Parameters
[in]objAFPObj containing user and group info
[in]argsaccess list string; NULL allows everybody to have access
[in]nameuser name to check
Returns
-1: no list
0: list exists, but name isn't in it
1: in list

◆ afp_config_free()

void afp_config_free ( AFPObj * obj)

get rid of any allocated afp_option buffers.

◆ afp_config_parse()

int afp_config_parse ( AFPObj * AFPObj,
char * processname )

Initialize an AFPObj and options from ini config file

◆ apply_multiprotocol_defaults()

void apply_multiprotocol_defaults ( AFPObj * obj,
const char * volname )
static

Apply the multi protocol coherency defaults to the process options.

Defaults the settings safe concurrent access by other processes (Samba, NFS, local tools) requires: strict locking on, dircache validation on every access, rfork caching off, (Solaris) F_SHARE reservations on. Defaults only: an explicit afp.conf setting wins, with a warning when it weakens coherency. Idempotent across config reloads.

Parameters
[in]objhandle (options are process-global)
[in]volnamevolume name, for the log messages

◆ check_ea_support()

void check_ea_support ( struct vol * vol)
static

◆ check_vol_acl_support()

int check_vol_acl_support ( const struct vol * vol)
static

Check whether a volume supports ACLs.

Parameters
[in]volvolume
Returns
0 if not, 1 if yes

◆ conf_cnid_scheme_in_use()

int conf_cnid_scheme_in_use ( const AFPObj * obj,
const char * scheme )

Whether any configured volume resolves to the given CNID scheme.

Scans the loaded volume list, then the [Homes] section: homes volumes are instantiated per-user at login, so outside AFP sessions they never appear in the list. The section's scheme is resolved the same way creatvol() resolves it (section -> preset -> global -> compiled default).

◆ conf_int_key_usable()

int conf_int_key_usable ( INIPARSER_DICTIONARY * conf,
const char * opt,
int min,
int max )
static

Whether a [Global] int key holds a value within bounds.

Explicitness probe for bounded int options: a value that does not parse or falls outside [min, max] was replaced by the default, so it is not an operator instruction and must not suppress a coherency default.

Parameters
[in]confconfig handle
[in]optoption name
[in]minlowest accepted value
[in]maxhighest accepted value
Returns
1 when the key is set to a value in [min, max], else 0

◆ conf_key_present()

int conf_key_present ( INIPARSER_DICTIONARY * conf,
const char * opt )
static

Whether a [Global] key is present with a non-empty value.

The explicitness probe for the multi protocol defaults: "the operator said something" is recorded separately from the parsed value so it stays correct when compiled defaults change. Empty values ("key = ") count as unset, matching every parse in this file. Note the deliberate asymmetry with booleans: a boolean only counts as explicit when it parses (conf_parse_bool() != -1, invalid = warned + unset), while int options count on presence because safe_atoi() already resolved an invalid value to the default with its own warning.

Parameters
[in]confconfig handle
[in]optoption name
Returns
1 when the key is set non-empty in [Global], else 0

◆ conf_parse_bool()

int conf_parse_bool ( const char * opt,
const char * val )
static

Parse one boolean config value strictly.

Accepted spellings (case-insensitive, whole-word): true: yes, y, true, t, on, enabled, 1 false: no, n, false, f, off, disabled, 0

Parameters
[in]optoption name, for the warning
[in]valraw config value (may be NULL or empty = unset)
Returns
1 (true), 0 (false), or -1 (unset, or invalid with a warning)

◆ conf_testutil_set_lastvid()

void conf_testutil_set_lastvid ( uint16_t vid)

Test seam: set the volume-id counter.

Saturating it (UINT16_MAX) makes the next creatvol() take the vid-overflow failure path. Lives here because the static it mutates does; declared in the test-local subtests_conf.h, not the public API.

Parameters
[in]vidnew counter value (unload_volumes() resets it to 0)

◆ creatvol()

struct vol * creatvol ( AFPObj * obj,
const struct passwd * pwd,
const char * section,
const char * name,
const char * path_in,
const char * preset )
static

Create volume struct.

Parameters
[in]objhandle
[in]pwdstruct passwd of logged in user, may be NULL in master afpd
[in]sectionvolume name wo variables expanded (exactly as in iniconfig)
[in]namevolume name
[in]path_involume path
[in]presetdefault preset, may be NULL
Returns
vol on success, NULL on error

◆ do_check_ea_support()

int do_check_ea_support ( const struct vol * vol)
static

Check if the underlying filesystem supports EAs.

If not, switch to ea=ad. As we can't check (requires write access) on ro-volumes, we assume ea=sys.

◆ ext_cmp_key()

int ext_cmp_key ( const void * key,
const void * obj )
static

◆ extmap_cmp()

int extmap_cmp ( const void * map1,
const void * map2 )
static

◆ free_extmap()

void free_extmap ( void )
static

◆ get_vol_uuid()

char * get_vol_uuid ( const AFPObj * obj,
const char * volname )
static

Get a volume's UUID from the config file.

If there is none, it is generated and stored there.

Returns
pointer to allocated storage on success, NULL on error.

◆ getdefextmap()

struct extmap * getdefextmap ( void )

◆ getextmap()

struct extmap * getextmap ( const char * path)

◆ getoption_bool()

int getoption_bool ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
int defval )
static

Get boolean option from config, use default value if not set.

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]defvalif neither "vol" nor "defsec" contain "opt" return "defval"
Returns
const option string from "vol" or "defsec", or "defval" if not found

◆ getoption_int()

int getoption_int ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
int defval )
static

Get integer option from config, use default value if not set.

Uses safe_atoi() for bounds-checked string-to-integer conversion with overflow detection and non-numeric character rejection.

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]defvalif neither "vol" nor "defsec" contain "opt" return "defval"
Returns
int option from "vol" or "defsec", or "defval" if not found

◆ getoption_str()

const char * getoption_str ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
const char * defval )
static

Get option string from config, use default value if not set.

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]defvalif neither "vol" nor "defsec" contain "opt" return "defval"
Returns
const option string from "vol" or "defsec", or "defval" if not found

◆ getoption_strdup()

char * getoption_strdup ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
const char * defval )
static

Get option string from config, use default value if not set.

Returns a dynamically allocated string which caller must free

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]defvalif neither "vol" nor "defsec" contain "opt" return "defval"
Returns
dynamically allocated option string from "vol" or "defsec", or "defval" if not found

◆ getoption_strdup_alias()

char * getoption_strdup_alias ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * alias,
const char * defsec,
const char * defval,
const char * alias_warn,
bool * alias_used )
static

Get a string option with a deprecated alias.

The canonical option wins when it has a non-empty value. A non-empty alias is still reported even when the canonical option is also present, so stale deprecated settings are not silently hidden.

Parameters
[in]confconfig handle
[in]volsection name
[in]optcanonical option
[in]aliasdeprecated option name
[in]defsecfallback section for both options
[in]defvaldefault value when neither option is set
[in]alias_warnwarning to emit when the alias is set
[out]alias_usedset when the returned value is from the alias; may be NULL
Returns
dynamically allocated option string, or NULL on allocation failure

◆ getoption_uint32_strict()

uint32_t getoption_uint32_strict ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
uint32_t minval,
uint32_t maxval,
uint32_t defval )
static

Get uint32 option from config, use default value if unset or invalid.

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]minvalminimum accepted value
[in]maxvalmaximum accepted value
[in]defvalif unset or out of range return "defval"
Returns
uint32 option from "vol" or "defsec", or "defval"

◆ getuserbypath()

char * getuserbypath ( const char * path)
static

get username by path

getvolbypath() assumes that the user home directory has the same name as the username. If that is not true, getuserbypath() is called and tries to retrieve the username from the directory owner, checking its validity.

Parameters
[in]pathabsolute volume path
Returns
NULL if no match is found, pointer to username if successful

◆ getvolbyname()

struct vol * getvolbyname ( const char * name)

◆ getvolbypath()

struct vol * getvolbypath ( AFPObj * obj,
const char * path )

Search volume by path, creating user home vols as necessary.

Path may be absolute or relative. Ordinary volume structs are created when the ini config is initially parsed (load_afp_conf_vols()), but user volumes are as load_afp_conf_vols() only can create the user volume of the logged in user in an AFP session in afpd, but not when called from e.g. cnid_metad or dbd. Both cnid_metad and dbd thus need a way to lookup and create struct vols for user home by path. This is what this func does as well.

  1. Search "normal" volume list
  2. Check if theres a [Homes] section, load_afp_conf_vols() remembers this for us
  3. If there is, match "path" with "basedir regex" to get the user home parent dir
  4. Built user home path by appending the basedir matched in (3) and appending the username
  5. The next path element then is the username
    • getvolbypath() assumes that the user home directory has the same name as the username. If that is not true, getuserbypath() is called and tries to retrieve the username from the directory owner, checking its validity
  6. Append [Homes]->path subdirectory if defined
  7. Create volume
Parameters
[in,out]objhandle
[in]pathpath, may be relative or absolute

◆ getvolbyvid()

struct vol * getvolbyvid ( const uint16_t vid)

◆ getvolumes()

struct vol * getvolumes ( void )

◆ hostaccessvol()

int hostaccessvol ( const AFPObj * obj,
const char * volname,
const char * args )
static

check host access list for volume

This function wants a string consisting of ip addresses or networks in CIDR notation seperated by comma or space.

Parameters
[in]objAFPObj containing client info
[in]volnamevolume name (not used)
[in]argsaccess list string; NULL allows all hosts to have access
Returns
-1: no list
0: list exists, but host isn't in it
1: host is in list

◆ load_afp_conf_vols()

int load_afp_conf_vols ( AFPObj * obj,
lv_flags_t flags )

Initialize volumes and load ini configfile.

Parameters
[in]objhandle
[in]flagsflags controlling volume load behaviour:
  • LV_DEFAULT: load shares in a user/session context, this honors authorization
  • LV_ALL: load shares that are available in the config file
  • LV_FORCE: reload file even though the timestamp wasn't changed

◆ load_charset()

int load_charset ( struct vol * vol)

Load charsets for a volume

◆ log_ea_format_advice()

void log_ea_format_advice ( const struct vol * volume,
const char * ea_setting )
static

Log the storage-format implications of the coherency posture.

States which metadata format the volume uses, since only 'ea = samba' is readable by Samba, and points an ea = samba volume that has not declared multi protocol at the switch. The format is never changed implicitly: the other accessor may be NFS or a local process, and existing metadata is not converted in place.

Parameters
[in]volumethe volume
[in]ea_settingexplicit non-samba ea value ("sys", "ad", "none"), NULL when unset (auto-detect)

◆ netatalk_readbuf_clamp()

int netatalk_readbuf_clamp ( int readbuf,
uint32_t quantum,
uint64_t limit )

Bound dsireadbuf so dsireadbuf * quantum never exceeds limit. The limit always wins: on a constrained platform the result may drop below the usual dsireadbuf floor of 6, but never below 1. The quantum is never reduced here: frame acceptance must not change as a side effect of read-ahead sizing. A zero quantum cannot occur in the config path and is treated as "no limit".

◆ readextmap()

int readextmap ( const char * file)
static

◆ readvolfile()

int readvolfile ( AFPObj * obj,
const struct passwd * pwent )
static

Read volumes from iniconfig and add the volumes contained within to the global volume list.

This gets called from the forked afpd childs. The master now reads this too for Zeroconf announcements.

◆ rewrite_vol_uuid_conf()

int rewrite_vol_uuid_conf ( AFPObj * obj,
struct vol * Volumes )
static

◆ safe_atoi()

int safe_atoi ( const char * str,
const char * param_name,
int min_val,
int max_val,
int default_val )

Safe string to integer conversion with bounds checking.

Parameters
strString to convert
param_nameParameter name for error messages
min_valMinimum allowed value
max_valMaximum allowed value
default_valDefault value to return on error
Returns
Converted integer value or default_val on error

◆ setextmap()

int setextmap ( char * ext,
char * type,
char * creator )
static

◆ sortextmap()

void sortextmap ( void )
static

◆ unload_volumes()

void unload_volumes ( AFPObj * obj)

◆ vdgoption_bool()

int vdgoption_bool ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
int defval )
static

Get boolean option from volume, default section or global - use default value if not set.

Order of precedence: volume -> default section -> global -> default value

"vdg" means volume, default section or global

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]defvalif neither "vol", "defsec" nor global contain "opt" return "defval"
Returns
1 or 0 from "vol", "defsec" or global, or "defval" if not found

◆ vdgoption_str()

const char * vdgoption_str ( INIPARSER_DICTIONARY * conf,
const char * vol,
const char * opt,
const char * defsec,
const char * defval )
static

Get string option from volume, default section or global - use default value if not set.

Order of precedence: volume -> default section -> global -> default value

"vdg" means volume, default section or global

Parameters
[in]confconfig handle
[in]volvolume name (must be section name i.e. wo vars expanded)
[in]optoption
[in]defsecif "option" is not found in "vol", try to find it in section "defsec"
[in]defvalif neither "vol", "defsec" nor global contain "opt" return "defval"
Returns
const option string from "vol", "defsec" or global, or "defval" if not found

◆ vol_section()

int vol_section ( const char * sec)
static

◆ volfile_changed()

int volfile_changed ( AFPObj * obj)
static

◆ volume_free()

void volume_free ( struct vol * vol)

Free all resources allocated in a struct vol in load_afp_conf_vols().

Actually opening a volume (afp_openvol()) will allocate additional resources which are freed in closevol()

◆ volume_unlink()

void volume_unlink ( struct vol * volume)

Remove a volume from the linked list of volumes

◆ volxlate()

char * volxlate ( const AFPObj * obj,
char * dest,
size_t destlen,
const char * src,
const struct passwd * pwd,
const char * path,
const char * volname )
static

Handle variable substitutions.

here's what we understand:

$b -> basename of path
$c -> client ip/appletalk address
$d -> volume pathname on server
$f -> full name (whatever's in the gecos field)
$g -> group
$h -> hostname
$i -> client ip/appletalk address without port
$s -> server name (hostname if it doesn't exist)
$u -> username (guest is usually nobody)
$v -> volume name or basename if null
$$ -> $
Definition include/atalk/directory.h:140
Definition cnid_metad.c:111

This get's called from readvolfile with

path = NULL, volname = NULL for xlating the volumes path
path = path, volname = NULL for xlating the volumes name
... and from volumes options parsing code when xlating e.g. dbpath with
path = path, volname = volname
#define NULL
Definition utf8util.c:47

Using this information we can reject xlation of any variable depeninding on a login context which is not given in the afp master, where we must evaluate this whole stuff too for the Zeroconf announcements.

Variable Documentation

◆ Defextmap

struct extmap * Defextmap = NULL
static

◆ Extmap

struct extmap* Extmap = NULL
static

◆ Extmap_cnt

int Extmap_cnt
static

◆ have_uservol

int have_uservol = 0
static

whether there's generic user home share in config ("~" or "~/path", but not "~user")

◆ lastvid

uint16_t lastvid = 0
static

◆ UUID_FILE_HEADER

const char UUID_FILE_HEADER[]
static
Initial value:
=
"# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n"
"# This file is auto-generated by afpd\n"
"# and stores UUIDs for AFP volumes.\n\n"
"# If you set \"volume uuid = xxxxx\" in afp.conf, this file is not used.\n\n"

◆ Volumes

struct vol* Volumes = NULL
static