#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 vol * | creatvol (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 extmap * | getextmap (const char *path) |
| struct extmap * | getdefextmap (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 vol * | getvolumes (void) |
| int | conf_cnid_scheme_in_use (const AFPObj *obj, const char *scheme) |
| Whether any configured volume resolves to the given CNID scheme. | |
| struct vol * | getvolbyvid (const uint16_t vid) |
| static char * | getuserbypath (const char *path) |
| get username by path | |
| struct vol * | getvolbypath (AFPObj *obj, const char *path) |
| Search volume by path, creating user home vols as necessary. | |
| struct vol * | getvolbyname (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 vol * | Volumes = NULL |
| static uint16_t | lastvid = 0 |
| static struct extmap * | Extmap = NULL |
| static struct extmap * | Defextmap = NULL |
| static int | Extmap_cnt |
| #define EABUFSZ 4 |
| #define IS_VAR | ( | a, | |
| b ) |
| #define MAXPRESETLEN 100 |
| #define MAXVAL 1024 |
| #define UUID_PRINTABLE_STRING_LENGTH 37 |
| #define VOLPASSLEN 8 |
|
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:
| [in] | obj | AFPObj containing user and group info |
| [in] | args | access list string; NULL allows everybody to have access |
| [in] | name | user name to check |
| void afp_config_free | ( | AFPObj * | obj | ) |
get rid of any allocated afp_option buffers.
| int afp_config_parse | ( | AFPObj * | AFPObj, |
| char * | processname ) |
Initialize an AFPObj and options from ini config file
|
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.
| [in] | obj | handle (options are process-global) |
| [in] | volname | volume name, for the log messages |
|
static |
|
static |
Check whether a volume supports ACLs.
| [in] | vol | volume |
| 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).
|
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.
| [in] | conf | config handle |
| [in] | opt | option name |
| [in] | min | lowest accepted value |
| [in] | max | highest accepted value |
|
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.
| [in] | conf | config handle |
| [in] | opt | option name |
|
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
| [in] | opt | option name, for the warning |
| [in] | val | raw config value (may be NULL or empty = unset) |
| 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.
| [in] | vid | new counter value (unload_volumes() resets it to 0) |
|
static |
Create volume struct.
| [in] | obj | handle |
| [in] | pwd | struct passwd of logged in user, may be NULL in master afpd |
| [in] | section | volume name wo variables expanded (exactly as in iniconfig) |
| [in] | name | volume name |
| [in] | path_in | volume path |
| [in] | preset | default preset, may be NULL |
|
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.
|
static |
|
static |
|
static |
|
static |
Get a volume's UUID from the config file.
If there is none, it is generated and stored there.
| struct extmap * getdefextmap | ( | void | ) |
| struct extmap * getextmap | ( | const char * | path | ) |
|
static |
Get boolean option from config, use default value if not set.
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | defval | if neither "vol" nor "defsec" contain "opt" return "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.
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | defval | if neither "vol" nor "defsec" contain "opt" return "defval" |
|
static |
Get option string from config, use default value if not set.
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | defval | if neither "vol" nor "defsec" contain "opt" return "defval" |
|
static |
Get option string from config, use default value if not set.
Returns a dynamically allocated string which caller must free
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | defval | if neither "vol" nor "defsec" contain "opt" return "defval" |
|
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.
| [in] | conf | config handle |
| [in] | vol | section name |
| [in] | opt | canonical option |
| [in] | alias | deprecated option name |
| [in] | defsec | fallback section for both options |
| [in] | defval | default value when neither option is set |
| [in] | alias_warn | warning to emit when the alias is set |
| [out] | alias_used | set when the returned value is from the alias; may be NULL |
|
static |
Get uint32 option from config, use default value if unset or invalid.
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | minval | minimum accepted value |
| [in] | maxval | maximum accepted value |
| [in] | defval | if unset or out of range return "defval" |
|
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.
| [in] | path | absolute volume path |
| struct vol * getvolbyname | ( | const char * | name | ) |
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.
| [in,out] | obj | handle |
| [in] | path | path, may be relative or absolute |
| struct vol * getvolbyvid | ( | const uint16_t | vid | ) |
| struct vol * getvolumes | ( | void | ) |
|
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.
| [in] | obj | AFPObj containing client info |
| [in] | volname | volume name (not used) |
| [in] | args | access list string; NULL allows all hosts to have access |
| int load_afp_conf_vols | ( | AFPObj * | obj, |
| lv_flags_t | flags ) |
Initialize volumes and load ini configfile.
| [in] | obj | handle |
| [in] | flags | flags controlling volume load behaviour:
|
| int load_charset | ( | struct vol * | vol | ) |
Load charsets for a volume
|
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.
| [in] | volume | the volume |
| [in] | ea_setting | explicit non-samba ea value ("sys", "ad", "none"), NULL when unset (auto-detect) |
| 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".
|
static |
|
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.
| 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.
| str | String to convert |
| param_name | Parameter name for error messages |
| min_val | Minimum allowed value |
| max_val | Maximum allowed value |
| default_val | Default value to return on error |
|
static |
|
static |
| void unload_volumes | ( | AFPObj * | obj | ) |
|
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
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | defval | if neither "vol", "defsec" nor global contain "opt" return "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
| [in] | conf | config handle |
| [in] | vol | volume name (must be section name i.e. wo vars expanded) |
| [in] | opt | option |
| [in] | defsec | if "option" is not found in "vol", try to find it in section "defsec" |
| [in] | defval | if neither "vol", "defsec" nor global contain "opt" return "defval" |
|
static |
|
static |
| 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()
| void volume_unlink | ( | struct vol * | volume | ) |
Remove a volume from the linked list of volumes
|
static |
Handle variable substitutions.
here's what we understand:
This get's called from readvolfile with
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.
|
static |
|
static |
whether there's generic user home share in config ("~" or "~/path", but not "~user")
|
static |
|
static |