netatalk: netatalk_conf.c File Reference

netatalk 4.5.1
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
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
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 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 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_volumes().
int | load_charset (struct vol *vol)
int | load_volumes (AFPObj *obj, lv_flags_t flags)
| Initialize volumes and load ini configfile.
void | unload_volumes (AFPObj *obj)
struct vol * | getvolumes (void)
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

## 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] | obj | AFPObj containing user and group info
  [in] | args | access list string; NULL allows everybody to have access
  [in] | name | user 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

## ◆ 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] | vol | volume

Returns
  0 if not, 1 if yes

## ◆ 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] | 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

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] | 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"

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] | 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"

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] | 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"

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] | 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"

Returns
  dynamically allocated option string from "vol" or "defsec", or "defval" if not found

## ◆ 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] | 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"

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] | path | absolute 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_volumes()), but user volumes are as load_volumes() 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_volumes() 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] | obj | handle
  [in] | path | path, 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] | obj | AFPObj containing client info
  [in] | volname | volume name (not used)
  [in] | args | access 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_charset()

int load_charset | ( | struct vol * | vol | ) |

Load charsets for a volume

## ◆ load_volumes()

int load_volumes | ( | AFPObj * | obj,
|  | lv_flags_t | flags )

Initialize volumes and load ini configfile.

Parameters

  [in] | obj | handle
  [in] | flags | flags 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

## ◆ 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

  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

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] | 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"

Returns
  const option string from "vol" or "defsec", 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_volumes().

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
$$ -> $
volume
static afpvol_t volume
Definition nad_rm.c:46
path
Definition include/atalk/directory.h:123
server
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
dbpath
static bstring dbpath
Definition etc/cnid_dbd/main.c:48
NULL
#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