From 6561acb11104073c255ab94cf512b352c3f58bfa Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Mon, 21 Jan 2013 18:43:09 +0100 Subject: [PATCH 01/67] Set version to 3.0.3dev --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index d9c62ed9..226bf924 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.2 \ No newline at end of file +3.0.3dev \ No newline at end of file From 826014011cdcc4baa762cc4c791e6d6a22c93856 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Mon, 21 Jan 2013 18:47:50 +0100 Subject: [PATCH 02/67] Ignore develop abi file --- libatalk/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/libatalk/.gitignore b/libatalk/.gitignore index 33a5b662..e9f48fae 100644 --- a/libatalk/.gitignore +++ b/libatalk/.gitignore @@ -6,3 +6,4 @@ Makefile.in .libs dummy.o libatalk.abi.tmp +*dev.abi From d15bdfc509c1a21a1c75b792eebade617d1c4402 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 24 Jan 2013 19:00:23 +0100 Subject: [PATCH 03/67] Increase default DSI blocksize to 1 MB, taken from 10.8 AFP server --- NEWS | 4 ++++ include/atalk/dsi.h | 2 +- man/man5/afp.conf.5.tmpl | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 154eccf2..d98cac8a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +Changes in 3.0.3 +================ +* UPD: afpd: Increase default DSI server quantum to 1 MB + Changes in 3.0.2 ================ * NEW: afpd: Put file extension type/creator mapping back in which had diff --git a/include/atalk/dsi.h b/include/atalk/dsi.h index 00c80d42..11fb59b2 100644 --- a/include/atalk/dsi.h +++ b/include/atalk/dsi.h @@ -138,7 +138,7 @@ typedef struct DSI { #define DSI_DEFQUANT 2 /* default attention quantum size */ #define DSI_SERVQUANT_MAX 0xffffffff /* server quantum */ #define DSI_SERVQUANT_MIN 32000 /* minimum server quantum */ -#define DSI_SERVQUANT_DEF 0x0004A2E0L /* default server quantum */ +#define DSI_SERVQUANT_DEF 0x100000L /* default server quantum (1 MB) */ /* default port number */ #define DSI_AFPOVERTCP_PORT 548 diff --git a/man/man5/afp.conf.5.tmpl b/man/man5/afp.conf.5.tmpl index 9f9d007b..4f2472c3 100644 --- a/man/man5/afp.conf.5.tmpl +++ b/man/man5/afp.conf.5.tmpl @@ -465,7 +465,7 @@ Sets the maximum number of clients that can simultaneously connect to the server .PP server quantum = \fInumber\fR \fB(G)\fR .RS 4 -This specifies the DSI server quantum\&. The default value is 303840\&. The maximum value is 0xFFFFFFFFF, the minimum is 32000\&. If you specify a value that is out of range, the default value will be set\&. Do not change this value unless you\*(Aqre absolutely sure, what you\*(Aqre doing +This specifies the DSI server quantum\&. The default value is 1 MB\&. The maximum value is 0xFFFFFFFFF, the minimum is 32000\&. If you specify a value that is out of range, the default value will be set\&. Do not change this value unless you\*(Aqre absolutely sure, what you\*(Aqre doing .RE .PP sleep time = \fInumber\fR \fB(G)\fR From 41868f4c7864e364b3996cdb7ea193026bc21b5a Mon Sep 17 00:00:00 2001 From: HAT Date: Thu, 31 Jan 2013 01:06:57 +0900 Subject: [PATCH 04/67] dbd command show path dbd command show path #2 (use fullpathname) --- libatalk/adouble/ad_open.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 5205b9e2..5aca77c0 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -523,7 +523,7 @@ int ad_valid_header_osx(const char *path) adosx.ad_version = ntohl(adosx.ad_version); if ((adosx.ad_magic != AD_MAGIC) || (adosx.ad_version != AD_VERSION2)) { - LOG(log_warning, logtype_ad, "ad_valid_header_osx: not an adouble:osx file"); + LOG(log_warning, logtype_ad, "ad_valid_header_osx(\"%s\"): not an adouble:osx file", fullpathname(path)); EC_FAIL; } @@ -631,7 +631,7 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct } if (header_len < AD_HEADER_LEN) { - LOG(log_error, logtype_ad, "ad_header_read_ea: bogus AppleDouble header."); + LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): bogus AppleDouble header.", fullpathname(path)); errno = EIO; return -1; } @@ -643,7 +643,7 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct ad->ad_version = ntohl( ad->ad_version ); if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION2)) { - LOG(log_error, logtype_ad, "ad_header_read_ea: wrong magic or version"); + LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): wrong magic or version", fullpathname(path)); errno = EIO; return -1; } @@ -656,7 +656,7 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct if (len + AD_HEADER_LEN > sizeof(ad->ad_data)) len = sizeof(ad->ad_data) - AD_HEADER_LEN; if (len > header_len - AD_HEADER_LEN) { - LOG(log_error, logtype_ad, "ad_header_read_ea: can't read entry info."); + LOG(log_error, logtype_ad, "ad_header_read_ea(\"%s\"): can't read entry info.", fullpathname(path)); errno = EIO; return -1; } From 9df0118bdf4c2831b0d376dca4c80e91ffb5f31d Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Fri, 1 Feb 2013 19:21:01 +0100 Subject: [PATCH 05/67] afpd/volume: don't leak vol_mname in afp_openvol Reported as Coverity by CID #201201 --- etc/afpd/volume.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 844444ba..8798635a 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -791,7 +791,6 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t ret = AFPERR_MISC; goto openvol_err; } - free(vol_mname); volume->v_root = dir; curdir = dir; @@ -829,6 +828,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t if ((msg = iniparser_getstring(obj->iniconfig, volume->v_configname, "login message", NULL)) != NULL) setmessage(msg); + free(vol_mname); return( AFP_OK ); } @@ -843,6 +843,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t cnid_close(volume->v_cdb); volume->v_cdb = NULL; } + free(vol_mname); *rbuflen = 0; return ret; } From fb751e80c0bc12c35675fbf1434ceecb4aad47cb Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 6 Feb 2013 08:30:17 +0100 Subject: [PATCH 06/67] Remove continous service feature --- etc/afpd/afp_dsi.c | 19 +-- etc/afpd/main.c | 100 +++----------- include/atalk/dsi.h | 2 +- include/atalk/globals.h | 1 - include/atalk/paths.h | 1 - include/atalk/server_child.h | 67 +++++----- include/atalk/server_ipc.h | 5 +- include/atalk/util.h | 2 +- libatalk/dsi/dsi_getsess.c | 6 +- libatalk/util/netatalk_conf.c | 2 - libatalk/util/server_child.c | 237 +++++++++++++--------------------- libatalk/util/server_ipc.c | 99 +------------- man/man5/afp.conf.5.tmpl | 7 - man/man8/netatalk.8.tmpl | 6 - 14 files changed, 152 insertions(+), 402 deletions(-) diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index 8e1f90d2..77918c56 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -140,23 +140,6 @@ static void afp_dsi_die(int sig) } } -/* SIGQUIT handler */ -static void ipc_reconnect_handler(int sig _U_) -{ - if (reconnect_ipc(AFPobj) != 0) { - LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC reconnect"); - afp_dsi_close(AFPobj); - exit(EXITERR_SYS); - } - - if (ipc_child_write(AFPobj->ipc_fd, IPC_GETSESSION, AFPobj->sinfo.clientid_len, AFPobj->sinfo.clientid) != 0) { - LOG(log_error, logtype_afpd, "ipc_reconnect_handler: failed IPC ID resend"); - afp_dsi_close(AFPobj); - exit(EXITERR_SYS); - } - LOG(log_note, logtype_afpd, "ipc_reconnect_handler: IPC reconnect done"); -} - /* SIGURG handler (primary reconnect) */ static void afp_dsi_transfer_session(int sig _U_) { @@ -407,7 +390,7 @@ void afp_over_dsi_sighandlers(AFPObj *obj) } /* install SIGQUIT */ - action.sa_handler = ipc_reconnect_handler; + action.sa_handler = afp_dsi_die; if ( sigaction(SIGQUIT, &action, NULL ) < 0 ) { LOG(log_error, logtype_afpd, "afp_over_dsi: sigaction: %s", strerror(errno) ); afp_dsi_die(EXITERR_SYS); diff --git a/etc/afpd/main.c b/etc/afpd/main.c index 0e0a858e..a66e4a86 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -45,7 +45,7 @@ unsigned char nologin = 0; static AFPObj obj; -static server_child *server_children; +static server_child_t *server_children; static sig_atomic_t reloadconfig = 0; static sig_atomic_t gotsigchld = 0; @@ -54,9 +54,8 @@ static struct pollfd *fdset; static struct polldata *polldata; static int fdset_size; /* current allocated size */ static int fdset_used; /* number of used elements */ -static int disasociated_ipc_fd; /* disasociated sessions uses this fd for IPC */ -static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children); +static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children); static void afp_exit(int ret) { @@ -81,16 +80,6 @@ static void fd_set_listening_sockets(const AFPObj *config) LISTEN_FD, dsi); } - - if (config->options.flags & OPTION_KEEPSESSIONS) - fdset_add_fd(config->options.connections + AFP_LISTENERS + FDSET_SAFETY, - &fdset, - &polldata, - &fdset_used, - &fdset_size, - disasociated_ipc_fd, - DISASOCIATED_IPC_FD, - NULL); } static void fd_reset_listening_sockets(const AFPObj *config) @@ -100,9 +89,6 @@ static void fd_reset_listening_sockets(const AFPObj *config) for (dsi = config->dsi; dsi; dsi = dsi->next) { fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, dsi->serversock); } - - if (config->options.flags & OPTION_KEEPSESSIONS) - fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, disasociated_ipc_fd); } /* ------------------ */ @@ -112,22 +98,9 @@ static void afp_goaway(int sig) case SIGTERM: case SIGQUIT: - switch (sig) { - case SIGTERM: - LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGTERM"); - break; - case SIGQUIT: - if (obj.options.flags & OPTION_KEEPSESSIONS) { - LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT, NOT disconnecting clients"); - } else { - LOG(log_note, logtype_afpd, "AFP Server shutting down on SIGQUIT"); - sig = SIGTERM; - } - break; - } + LOG(log_note, logtype_afpd, "AFP Server shutting down"); if (server_children) - server_child_kill(server_children, CHILD_DSIFORK, sig); - + server_child_kill(server_children, SIGTERM); _exit(0); break; @@ -137,7 +110,7 @@ static void afp_goaway(int sig) LOG(log_info, logtype_afpd, "disallowing logins"); if (server_children) - server_child_kill(server_children, CHILD_DSIFORK, sig); + server_child_kill(server_children, sig); break; case SIGHUP : @@ -167,11 +140,9 @@ static void child_handler(void) #endif /* ! WAIT_ANY */ while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) { - for (i = 0; i < server_children->nforks; i++) { - if ((fd = server_child_remove(server_children, i, pid)) != -1) { - fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd); - break; - } + if ((fd = server_child_remove(server_children, pid)) != -1) { + fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, fd); + break; } if (WIFEXITED(status)) { @@ -232,7 +203,7 @@ int main(int ac, char **av) /* install child handler for asp and dsi. we do this before afp_goaway * as afp_goaway references stuff from here. * XXX: this should really be setup after the initial connections. */ - if (!(server_children = server_child_alloc(obj.options.connections, CHILD_NFORKS))) { + if (!(server_children = server_child_alloc(obj.options.connections))) { LOG(log_error, logtype_afpd, "main: server_child alloc: %s", strerror(errno) ); afp_exit(EXITERR_SYS); } @@ -350,12 +321,6 @@ int main(int ac, char **av) cnid_init(); /* watch atp, dsi sockets and ipc parent/child file descriptor. */ - - if (obj.options.flags & OPTION_KEEPSESSIONS) { - LOG(log_note, logtype_afpd, "Activating continous service"); - disasociated_ipc_fd = ipc_server_uds(_PATH_AFP_IPC); - } - fd_set_listening_sockets(&obj); /* set limits */ @@ -433,7 +398,7 @@ int main(int ac, char **av) &polldata, &fdset_used, &fdset_size, - child->ipc_fd, + child->afpch_ipc_fd, IPC_FD, child); } @@ -441,46 +406,13 @@ int main(int ac, char **av) case IPC_FD: child = (afp_child_t *)polldata[i].data; - LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->pid); - - if (ipc_server_read(server_children, child->ipc_fd) != 0) { - fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->ipc_fd); - close(child->ipc_fd); - child->ipc_fd = -1; - if ((obj.options.flags & OPTION_KEEPSESSIONS) && child->disasociated) { - LOG(log_note, logtype_afpd, "main: removing reattached child[%u]", child->pid); - server_child_remove(server_children, CHILD_DSIFORK, child->pid); - } - } - break; - - case DISASOCIATED_IPC_FD: - LOG(log_debug, logtype_afpd, "main: IPC reconnect request"); - if ((recon_ipc_fd = accept(disasociated_ipc_fd, NULL, NULL)) == -1) { - LOG(log_error, logtype_afpd, "main: accept: %s", strerror(errno)); - break; - } - if (readt(recon_ipc_fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) { - LOG(log_error, logtype_afpd, "main: readt: %s", strerror(errno)); - close(recon_ipc_fd); - break; - } - LOG(log_note, logtype_afpd, "main: IPC reconnect from pid [%u]", pid); + LOG(log_debug, logtype_afpd, "main: IPC request from child[%u]", child->afpch_pid); - if ((child = server_child_add(server_children, CHILD_DSIFORK, pid, recon_ipc_fd)) == NULL) { - LOG(log_error, logtype_afpd, "main: server_child_add"); - close(recon_ipc_fd); - break; + if (ipc_server_read(server_children, child->afpch_ipc_fd) != 0) { + fdset_del_fd(&fdset, &polldata, &fdset_used, &fdset_size, child->afpch_ipc_fd); + close(child->afpch_ipc_fd); + child->afpch_ipc_fd = -1; } - child->disasociated = 1; - fdset_add_fd(obj.options.connections + AFP_LISTENERS + FDSET_SAFETY, - &fdset, - &polldata, - &fdset_used, - &fdset_size, - recon_ipc_fd, - IPC_FD, - child); break; default: @@ -494,7 +426,7 @@ int main(int ac, char **av) return 0; } -static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child *server_children) +static afp_child_t *dsi_start(AFPObj *obj, DSI *dsi, server_child_t *server_children) { afp_child_t *child = NULL; diff --git a/include/atalk/dsi.h b/include/atalk/dsi.h index 11fb59b2..4197dba5 100644 --- a/include/atalk/dsi.h +++ b/include/atalk/dsi.h @@ -165,7 +165,7 @@ extern int dsi_tcp_init(DSI *dsi, const char *hostname, const char *address, con extern void dsi_free(DSI *dsi); /* in dsi_getsess.c */ -extern int dsi_getsession (DSI *, server_child *, const int, afp_child_t **); +extern int dsi_getsession (DSI *, server_child_t *, const int, afp_child_t **); extern void dsi_kill (int); diff --git a/include/atalk/globals.h b/include/atalk/globals.h index 75d4041b..925f4560 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -41,7 +41,6 @@ #define OPTION_UUID (1 << 7) #define OPTION_ACL2MACCESS (1 << 8) #define OPTION_NOZEROCONF (1 << 9) -#define OPTION_KEEPSESSIONS (1 << 10) /* preserve sessions across master afpd restart with SIGQUIT */ #define OPTION_SHARE_RESERV (1 << 11) /* whether to use Solaris fcntl F_SHARE locks */ #define PASSWD_NONE 0 diff --git a/include/atalk/paths.h b/include/atalk/paths.h index 1aab9690..ba4d2f23 100644 --- a/include/atalk/paths.h +++ b/include/atalk/paths.h @@ -36,7 +36,6 @@ * netatalk paths */ #define _PATH_AFPTKT "/tmp/AFPtktXXXXXX" -#define _PATH_AFP_IPC ATALKPATHCAT(_PATH_LOCKDIR,"afpd_ipc") #if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__) # define _PATH_NETATALK_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"netatalk.pid") #else diff --git a/include/atalk/server_child.h b/include/atalk/server_child.h index ad41bcec..6f8f18a0 100644 --- a/include/atalk/server_child.h +++ b/include/atalk/server_child.h @@ -12,41 +12,42 @@ /* useful stuff for child processes. most of this is hidden in * server_child.c to ease changes in implementation */ -#define CHILD_NFORKS 2 -#define CHILD_ASPFORK 0 -#define CHILD_PAPFORK 0 -#define CHILD_DSIFORK 1 - -typedef struct server_child { - void *fork; - int count, nsessions, nforks; -} server_child; - -typedef struct server_child_data { - pid_t pid; /* afpd worker process pid (from the worker afpd process )*/ - uid_t uid; /* user id of connected client (from the worker afpd process) */ - int valid; /* 1 if we have a clientid */ - int killed; /* 1 if we already tried to kill the client */ - int disasociated; /* 1 if this is not a child, but a child from a previous afpd master */ - uint32_t time; /* client boot time (from the mac client) */ - uint32_t idlen; /* clientid len (from the Mac client) */ - char *clientid; /* clientid (from the Mac client) */ - int ipc_fd; /* socket for IPC bw afpd parent and childs */ - struct server_child_data **prevp, *next; +#define CHILD_HASHSIZE 32 + +/* One AFP session child process */ +typedef struct afp_child { + pid_t afpch_pid; /* afpd worker process pid (from the worker afpd process )*/ + uid_t afpch_uid; /* user id of connected client (from the worker afpd process) */ + int afpch_valid; /* 1 if we have a clientid */ + int afpch_killed; /* 1 if we already tried to kill the client */ + uint32_t afpch_time; /* client boot time (from the mac client) */ + uint32_t afpch_idlen; /* clientid len (from the Mac client) */ + char *afpch_clientid; /* clientid (from the Mac client) */ + int afpch_ipc_fd; /* socket for IPC bw afpd parent and childs */ + struct afp_child **afpch_prevp; + struct afp_child *afpch_next; } afp_child_t; +/* Info and table with all AFP session child processes */ +typedef struct { + pthread_mutex_t servch_lock; /* Lock */ + int servch_count; /* Current count of active AFP sessions */ + int servch_nsessions; /* Number of allowed AFP sessions */ + afp_child_t *servch_table[CHILD_HASHSIZE]; /* Hashtable with data of AFP sesssions */ + void (*servch_cleanup)(const pid_t); /* Cleanup handler */ +} server_child_t; + /* server_child.c */ -extern server_child *server_child_alloc (const int, const int); -extern afp_child_t *server_child_add (server_child *, int, pid_t, int ipc_fd); -extern int server_child_remove (server_child *, const int, const pid_t); -extern void server_child_free (server_child *); - -extern void server_child_kill (server_child *, const int, const int); -extern void server_child_kill_one_by_id (server_child *children, const int forkid, const pid_t pid, const uid_t, - const uint32_t len, char *id, uint32_t boottime); -extern int server_child_transfer_session(server_child *children, int forkid, pid_t, uid_t, int, uint16_t); -extern void server_child_setup (server_child *, const int, void (*)(const pid_t)); -extern void server_child_handler (server_child *); -extern void server_reset_signal (void); +extern server_child_t *server_child_alloc(int); +extern afp_child_t *server_child_add(server_child_t *, pid_t, int ipc_fd); +extern int server_child_remove(server_child_t *, pid_t); +extern void server_child_free(server_child_t *); + +extern void server_child_kill(server_child_t *, int); +extern void server_child_kill_one_by_id(server_child_t *children, pid_t pid, uid_t, + uint32_t len, char *id, uint32_t boottime); +extern int server_child_transfer_session(server_child_t *children, pid_t, uid_t, int, uint16_t); +extern void server_child_handler(server_child_t *); +extern void server_reset_signal(void); #endif diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h index aca04f80..0765c73c 100644 --- a/include/atalk/server_ipc.h +++ b/include/atalk/server_ipc.h @@ -7,10 +7,7 @@ #define IPC_DISCOLDSESSION 0 #define IPC_GETSESSION 1 -extern int ipc_server_uds(const char *name); -extern int ipc_client_uds(const char *name); -extern int reconnect_ipc(AFPObj *); -extern int ipc_server_read(server_child *children, int fd); +extern int ipc_server_read(server_child_t *children, int fd); extern int ipc_child_write(int fd, uint16_t command, int len, void *token); #endif /* IPC_GETSESSION_LOGIN */ diff --git a/include/atalk/util.h b/include/atalk/util.h index 08c37394..facc7763 100644 --- a/include/atalk/util.h +++ b/include/atalk/util.h @@ -149,7 +149,7 @@ extern void apply_ip_mask(struct sockaddr *ai, int maskbits); extern int compare_ip(const struct sockaddr *sa1, const struct sockaddr *sa2); /* Structures and functions dealing with dynamic pollfd arrays */ -enum fdtype {IPC_FD, LISTEN_FD, DISASOCIATED_IPC_FD}; +enum fdtype {IPC_FD, LISTEN_FD}; struct polldata { enum fdtype fdtype; /* IPC fd or listening socket fd */ void *data; /* pointer to AFPconfig for listening socket and * diff --git a/libatalk/dsi/dsi_getsess.c b/libatalk/dsi/dsi_getsess.c index cde5def7..38477be9 100644 --- a/libatalk/dsi/dsi_getsess.c +++ b/libatalk/dsi/dsi_getsess.c @@ -32,7 +32,7 @@ * @param childp (w) after fork: parent return pointer to child, child returns NULL * @returns 0 on sucess, any other value denotes failure */ -int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_child_t **childp) +int dsi_getsession(DSI *dsi, server_child_t *serv_children, int tickleval, afp_child_t **childp) { pid_t pid; int ipc_fds[2]; @@ -61,7 +61,7 @@ int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_chi /* using SIGKILL is hokey, but the child might not have * re-established its signal handler for SIGTERM yet. */ close(ipc_fds[1]); - if ((child = server_child_add(serv_children, CHILD_DSIFORK, pid, ipc_fds[0])) == NULL) { + if ((child = server_child_add(serv_children, pid, ipc_fds[0])) == NULL) { LOG(log_error, logtype_dsi, "dsi_getsess: %s", strerror(errno)); close(ipc_fds[0]); dsi->header.dsi_flags = DSIFL_REPLY; @@ -77,7 +77,7 @@ int dsi_getsession(DSI *dsi, server_child *serv_children, int tickleval, afp_chi /* child: check number of open connections. this is one off the * actual count. */ - if ((serv_children->count >= serv_children->nsessions) && + if ((serv_children->servch_count >= serv_children->servch_nsessions) && (dsi->header.dsi_command == DSIFUNC_OPEN)) { LOG(log_info, logtype_dsi, "dsi_getsess: too many connections"); dsi->header.dsi_flags = DSIFL_REPLY; diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index b1ca02d1..1bfa3a94 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -1641,8 +1641,6 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->flags |= OPTION_ANNOUNCESSH; if (iniparser_getboolean(config, INISEC_GLOBAL, "map acls", 1)) options->flags |= OPTION_ACL2MACCESS; - if (iniparser_getboolean(config, INISEC_GLOBAL, "keep sessions", 0)) - options->flags |= OPTION_KEEPSESSIONS; if (iniparser_getboolean(config, INISEC_GLOBAL, "close vol", 0)) options->flags |= OPTION_CLOSEVOL; if (!iniparser_getboolean(config, INISEC_GLOBAL, "client polling", 0)) diff --git a/libatalk/util/server_child.c b/libatalk/util/server_child.c index 547d68d9..6c86f483 100644 --- a/libatalk/util/server_child.c +++ b/libatalk/util/server_child.c @@ -1,8 +1,8 @@ /* * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) + * Copyright (c) 2013 Frank Lahm #include #include +#include #include #include @@ -47,41 +48,34 @@ #endif /* hash/child functions: hash OR's pid */ -#define CHILD_HASHSIZE 32 #define HASH(i) ((((i) >> 8) ^ (i)) & (CHILD_HASHSIZE - 1)) -typedef struct server_child_fork { - struct server_child_data *table[CHILD_HASHSIZE]; - void (*cleanup)(const pid_t); -} server_child_fork; - -static inline void hash_child(struct server_child_data **htable, - struct server_child_data *child) +static inline void hash_child(afp_child_t **htable, afp_child_t *child) { - struct server_child_data **table; + afp_child_t **table; - table = &htable[HASH(child->pid)]; - if ((child->next = *table) != NULL) - (*table)->prevp = &child->next; + table = &htable[HASH(child->afpch_pid)]; + if ((child->afpch_next = *table) != NULL) + (*table)->afpch_prevp = &child->afpch_next; *table = child; - child->prevp = table; + child->afpch_prevp = table; } -static inline void unhash_child(struct server_child_data *child) +static inline void unhash_child(afp_child_t *child) { - if (child->prevp) { - if (child->next) - child->next->prevp = child->prevp; - *(child->prevp) = child->next; + if (child->afpch_prevp) { + if (child->afpch_next) + child->afpch_next->afpch_prevp = child->afpch_prevp; + *(child->afpch_prevp) = child->afpch_next; } } -static struct server_child_data *resolve_child(struct server_child_data **table, pid_t pid) +static afp_child_t *resolve_child(afp_child_t **table, pid_t pid) { - struct server_child_data *child; + afp_child_t *child; - for (child = table[HASH(pid)]; child; child = child->next) { - if (child->pid == pid) + for (child = table[HASH(pid)]; child; child = child->afpch_next) { + if (child->afpch_pid == pid) break; } @@ -89,23 +83,15 @@ static struct server_child_data *resolve_child(struct server_child_data **table, } /* initialize server_child structure */ -server_child *server_child_alloc(const int connections, const int nforks) +server_child_t *server_child_alloc(int connections) { - server_child *children; - - children = (server_child *) calloc(1, sizeof(server_child)); - if (!children) - return NULL; - - children->nsessions = connections; - children->nforks = nforks; - children->fork = (void *) calloc(nforks, sizeof(server_child_fork)); + server_child_t *children; - if (!children->fork) { - free(children); + if (!(children = (server_child_t *)calloc(1, sizeof(server_child_t)))) return NULL; - } + children->servch_nsessions = connections; + pthread_mutex_init(&children->servch_lock, NULL); return children; } @@ -113,17 +99,11 @@ server_child *server_child_alloc(const int connections, const int nforks) * add a child * @return pointer to struct server_child_data on success, NULL on error */ -afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int ipc_fd) +afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd) { - server_child_fork *fork; afp_child_t *child = NULL; - sigset_t sig, oldsig; - /* we need to prevent deletions from occuring before we get a - * chance to add the child in. */ - sigemptyset(&sig); - sigaddset(&sig, SIGCHLD); - pthread_sigmask(SIG_BLOCK, &sig, &oldsig); + pthread_mutex_lock(&children->servch_lock); /* it's possible that the child could have already died before the * pthread_sigmask. we need to check for this. */ @@ -132,118 +112,102 @@ afp_child_t *server_child_add(server_child *children, int forkid, pid_t pid, int goto exit; } - fork = (server_child_fork *) children->fork + forkid; - /* if we already have an entry. just return. */ - if ((child = resolve_child(fork->table, pid))) + if ((child = resolve_child(children->servch_table, pid))) goto exit; if ((child = calloc(1, sizeof(afp_child_t))) == NULL) goto exit; - child->pid = pid; - child->valid = 0; - child->killed = 0; - child->ipc_fd = ipc_fd; + child->afpch_pid = pid; + child->afpch_ipc_fd = ipc_fd; - hash_child(fork->table, child); - children->count++; + hash_child(children->servch_table, child); + children->servch_count++; exit: - pthread_sigmask(SIG_SETMASK, &oldsig, NULL); + pthread_mutex_unlock(&children->servch_lock); return child; } /* remove a child and free it */ -int server_child_remove(server_child *children, const int forkid, pid_t pid) +int server_child_remove(server_child_t *children, pid_t pid) { int fd; - server_child_fork *fork; - struct server_child_data *child; + afp_child_t *child; - fork = (server_child_fork *) children->fork + forkid; - if (!(child = resolve_child(fork->table, pid))) + if (!(child = resolve_child(children->servch_table, pid))) return -1; unhash_child(child); - if (child->clientid) { - free(child->clientid); - child->clientid = NULL; + if (child->afpch_clientid) { + free(child->afpch_clientid); + child->afpch_clientid = NULL; } /* In main:child_handler() we need the fd in order to remove it from the pollfd set */ - fd = child->ipc_fd; + fd = child->afpch_ipc_fd; if (fd != -1) close(fd); free(child); - children->count--; + children->servch_count--; - if (fork->cleanup) - fork->cleanup(pid); + if (children->servch_cleanup) + children->servch_cleanup(pid); return fd; } /* free everything: by using a hash table, this increases the cost of * this part over a linked list by the size of the hash table */ -void server_child_free(server_child *children) +void server_child_free(server_child_t *children) { - server_child_fork *fork; - struct server_child_data *child, *tmp; - int i, j; - - for (i = 0; i < children->nforks; i++) { - fork = (server_child_fork *) children->fork + i; - for (j = 0; j < CHILD_HASHSIZE; j++) { - child = fork->table[j]; /* start at the beginning */ - while (child) { - tmp = child->next; - close(child->ipc_fd); - if (child->clientid) { - free(child->clientid); - } - free(child); - child = tmp; - } + afp_child_t *child, *tmp; + int j; + + for (j = 0; j < CHILD_HASHSIZE; j++) { + child = children->servch_table[j]; /* start at the beginning */ + while (child) { + tmp = child->afpch_next; + close(child->afpch_ipc_fd); + if (child->afpch_clientid) + free(child->afpch_clientid); + free(child); + child = tmp; } } - free(children->fork); + free(children); } /* send signal to all child processes */ -void server_child_kill(server_child *children, int forkid, int sig) +void server_child_kill(server_child_t *children, int sig) { - server_child_fork *fork; - struct server_child_data *child, *tmp; + afp_child_t *child, *tmp; int i; - fork = (server_child_fork *) children->fork + forkid; for (i = 0; i < CHILD_HASHSIZE; i++) { - child = fork->table[i]; + child = children->servch_table[i]; while (child) { - tmp = child->next; - kill(child->pid, sig); + tmp = child->afpch_next; + kill(child->afpch_pid, sig); child = tmp; } } } -/* send kill to a child processes. - * a plain-old linked list - * FIXME use resolve_child ? - */ -static int kill_child(struct server_child_data *child) +/* send kill to a child processes */ +static int kill_child(afp_child_t *child) { - if (!child->killed) { - kill(child->pid, SIGTERM); + if (!child->afpch_killed) { + kill(child->afpch_pid, SIGTERM); /* we don't wait because there's no guarantee that we can really kill it */ - child->killed = 1; + child->afpch_killed = 1; return 1; } else { - LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->pid); - kill(child->pid, SIGKILL); + LOG(log_info, logtype_default, "Unresponsive child[%d], sending SIGKILL", child->afpch_pid); + kill(child->afpch_pid, SIGKILL); } return 1; } @@ -252,19 +216,16 @@ static int kill_child(struct server_child_data *child) * Try to find an old session and pass socket * @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed */ -int server_child_transfer_session(server_child *children, - int forkid, +int server_child_transfer_session(server_child_t *children, pid_t pid, uid_t uid, int afp_socket, uint16_t DSI_requestID) { EC_INIT; - server_child_fork *fork; - struct server_child_data *child; + afp_child_t *child; - fork = (server_child_fork *) children->fork + forkid; - if ((child = resolve_child(fork->table, pid)) == NULL) { + if ((child = resolve_child(children->servch_table, pid)) == NULL) { LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid); if (kill(pid, 0) == 0) { LOG(log_note, logtype_default, "Reconnect: terminating old session[%u]", pid); @@ -279,23 +240,23 @@ int server_child_transfer_session(server_child *children, return 0; } - if (!child->valid) { + if (!child->afpch_valid) { /* hmm, client 'guess' the pid, rogue? */ LOG(log_error, logtype_default, "Reconnect: invalidated child[%u]", pid); return 0; - } else if (child->uid != uid) { + } else if (child->afpch_uid != uid) { LOG(log_error, logtype_default, "Reconnect: child[%u] not the same user", pid); return 0; } LOG(log_note, logtype_default, "Reconnect: transfering session to child[%u]", pid); - if (writet(child->ipc_fd, &DSI_requestID, 2, 0, 2) != 2) { + if (writet(child->afpch_ipc_fd, &DSI_requestID, 2, 0, 2) != 2) { LOG(log_error, logtype_default, "Reconnect: error sending DSI id to child[%u]", pid); EC_STATUS(-1); goto EC_CLEANUP; } - EC_ZERO_LOG(send_fd(child->ipc_fd, afp_socket)); + EC_ZERO_LOG(send_fd(child->afpch_ipc_fd, afp_socket)); EC_ZERO_LOG(kill(pid, SIGURG)); EC_STATUS(1); @@ -307,65 +268,51 @@ int server_child_transfer_session(server_child *children, /* see if there is a process for the same mac */ /* if the times don't match mac has been rebooted */ -void server_child_kill_one_by_id(server_child *children, int forkid, pid_t pid, +void server_child_kill_one_by_id(server_child_t *children, pid_t pid, uid_t uid, uint32_t idlen, char *id, uint32_t boottime) { - server_child_fork *fork; - struct server_child_data *child, *tmp; + afp_child_t *child, *tmp; int i; - fork = (server_child_fork *)children->fork + forkid; - for (i = 0; i < CHILD_HASHSIZE; i++) { - child = fork->table[i]; + child = children->servch_table[i]; while (child) { - tmp = child->next; - if ( child->pid != pid) { - if (child->idlen == idlen && memcmp(child->clientid, id, idlen) == 0) { - if ( child->time != boottime ) { + tmp = child->afpch_next; + if (child->afpch_pid != pid) { + if (child->afpch_idlen == idlen && memcmp(child->afpch_clientid, id, idlen) == 0) { + if ( child->afpch_time != boottime ) { /* Client rebooted */ - if (uid == child->uid) { + if (uid == child->afpch_uid) { kill_child(child); LOG(log_warning, logtype_default, "Terminated disconnected child[%u], client rebooted.", - child->pid); + child->afpch_pid); } else { LOG(log_warning, logtype_default, - "Session with different pid[%u]", child->pid); + "Session with different pid[%u]", child->afpch_pid); } } else { /* One client with multiple sessions */ LOG(log_debug, logtype_default, - "Found another session[%u] for client[%u]", child->pid, pid); + "Found another session[%u] for client[%u]", child->afpch_pid, pid); } } } else { /* update childs own slot */ - child->time = boottime; - if (child->clientid) - free(child->clientid); - LOG(log_debug, logtype_default, "Setting client ID for %u", child->pid); - child->uid = uid; - child->valid = 1; - child->idlen = idlen; - child->clientid = id; + child->afpch_time = boottime; + if (child->afpch_clientid) + free(child->afpch_clientid); + LOG(log_debug, logtype_default, "Setting client ID for %u", child->afpch_pid); + child->afpch_uid = uid; + child->afpch_valid = 1; + child->afpch_idlen = idlen; + child->afpch_clientid = id; } child = tmp; } } } -/* for extra cleanup if necessary */ -void server_child_setup(server_child *children, const int forkid, - void (*fcn)(const pid_t)) -{ - server_child_fork *fork; - - fork = (server_child_fork *) children->fork + forkid; - fork->cleanup = fcn; -} - - /* --------------------------- * reset children signals */ diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c index 815c58d8..838cece7 100644 --- a/libatalk/util/server_ipc.c +++ b/libatalk/util/server_ipc.c @@ -48,7 +48,7 @@ static char *ipc_cmd_str[] = { "IPC_DISCOLDSESSION", * Pass afp_socket to old disconnected session if one has a matching token (token = pid) * @returns -1 on error, 0 if no matching session was found, 1 if session was found and socket passed */ -static int ipc_kill_token(struct ipc_header *ipc, server_child *children) +static int ipc_kill_token(struct ipc_header *ipc, server_child_t *children) { pid_t pid; @@ -59,7 +59,6 @@ static int ipc_kill_token(struct ipc_header *ipc, server_child *children) memcpy (&pid, ipc->msg, sizeof(pid_t)); return server_child_transfer_session(children, - CHILD_DSIFORK, pid, ipc->uid, ipc->afp_socket, @@ -67,7 +66,7 @@ static int ipc_kill_token(struct ipc_header *ipc, server_child *children) } /* ----------------- */ -static int ipc_get_session(struct ipc_header *ipc, server_child *children) +static int ipc_get_session(struct ipc_header *ipc, server_child_t *children) { uint32_t boottime; uint32_t idlen; @@ -96,7 +95,6 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children) ipc->child_pid, ipc->uid, boottime); server_child_kill_one_by_id(children, - CHILD_DSIFORK, ipc->child_pid, ipc->uid, idlen, @@ -110,97 +108,6 @@ static int ipc_get_session(struct ipc_header *ipc, server_child *children) * Public functions ***********************************************************************************/ -/*! - * Listen on UNIX domain socket "name" for IPC from old sesssion - * - * @args name (r) file name to use for UNIX domain socket - * @returns socket fd, -1 on error - */ -int ipc_server_uds(const char *name) -{ - EC_INIT; - struct sockaddr_un address; - socklen_t address_length; - int fd = -1; - - EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) ); - EC_ZERO_LOG( setnonblock(fd, 1) ); - unlink(name); - address.sun_family = AF_UNIX; - address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", name); - EC_ZERO_LOG( bind(fd, (struct sockaddr *)&address, address_length) ); - EC_ZERO_LOG( listen(fd, 1024) ); - -EC_CLEANUP: - if (ret != 0) { - return -1; - } - - return fd; -} - -/*! - * Connect to UNIX domain socket "name" for IPC with new afpd master - * - * 1. Connect - * 2. send pid, which establishes a child structure for us in the master - * - * @args name (r) file name to use for UNIX domain socket - * @returns socket fd, -1 on error - */ -int ipc_client_uds(const char *name) -{ - EC_INIT; - struct sockaddr_un address; - socklen_t address_length; - int fd = -1; - pid_t pid = getpid(); - - EC_NEG1_LOG( fd = socket(PF_UNIX, SOCK_STREAM, 0) ); - address.sun_family = AF_UNIX; - address_length = sizeof(address.sun_family) + sprintf(address.sun_path, "%s", name); - - EC_ZERO_LOG( connect(fd, (struct sockaddr *)&address, address_length) ); /* 1 */ - LOG(log_debug, logtype_afpd, "ipc_client_uds: connected to master"); - - EC_ZERO_LOG( setnonblock(fd, 1) ); - - if (writet(fd, &pid, sizeof(pid_t), 0, 1) != sizeof(pid_t)) { - LOG(log_error, logtype_afpd, "ipc_client_uds: writet: %s", strerror(errno)); - EC_FAIL; - } - -EC_CLEANUP: - if (ret != 0) { - return -1; - } - LOG(log_debug, logtype_afpd, "ipc_client_uds: fd: %d", fd); - return fd; -} - -int reconnect_ipc(AFPObj *obj) -{ - int retrycount = 0; - - LOG(log_debug, logtype_afpd, "reconnect_ipc: start"); - - close(obj->ipc_fd); - obj->ipc_fd = -1; - - sleep((getpid() % 5) + 15); /* give it enough time to start */ - - while (retrycount++ < 10) { - if ((obj->ipc_fd = ipc_client_uds(_PATH_AFP_IPC)) == -1) { - LOG(log_error, logtype_afpd, "reconnect_ipc: cant reconnect to master"); - sleep(1); - continue; - } - LOG(log_debug, logtype_afpd, "reconnect_ipc: succesfull IPC reconnect"); - return 0; - } - return -1; -} - /* ----------------- * Ipc format * command @@ -219,7 +126,7 @@ int reconnect_ipc(AFPObj *obj) * * @returns -1 on error, 0 on success */ -int ipc_server_read(server_child *children, int fd) +int ipc_server_read(server_child_t *children, int fd) { int ret; struct ipc_header ipc; diff --git a/man/man5/afp.conf.5.tmpl b/man/man5/afp.conf.5.tmpl index 4f2472c3..c03ad30a 100644 --- a/man/man5/afp.conf.5.tmpl +++ b/man/man5/afp.conf.5.tmpl @@ -549,13 +549,6 @@ AFP user home volume name\&. The default is \fIuser\*(Aqs home\fR\&. .RE .PP -keep sessions = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR -.RS 4 -Enable "Continuous AFP Service"\&. This means restarting AFP and CNID service daemons master processes, but keeping the AFP session processes\&. This can be used to install (most) updates to Netatalk without interrupting active AFP sessions\&. Existing AFP sessions will still run the version from before updating, but new AFP sessions will run the updated code\&. After enabling this option when sending SIGQUIT to the -\fInetatalk\fR -service controller process, the AFP and CNID daemons will exit and then the service controller will restart them\&. AFP session processes are notified of the master afpd shutdown, they will then sleep 15\-20 seconds and then try to reconnect their IPC channel to the master afpd process\&. The IPC channel between the AFP master service daemon and the AFP session child is used for keeping session state of AFP sessions in the AFP master process\&. The session state is needed when AFP clients experience eg network outages and try to reconnect to the AFP server\&. -.RE -.PP login message = \fImessage\fR \fB(G)/(V)\fR .RS 4 Sets a message to be displayed when clients logon to the server\&. The message should be in diff --git a/man/man8/netatalk.8.tmpl b/man/man8/netatalk.8.tmpl index 88cb179e..06878da5 100644 --- a/man/man8/netatalk.8.tmpl +++ b/man/man8/netatalk.8.tmpl @@ -48,12 +48,6 @@ SIGTERM Stop Netatalk service, AFP and CNID daemons .RE .PP -SIGQUIT -.RS 4 -Restart AFP and CNID master daemons, but keep all session AFP processes running\&. Can be used to implement -AFP service without downtime\&. -.RE -.PP SIGHUP .RS 4 Sending a From e86e6fa4710f6831d07285303df6503087435c86 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Fri, 1 Feb 2013 19:22:17 +0100 Subject: [PATCH 07/67] afpd/hash: avoid use after free in main in case of OOM Reported by Coverity as CID #968574, #968575. --- etc/afpd/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/afpd/hash.c b/etc/afpd/hash.c index 4861e811..d88cb0c2 100644 --- a/etc/afpd/hash.c +++ b/etc/afpd/hash.c @@ -1012,6 +1012,7 @@ int main(void) puts("out of memory"); free((void *) key); free(val); + break; } if (!hash_alloc_insert(h, key, val)) { From 9565c94223fad1292bba40215377b10d78ca4c0b Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Fri, 1 Feb 2013 19:23:28 +0100 Subject: [PATCH 08/67] afpd/fork: avoid use after free on of_closefork error Reported by Coverity as CID #201311. --- etc/afpd/fork.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 2d59b5da..7b24b7f2 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1037,7 +1037,7 @@ int afp_closefork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, s ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "rsrc"); if (of_closefork(obj, ofork) < 0 ) { - LOG(log_error, logtype_afpd, "afp_closefork(%s): of_closefork: %s", of_name(ofork), strerror(errno) ); + LOG(log_error, logtype_afpd, "afp_closefork: of_closefork: %s", strerror(errno) ); return( AFPERR_PARAM ); } From 71258bb5c7192740b80077c1131c1ffd5ba6ab4e Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Fri, 1 Feb 2013 19:33:59 +0100 Subject: [PATCH 09/67] afpd/fce_api: avoid null pointer dereference Move path NULL check before it is actually referenced. Reported by Coverity as CID #968570. --- etc/afpd/fce_api.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/etc/afpd/fce_api.c b/etc/afpd/fce_api.c index 49dd3cd7..36cce446 100644 --- a/etc/afpd/fce_api.c +++ b/etc/afpd/fce_api.c @@ -361,9 +361,10 @@ int fce_register(fce_ev_t event, const char *path, const char *oldpath, fce_obj_ return AFP_OK; AFP_ASSERT(event >= FCE_FIRST_EVENT && event <= FCE_LAST_EVENT); + AFP_ASSERT(path); LOG(log_debug, logtype_fce, "register_fce(path: %s, type: %s, event: %s", - path , type == fce_dir ? "dir" : "file", fce_event_names[event]); + path, type == fce_dir ? "dir" : "file", fce_event_names[event]); bname = basename_safe(path); @@ -371,8 +372,6 @@ int fce_register(fce_ev_t event, const char *path, const char *oldpath, fce_obj_ /* No listeners configured */ return AFP_OK; - if (path == NULL) - return AFPERR_PARAM; /* do some initialization on the fly the first time */ if (first_event) { From 8852315e574879a9548c31f84c6eaea59f1db90f Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Sat, 9 Feb 2013 11:36:29 +0100 Subject: [PATCH 10/67] libatalk: Fix a couple of issues in ad_openat() Reported by coverity as CID #762151, #762127. --- libatalk/adouble/ad_open.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 5aca77c0..a4a56b12 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1824,10 +1824,12 @@ int ad_openat(struct adouble *ad, EC_INIT; int cwdfd = -1; va_list args; - mode_t mode; + mode_t mode = 0; if (dirfd != -1) { if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) + if (cwdfd > 0) + close(cwdfd); EC_FAIL; } From d93abdcce7f6569c98ffad0cbb2521541d8c47b9 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Sat, 9 Feb 2013 11:49:42 +0100 Subject: [PATCH 11/67] cnid_metad: avoid out of bounds read The check of i < MAXVOLS should be moved before referencing srv[i]. Reported by Coverity as CID #762114. --- etc/cnid_dbd/cnid_metad.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c index 18e063da..7b7664d5 100644 --- a/etc/cnid_dbd/cnid_metad.c +++ b/etc/cnid_dbd/cnid_metad.c @@ -184,8 +184,8 @@ static int maybe_start_dbd(const AFPObj *obj, char *dbdpn, const char *volpath) time(&t); if (!up) { /* find an empty slot (i < maxvol) or the first free slot (i == maxvol)*/ - for (i = 0; i <= maxvol; i++) { - if (srv[i].v_path == NULL && i < MAXVOLS) { + for (i = 0; i <= maxvol && i < MAXVOLS; i++) { + if (srv[i].v_path == NULL) { up = &srv[i]; if ((up->v_path = strdup(volpath)) == NULL) return -1; From 1ff41abaee2c93a6c306d252a1f5fc4013fd41d9 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Sat, 9 Feb 2013 11:57:46 +0100 Subject: [PATCH 12/67] afpd: fix out of bounds write Reported by Coverity as CID #762111. --- etc/afpd/auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index 7569cfef..5246d436 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -912,7 +912,7 @@ int afp_changepw(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rb if ( ibuf[0] != '\0' || ibuf[1] != '\0') return AFPERR_PARAM; ibuf += 2; - len = MIN(sizeof(username), strlen(obj->username)); + len = MIN(sizeof(username) - 1, strlen(obj->username)); memcpy(username, obj->username, len); username[ len ] = '\0'; } From 4b9386e5fdbc75f6a9215d1a010698a112f34386 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Sat, 9 Feb 2013 12:07:28 +0100 Subject: [PATCH 13/67] afpd/acls: fix dereference before null check error Reported by Coverity as CID #968569. --- etc/afpd/acls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etc/afpd/acls.c b/etc/afpd/acls.c index 55a1e3ae..56ffeea9 100644 --- a/etc/afpd/acls.c +++ b/etc/afpd/acls.c @@ -1363,6 +1363,8 @@ static int check_acl_access(const AFPObj *obj, LOG(log_maxdebug, logtype_afpd, "check_acl_access(dir: \"%s\", path: \"%s\", curdir: \"%s\", 0x%08x)", cfrombstr(dir->d_fullpath), path, getcwdpath(), requested_rights); + AFP_ASSERT(vol); + /* This check is not used anymore, as OS X Server seems to be ignoring too */ #if 0 /* Get uid or gid from UUID */ From ce4484dc5e8562b3ed1876d9efd5d285800e9a22 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Sat, 9 Feb 2013 12:11:19 +0100 Subject: [PATCH 14/67] afpd/hash: return error if we can't allocate the hash Instead of possible dereference of null. Reported by Coverity as CID #968565. --- etc/afpd/hash.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etc/afpd/hash.c b/etc/afpd/hash.c index 4861e811..f0030f92 100644 --- a/etc/afpd/hash.c +++ b/etc/afpd/hash.c @@ -982,8 +982,10 @@ int main(void) "s switch to non-functioning allocator\n" "q quit"; - if (!h) + if (!h) { puts("hash_create failed"); + return 1; + } for (;;) { if (prompt) From 29ea1e9dd3df00b3ff2ba05bccd53312fd417cbe Mon Sep 17 00:00:00 2001 From: HAT Date: Sun, 10 Feb 2013 12:27:35 +0900 Subject: [PATCH 15/67] bundled libevent2 is static --- NEWS | 1 + libevent/Makefile.am | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index d98cac8a..41aac88c 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ Changes in 3.0.3 ================ * UPD: afpd: Increase default DSI server quantum to 1 MB +* UPD: bundled libevent2 is now static Changes in 3.0.2 ================ diff --git a/libevent/Makefile.am b/libevent/Makefile.am index 09505bd7..87f3f146 100644 --- a/libevent/Makefile.am +++ b/libevent/Makefile.am @@ -196,7 +196,7 @@ NO_UNDEFINED = MAYBE_CORE = endif -GENERIC_LDFLAGS = -version-info $(VERSION_INFO) $(RELEASE) $(NO_UNDEFINED) +GENERIC_LDFLAGS = -static libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC) libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) @@ -251,3 +251,5 @@ FORCE: DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h +install: + From 539bab5ea7c47c713759aac42cc0a0d9806ba73f Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 7 Feb 2013 12:25:13 +0100 Subject: [PATCH 16/67] systemd service file use PIDFile and ExecReload Add --with-lockfile=PATH configure option for specifying an alternative path for the netatalk lockfile. Implements FR #70. --- NEWS | 4 +++ configure.ac | 6 +++- distrib/initscripts/Makefile.am | 1 + distrib/initscripts/service.systemd.tmpl | 2 ++ etc/netatalk/netatalk.c | 6 ++-- include/atalk/paths.h | 29 ------------------ macros/netatalk.m4 | 38 ++++++++++++++++++++++-- macros/summary.m4 | 2 ++ 8 files changed, 53 insertions(+), 35 deletions(-) diff --git a/NEWS b/NEWS index 41aac88c..75a92291 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,10 @@ Changes in 3.0.3 ================ * UPD: afpd: Increase default DSI server quantum to 1 MB * UPD: bundled libevent2 is now static +* NEW: --with-lockfile=PATH configure option for specifying an + alternative path for the netatalk lockfile. +* UPD: systemd service file use PIDFile and ExecReload. + From FR #70. Changes in 3.0.2 ================ diff --git a/configure.ac b/configure.ac index bfb578ca..3c8843d1 100644 --- a/configure.ac +++ b/configure.ac @@ -180,10 +180,14 @@ AC_NETATALK_SENDFILE dnl Check whether bundled libevent shall not be used AC_NETATALK_LIBEVENT +dnl libatalk API checks +AC_DEVELOPER + dnl FHS stuff has to be done last because it overrides other defaults AC_NETATALK_FHS -AC_DEVELOPER +dnl netatalk lockfile path, must come after AC_NETATALK_FHS +AC_NETATALK_LOCKFILE CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys $CFLAGS" UAMS_PATH="${uams_path}" diff --git a/distrib/initscripts/Makefile.am b/distrib/initscripts/Makefile.am index 5bdf9510..2d1cb3ab 100644 --- a/distrib/initscripts/Makefile.am +++ b/distrib/initscripts/Makefile.am @@ -13,6 +13,7 @@ pkgconfdir = @PKGCONFDIR@ -e s@:SBINDIR:@${sbindir}@ \ -e s@:ETCDIR:@${pkgconfdir}@ \ -e s@:NETATALK_VERSION:@${NETATALK_VERSION}@ \ + -e s@:PATH_NETATALK_LOCK:@${PATH_NETATALK_LOCK}@ \ <$< >$@ GENERATED_FILES = \ diff --git a/distrib/initscripts/service.systemd.tmpl b/distrib/initscripts/service.systemd.tmpl index d21dde92..670f1445 100644 --- a/distrib/initscripts/service.systemd.tmpl +++ b/distrib/initscripts/service.systemd.tmpl @@ -10,6 +10,8 @@ After=syslog.target network.target avahi-daemon.service Type=forking GuessMainPID=no ExecStart=:SBINDIR:/netatalk +PIDFile=:PATH_NETATALK_LOCK: +ExecReload=/bin/kill -HUP $MAINPID Restart=always RestartSec=1 diff --git a/etc/netatalk/netatalk.c b/etc/netatalk/netatalk.c index 9ac72c5a..1a31a3a9 100644 --- a/etc/netatalk/netatalk.c +++ b/etc/netatalk/netatalk.c @@ -209,7 +209,7 @@ static void kill_childs(int sig, ...) /* this get called when error conditions are met that require us to exit gracefully */ static void netatalk_exit(int ret) { - server_unlock(_PATH_NETATALK_LOCK); + server_unlock(PATH_NETATALK_LOCK); exit(ret); } @@ -270,13 +270,13 @@ int main(int argc, char **argv) } } - if (check_lockfile("netatalk", _PATH_NETATALK_LOCK) != 0) + if (check_lockfile("netatalk", PATH_NETATALK_LOCK) != 0) exit(EXITERR_SYS); if (!debug && daemonize(0, 0) != 0) exit(EXITERR_SYS); - if (create_lockfile("netatalk", _PATH_NETATALK_LOCK) != 0) + if (create_lockfile("netatalk", PATH_NETATALK_LOCK) != 0) exit(EXITERR_SYS); sigfillset(&blocksigs); diff --git a/include/atalk/paths.h b/include/atalk/paths.h index ba4d2f23..f5f6486c 100644 --- a/include/atalk/paths.h +++ b/include/atalk/paths.h @@ -13,34 +13,5 @@ #define ATALKPATHCAT(a,b) a/**/b #endif - -/* lock file path. this should be re-organized a bit. */ -#if ! defined (_PATH_LOCKDIR) -# if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__) -# define _PATH_LOCKDIR "/var/run/" -# elif defined (BSD4_4) -# ifdef MACOSX_SERVER -# define _PATH_LOCKDIR "/var/run/" -# else -# define _PATH_LOCKDIR "/var/spool/lock/" -# endif -# elif defined (linux) -# define _PATH_LOCKDIR "/var/lock/" -# else -# define _PATH_LOCKDIR "/var/spool/locks/" -# endif -#endif - - -/* - * netatalk paths - */ -#define _PATH_AFPTKT "/tmp/AFPtktXXXXXX" -#if defined (FHS_COMPATIBILITY) || defined (__NetBSD__) || defined (__OpenBSD__) -# define _PATH_NETATALK_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"netatalk.pid") -#else -# define _PATH_NETATALK_LOCK ATALKPATHCAT(_PATH_LOCKDIR,"netatalk") -#endif - #endif /* atalk/paths.h */ diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index e77aac53..72cbaebd 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -60,13 +60,47 @@ AC_ARG_ENABLE(fhs, use_pam_so=yes AC_DEFINE(FHS_COMPATIBILITY, 1, [Define if you want compatibily with the FHS]) AC_MSG_RESULT([yes]) + atalk_cv_fhs_compat=yes else AC_MSG_RESULT([no]) + atalk_cv_fhs_compat=no fi ],[ AC_MSG_RESULT([no]) - ] -)]) + atalk_cv_fhs_compat=no +])]) + +dnl netatalk lockfile path +AC_DEFUN([AC_NETATALK_LOCKFILE], [ + AC_MSG_CHECKING([netatalk lockfile path]) + AC_ARG_WITH( + lockfile, + [AS_HELP_STRING([--with-lockfile=PATH],[Path of netatalk lockfile])], + ac_cv_netatalk_lock=$withval, + ac_cv_netatalk_lock="" + ) + if test -z "$ac_cv_netatalk_lock" ; then + ac_cv_netatalk_lock=/var/spool/locks/netatalk + if test x"$atalk_cv_fhs_compat" = x"yes" ; then + ac_cv_netatalk_lock=/var/run/netatalk.pid + else + case "$host_os" in + *freebsd*) + ac_cv_netatalk_lock=/var/spool/lock/netatalk + ;; + *netbsd*|*openbsd*) + ac_cv_netatalk_lock=/var/run/netatalk.pid + ;; + *linux*) + ac_cv_netatalk_lock=/var/lock/netatalk + ;; + esac + fi + fi + AC_DEFINE_UNQUOTED(PATH_NETATALK_LOCK, ["$ac_cv_netatalk_lock"], [netatalk lockfile path]) + AC_SUBST(PATH_NETATALK_LOCK, ["$ac_cv_netatalk_lock"]) + AC_MSG_RESULT([$ac_cv_netatalk_lock]) +]) dnl 64bit platform check AC_DEFUN([AC_NETATALK_64BIT_LIBS], [ diff --git a/macros/summary.m4 b/macros/summary.m4 index 6c696fc2..f4d99863 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -9,6 +9,8 @@ AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], [ else AC_MSG_RESULT([ none]) fi + AC_MSG_RESULT([ Netatalk lockfile:]) + AC_MSG_RESULT([ $ac_cv_netatalk_lock]) AC_MSG_RESULT([ AFP:]) AC_MSG_RESULT([ Extended Attributes: $neta_cv_eas]) AC_MSG_RESULT([ ACL support: $with_acl_support]) From f0d8ae7e26bbc6eb0bfc55748aa8ef83c1bc54dc Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 11 Feb 2013 22:03:26 +0100 Subject: [PATCH 17/67] afpd/file: fix memory leak Reported by Coverity as CID #201194. --- etc/afpd/file.c | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 153f1325..e48afe21 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -335,6 +335,7 @@ int getmetadata(const AFPObj *obj, || (bconchar(fullpath, '/') != BSTR_OK) || (bcatcstr(fullpath, upath)) != BSTR_OK) { LOG(log_error, logtype_afpd, "getmetadata: fullpath: %s", strerror(errno)); + bdestroy(fullpath); return AFPERR_MISC; } From ae03ddc173c85f0c801ae899bde12f6049189f62 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 11 Feb 2013 22:11:46 +0100 Subject: [PATCH 18/67] afpd/filedir: fix memory leak Reported by Coverity as CID #201196. --- etc/afpd/filedir.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 543db0dc..5a23f28e 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -582,8 +582,10 @@ char *absupath(const struct vol *vol, struct dir *dir, char *u) return NULL; if (bcatcstr(path, u) != BSTR_OK) return NULL; - if (path->slen > MAXPATHLEN) + if (path->slen > MAXPATHLEN) { + bdestroy(path); return NULL; + } LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path)); From 49759493eb1e3af9cba918721b0f945dd153a18c Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 11 Feb 2013 22:18:01 +0100 Subject: [PATCH 19/67] afpd/colume: fix a couple of memory leaks Reported by Coverity as CID #201199, #201200. --- etc/afpd/volume.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 8798635a..88677155 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -176,13 +176,18 @@ static int get_tm_used(struct vol * restrict vol) EC_NULL_LOG( infoplist = bformat("%s/%s/%s", vol->v_path, entry->d_name, "Info.plist") ); - if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) + if ((bandsize = get_tm_bandsize(cfrombstr(infoplist))) == -1) { + bdestroy(infoplist); continue; + } EC_NULL_LOG( bandsdir = bformat("%s/%s/%s/", vol->v_path, entry->d_name, "bands") ); - if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) + if ((links = get_tm_bands(cfrombstr(bandsdir))) == -1) { + bdestroy(infoplist); + bdestroy(bandsdir); continue; + } used += (links - 1) * bandsize; LOG(log_debug, logtype_afpd, "getused(\"%s\"): bands: %" PRIu64 " bytes", From 2f88f394f83e819415a7a505b80ba7b57615649a Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 11 Feb 2013 22:31:24 +0100 Subject: [PATCH 20/67] cnid_dbd: fix resource leak Reported by Coverity as CID #968567. --- etc/cnid_dbd/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c index 767e1e3c..0067504a 100644 --- a/etc/cnid_dbd/main.c +++ b/etc/cnid_dbd/main.c @@ -228,8 +228,10 @@ static int delete_db(void) LOG(log_warning, logtype_cnid, "Recreated CNID BerkeleyDB databases of volume \"%s\"", vol->v_localname); EC_CLEANUP: - if (cwd != -1) + if (cwd != -1) { fchdir(cwd); + close(cwd); + } EC_EXIT; } From b4a69f5a70e1d928f658a3d13238fd98c898a3fb Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 11 Feb 2013 22:35:21 +0100 Subject: [PATCH 21/67] afpd/directory: avoid unitialized pointer read Initialize fullpath to null so that in case of error before its allocation we don't call bdestroy on random memory. Reported by Coverity as CID #201284. --- etc/afpd/directory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 9a4fc64e..eb1cdf58 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -815,7 +815,7 @@ struct dir *dir_add(struct vol *vol, const struct dir *dir, struct path *path, i cnid_t id; struct adouble ad; struct adouble *adp = NULL; - bstring fullpath; + bstring fullpath = NULL; AFP_ASSERT(vol); AFP_ASSERT(dir); From 0253f09e2f0dab6d6d721264234161539aad4774 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Mon, 11 Feb 2013 22:43:53 +0100 Subject: [PATCH 22/67] libatal/vfs: stats a path before checking if it is a directory Reported by Coverity as CID #201301. --- libatalk/vfs/vfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c index 3dd3ebb4..a349cfe8 100644 --- a/libatalk/vfs/vfs.c +++ b/libatalk/vfs/vfs.c @@ -408,6 +408,9 @@ static int RF_posix_acl(VFS_FUNC_ARGS_ACL) struct stat st; int len; + if (stat(path, &st) == -1) + EC_FAIL; + if (S_ISDIR(st.st_mode)) { len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path); if (len < 0 || len >= MAXPATHLEN) From 5e0444c335b5afc0f86fab91ed1f02de9bdf2835 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 13 Feb 2013 17:27:52 +0100 Subject: [PATCH 23/67] Couldn't create folders on FreeBSD 9.1 ZFS fileystems Fixes bug #491. --- NEWS | 2 ++ libatalk/acl/unix.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/NEWS b/NEWS index 75a92291..eb0b275c 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ Changes in 3.0.3 alternative path for the netatalk lockfile. * UPD: systemd service file use PIDFile and ExecReload. From FR #70. +* FIX: Couldn't create folders on FreeBSD 9.1 ZFS fileystems. + Fixed bug #491. Changes in 3.0.2 ================ diff --git a/libatalk/acl/unix.c b/libatalk/acl/unix.c index 62849351..cc69d8ad 100644 --- a/libatalk/acl/unix.c +++ b/libatalk/acl/unix.c @@ -308,6 +308,14 @@ int posix_chmod(const char *name, mode_t mode) { /* Call chmod() first because there might be some special bits to be set which * aren't related to access control. */ +#ifdef BSD4_4 + /* + * On FreeBSD chmod_acl() ends up in here too, but on + * FreeBSD sine ~9.1 with ZFS doesn't allow setting the g+s bit. + * Fixes PR #491. + */ + mode &= 0777; +#endif ret = chmod(name, mode); if (ret) From d83c3a5b7d2fa057fc8f39707733669b7dece8cc Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 13 Feb 2013 21:54:01 +0100 Subject: [PATCH 24/67] afpd/volume: avoid read of unitialized pointer Reported by Coverity as CID #980994. --- etc/afpd/volume.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 88677155..9c7eb2bd 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -673,7 +673,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t size_t namelen; uint16_t bitmap; char *vol_uname; - char *vol_mname; + char *vol_mname = NULL; char *volname_tmp; ibuf += 2; From 1db3409a39c1700e4e661d2e00fa2cbdb6ee6cd7 Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 13 Feb 2013 21:58:00 +0100 Subject: [PATCH 25/67] libatalk: avoid double close in ad_openat Partly revert 8852315e574879a9548c31f84c6eaea59f1db90f Reported by Coverity as CID #980995. --- libatalk/adouble/ad_open.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index a4a56b12..3cedebab 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1828,8 +1828,6 @@ int ad_openat(struct adouble *ad, if (dirfd != -1) { if ((cwdfd = open(".", O_RDONLY) == -1) || (fchdir(dirfd) != 0)) - if (cwdfd > 0) - close(cwdfd); EC_FAIL; } From cc9df88163a2e018a55725f9b87c4002c84811ac Mon Sep 17 00:00:00 2001 From: Riccardo Magliocchetti Date: Wed, 13 Feb 2013 22:18:41 +0100 Subject: [PATCH 26/67] afpd/file: fix check in deletefile AD_RSRC_OPEN(ad) is defined as: (((ad)->ad_reso_refcount) && (ad_reso_fileno(ad) >= 0)) So there's no way it can returns -1 Reported by coverity as CID #762087. --- etc/afpd/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/file.c b/etc/afpd/file.c index e48afe21..e7859659 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1580,7 +1580,7 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) adp = &ad; } - if ( adp && AD_RSRC_OPEN(adp) != -1 ) { /* there's a resource fork */ + if ( adp && AD_RSRC_OPEN(adp) ) { /* there's a resource fork */ adflags |= ADFLAGS_RF; /* FIXME we have a pb here because we want to know if a file is open * there's a 'priority inversion' if you can't open the ressource fork RW From a91e49a8d841b066e948a49439fcb3f3dbba4bde Mon Sep 17 00:00:00 2001 From: HAT Date: Thu, 14 Feb 2013 23:27:29 +0900 Subject: [PATCH 27/67] update RedHat initscript "graceful" is removed because SIGQUIT is gone. "reload" use SIGHUP. "condrestart" is added because spec file requires it. --- NEWS | 1 + distrib/initscripts/rc.redhat.tmpl | 31 ++++++++++++++++++------------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index eb0b275c..934ce79d 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ Changes in 3.0.3 alternative path for the netatalk lockfile. * UPD: systemd service file use PIDFile and ExecReload. From FR #70. +* UPD: RedHat sysvinit: rm graceful, reimplement reload, add condrestart * FIX: Couldn't create folders on FreeBSD 9.1 ZFS fileystems. Fixed bug #491. diff --git a/distrib/initscripts/rc.redhat.tmpl b/distrib/initscripts/rc.redhat.tmpl index 643448ae..0721d9f6 100644 --- a/distrib/initscripts/rc.redhat.tmpl +++ b/distrib/initscripts/rc.redhat.tmpl @@ -21,7 +21,7 @@ RETVAL=1 netatalk_startup() { # Check that networking is up. if [ ${NETWORKING} = "no" ]; then - echo "[Network isn't started]"; + echo "[Network isn't started]"; exit 1; fi @@ -51,11 +51,17 @@ netatalk_stop() { fi } -# code to cause apfd and cnid_metad to restart -netatalk_graceful() { +# restart code +netatalk_restart() { + netatalk_stop + netatalk_startup +} + +# reload config files +netatalk_reload() { if [ -x ${NETATALK_SBIN}/netatalk ]; then - echo -n $"Restarting cnid_metad and afpd: " - killproc netatalk -QUIT + echo -n $"Reloading $prog: " + killproc netatalk -HUP RETVAL=$? echo fi @@ -68,20 +74,21 @@ case "$1" in 'stop') netatalk_stop ;; - 'restart'|'reload') - $0 stop - $0 start - RETVAL=$? + 'restart') + netatalk_restart + ;; + 'reload'|'graceful') + netatalk_reload ;; 'status') status netatalk RETVAL=$? ;; - 'graceful') - netatalk_graceful + 'condrestart') + [ -f /var/lock/subsys/netatalk ] && netatalk_restart || : ;; *) - echo "Usage: $0 {start|stop|restart|reload|status|graceful}" + echo "Usage: $0 {start|stop|restart|reload|status|condrestart}" exit 2 esac From 726e33c8e3cdd4bfe7a7f063377e56b038dbc7a7 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 15 Feb 2013 11:19:50 +0100 Subject: [PATCH 28/67] User homes directory names Fix an issue with user homes when user home directory has not the same name as the username. Fixes bug #497. --- NEWS | 3 ++ libatalk/util/netatalk_conf.c | 61 +++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/NEWS b/NEWS index 934ce79d..461cc85a 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,9 @@ Changes in 3.0.3 * UPD: RedHat sysvinit: rm graceful, reimplement reload, add condrestart * FIX: Couldn't create folders on FreeBSD 9.1 ZFS fileystems. Fixed bug #491. +* FIX: Fix an issue with user homes when user home directory has not the + same name as the username. + Fixes bug #497. Changes in 3.0.2 ================ diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 1bfa3a94..75561245 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -1432,6 +1432,56 @@ struct vol *getvolbyvid(const uint16_t vid ) return( vol ); } +/* + * 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. + * + * @param path (r) absolute volume path + * @returns NULL if no match is found, pointer to username if successfull + * + */ +static char *getuserbypath(const char *path) +{ + EC_INIT; + struct stat sbuf; + struct passwd *pwd; + char *hdir = NULL; + + LOG(log_debug, logtype_afpd, "getuserbypath(\"%s\")", path); + + /* does folder exists? */ + if (stat(path, &sbuf) != 0) + EC_FAIL; + + /* get uid of dir owner */ + if ((pwd = getpwuid(sbuf.st_uid)) == NULL) + EC_FAIL; + + /* does user home directory exists? */ + if (stat(pwd->pw_dir, &sbuf) != 0) + EC_FAIL; + + /* resolve and remove symlinks */ + if ((hdir = realpath_safe(pwd->pw_dir)) == NULL) + EC_FAIL; + + /* handle subdirectories, path = */ + if (strncmp(path, hdir, strlen(hdir)) != 0) + EC_FAIL; + + LOG(log_debug, logtype_afpd, "getuserbypath: match user: %s, home: %s, realhome: %s", + pwd->pw_name, pwd->pw_dir, hdir); + +EC_CLEANUP: + if (hdir) + free(hdir); + if (ret != 0) + return NULL; + return pwd->pw_name; +} /*! * Search volume by path, creating user home vols as necessary * @@ -1447,6 +1497,9 @@ struct vol *getvolbyvid(const uint16_t vid ) * (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 + * (5b) 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 * @@ -1539,6 +1592,14 @@ struct vol *getvolbypath(AFPObj *obj, const char *path) subpath = prw; strlcat(tmpbuf, user, MAXPATHLEN); + if (getpwnam(user) == NULL) { + /* (5b) */ + char *tuser; + if ((tuser = getuserbypath(tmpbuf)) != NULL) { + free(user); + user = strdup(tuser); + } + } strlcpy(obj->username, user, MAXUSERLEN); strlcat(tmpbuf, "/", MAXPATHLEN); From b279c8fb6bcc7633ac196ad1ba6f3580ac63a517 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 15 Feb 2013 11:32:15 +0100 Subject: [PATCH 29/67] Add checks for required packages --- bootstrap | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/bootstrap b/bootstrap index 76b98f3b..b847ba65 100755 --- a/bootstrap +++ b/bootstrap @@ -1,5 +1,50 @@ #!/bin/sh +DIE=0 + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`autoconf' installed to." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(libtool --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`libtool' installed." + echo "Get ftp://ftp.gnu.org/pub/gnu/libtool-1.2d.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`automake' installed." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +(aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing \`aclocal'. The version of \`automake'" + echo "installed doesn't appear recent enough." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + +(pkg-config --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`pkg-config' installed." + DIE=1 +} + +if test "$DIE" -eq 1; then + exit 1 +fi + set -x rm -rf autom4te*.cache From 0890360dc726ea439b8af81ce21eb9508841bb12 Mon Sep 17 00:00:00 2001 From: HAT Date: Fri, 15 Feb 2013 21:13:35 +0900 Subject: [PATCH 30/67] typo in netatalk.c --- etc/netatalk/netatalk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/netatalk/netatalk.c b/etc/netatalk/netatalk.c index 1a31a3a9..b3ab20a1 100644 --- a/etc/netatalk/netatalk.c +++ b/etc/netatalk/netatalk.c @@ -291,7 +291,7 @@ int main(int argc, char **argv) LOG(log_note, logtype_default, "Netatalk AFP server starting"); if ((afpd_pid = run_process(_PATH_AFPD, "-d", "-F", obj.options.configfile, NULL)) == -1) { - LOG(log_error, logtype_afpd, "Error starting 'cnid_metad'"); + LOG(log_error, logtype_afpd, "Error starting 'afpd'"); netatalk_exit(EXITERR_CONF); } From 01e4f40259950a534d8608e0b3e68e50fb1ca233 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 19 Feb 2013 17:35:04 +0100 Subject: [PATCH 31/67] Several fixes in ad_conv_dehex() Testing whether we need to perform dehexing was done by a simple strchr(':'), thus names only containing a single ':' would trigger dehexing even though they might not contain the relevant strings ":2e" or :2f". Also fix a ressource leak in bfindreplace() and simplify the check whether a rename took place in enumerate.c. --- etc/afpd/enumerate.c | 18 ++++++++---------- libatalk/adouble/ad_conv.c | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c index 0c3c0576..5f0e1644 100644 --- a/etc/afpd/enumerate.c +++ b/etc/afpd/enumerate.c @@ -362,16 +362,14 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, /* conversions on the fly */ const char *convname; - if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0 && convname) { - s_path.u_name = (char *)convname; - } - - /* Fixup CNID db if ad_convert resulted in a rename (then convname != NULL) */ - if (convname) { - s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last)); - if (s_path.id != CNID_INVALID) { - if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)) != 0) - LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname)); + if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0) { + if (convname) { + s_path.u_name = (char *)convname; + s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last)); + if (s_path.id != CNID_INVALID) { + if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)) != 0) + LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname)); + } } } diff --git a/libatalk/adouble/ad_conv.c b/libatalk/adouble/ad_conv.c index a9fae763..151ab9fd 100644 --- a/libatalk/adouble/ad_conv.c +++ b/libatalk/adouble/ad_conv.c @@ -201,21 +201,31 @@ static int ad_conv_dehex(const char *path, const struct stat *sp, const struct v { EC_INIT; static char buf[MAXPATHLEN]; - const char *p; int adflags = S_ISDIR(sp->st_mode) ? ADFLAGS_DIR : 0; bstring newpath = NULL; + static bstring str2e = NULL; + static bstring str2f = NULL; + static bstring strdot = NULL; + static bstring strcolon = NULL; + + if (str2e == NULL) { + str2e = bfromcstr(":2e"); + str2f = bfromcstr(":2f"); + strdot = bfromcstr("."); + strcolon = bfromcstr(":"); + } LOG(log_debug, logtype_ad,"ad_conv_dehex(\"%s\"): BEGIN", fullpathname(path)); *newpathp = NULL; - if ((p = strchr(path, ':')) == NULL) + if (((strstr(path, ":2e")) == NULL) && ((strstr(path, ":2f")) == NULL) ) goto EC_CLEANUP; EC_NULL( newpath = bfromcstr(path) ); - EC_ZERO( bfindreplace(newpath, bfromcstr(":2e"), bfromcstr("."), 0) ); - EC_ZERO( bfindreplace(newpath, bfromcstr(":2f"), bfromcstr(":"), 0) ); + EC_ZERO( bfindreplace(newpath, str2e, strdot, 0) ); + EC_ZERO( bfindreplace(newpath, str2f, strcolon, 0) ); become_root(); if (adflags != ADFLAGS_DIR) From 22ad101eb72bf10fe5144526209798c677b2d1d8 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 5 Feb 2013 17:25:27 +0100 Subject: [PATCH 32/67] AFP statistics via dbus IPC Fix PAM config installation. make distcheck was failing on Solaris in uninstall, because the uninstall target ran some `rm -f PAMFILE` where PAMFILE is hardcoded to /etc/pam.d. The resulting EPERM causes the make target to fail. --- NEWS | 7 + config/Makefile.am | 8 +- config/netatalk-dbus.conf | 17 +++ config/pam/.gitignore | 2 +- config/pam/Makefile.am | 28 +--- .../pam/{netatalk.pam.tmpl => netatalk.tmpl} | 0 configure.ac | 3 + contrib/shell_utils/Makefile.am | 4 +- contrib/shell_utils/afpstats | 29 +++++ etc/afpd/Makefile.am | 23 +++- etc/afpd/afp_dsi.c | 15 +-- etc/afpd/afpstats-service.xml | 8 ++ etc/afpd/afpstats.c | 118 +++++++++++++++++ etc/afpd/afpstats.h | 23 ++++ etc/afpd/afpstats_obj.c | 110 ++++++++++++++++ etc/afpd/afpstats_obj.h | 19 +++ etc/afpd/afpstats_service_glue.h | 121 ++++++++++++++++++ etc/afpd/auth.c | 3 + etc/afpd/main.c | 6 + etc/afpd/volume.c | 28 ++++ include/atalk/dsi.h | 3 - include/atalk/server_child.h | 7 +- include/atalk/server_ipc.h | 3 + libatalk/dsi/dsi_stream.c | 4 - libatalk/util/server_child.c | 26 ++-- libatalk/util/server_ipc.c | 55 ++++++++ macros/netatalk.m4 | 24 ++++ macros/pam-check.m4 | 7 + macros/summary.m4 | 2 + 29 files changed, 648 insertions(+), 55 deletions(-) create mode 100644 config/netatalk-dbus.conf rename config/pam/{netatalk.pam.tmpl => netatalk.tmpl} (100%) create mode 100755 contrib/shell_utils/afpstats create mode 100644 etc/afpd/afpstats-service.xml create mode 100644 etc/afpd/afpstats.c create mode 100644 etc/afpd/afpstats.h create mode 100644 etc/afpd/afpstats_obj.c create mode 100644 etc/afpd/afpstats_obj.h create mode 100644 etc/afpd/afpstats_service_glue.h diff --git a/NEWS b/NEWS index 461cc85a..df015fa5 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,13 @@ Changes in 3.0.3 * FIX: Fix an issue with user homes when user home directory has not the same name as the username. Fixes bug #497. +* UPD: Fix PAM config install, new default installation dir is + $sysconfdir/pam.d/. Add configure option --with-pam-confdir + to specify alternative path. +* NEW: AFP stats about active session via dbus IPC. Client side python + program `afpstats`. Requires dbus, dbus-glib any python-dbus. + configure option --dbus-sysconf-dir for specifying dbus + system security configuration files. Changes in 3.0.2 ================ diff --git a/config/Makefile.am b/config/Makefile.am index 57c85ff3..e72c38f3 100644 --- a/config/Makefile.am +++ b/config/Makefile.am @@ -6,13 +6,19 @@ SUFFIXES = .tmpl . TMPLFILES = afp.conf.tmpl GENFILES = afp.conf CLEANFILES = $(GENFILES) -EXTRA_DIST = afp.conf.tmpl extmap.conf +EXTRA_DIST = afp.conf.tmpl extmap.conf netatalk-dbus.conf OVERWRITE_CONFIG = @OVERWRITE_CONFIG@ CONFFILES = extmap.conf pkgconfdir = @PKGCONFDIR@ + +if HAVE_DBUS_GLIB +dbusservicedir = $(DBUS_SYS_DIR) +dbusservice_DATA = netatalk-dbus.conf +endif + # # rule to parse template files # diff --git a/config/netatalk-dbus.conf b/config/netatalk-dbus.conf new file mode 100644 index 00000000..1646efd4 --- /dev/null +++ b/config/netatalk-dbus.conf @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/config/pam/.gitignore b/config/pam/.gitignore index dbbab4b2..d209ccf9 100644 --- a/config/pam/.gitignore +++ b/config/pam/.gitignore @@ -1,5 +1,5 @@ Makefile Makefile.in netatalk.pam -.gitignore +netatalk *.o diff --git a/config/pam/Makefile.am b/config/pam/Makefile.am index e01d784c..62affbda 100644 --- a/config/pam/Makefile.am +++ b/config/pam/Makefile.am @@ -1,10 +1,9 @@ ## Makefile for distrib/pam/ SUFFIXES = .tmpl . -pamdir = @PAMDIR@/etc/pam.d -EXTRA_DIST = netatalk.pam.tmpl -noinst_SCRIPTS = netatalk.pam -CLEANFILES = netatalk.pam +EXTRA_DIST = netatalk.tmpl +noinst_SCRIPTS = netatalk +CLEANFILES = netatalk .tmpl: sed -e "s,[@]PAM_DIRECTIVE[@],${PAM_DIRECTIVE},g" \ @@ -15,23 +14,6 @@ CLEANFILES = netatalk.pam <$< >$@ if USE_PAM -install-data-local: netatalk.pam - $(mkinstalldirs) $(DESTDIR)$(pamdir) - if test "x$(OVERWRITE_CONFIG)" = "xyes" -o ! -f $(DESTDIR)$(pamdir)/netatalk; then \ - echo "$(INSTALL_DATA) $$f $(DESTDIR)$(pamdir)/netatalk"; \ - $(INSTALL_DATA) netatalk.pam $(DESTDIR)$(pamdir)/netatalk || echo "WARNING: Can't install PAM files"; \ - else \ - echo "not overwriting $(DESTDIR)$(pamdir)/netatalk"; \ - fi; - -uninstall-local: - echo rm -f $(DESTDIR)$(pamdir)/netatalk; \ - rm -f $(DESTDIR)$(pamdir)/netatalk; \ - for f in $(CONFFILES) $(GENFILES); do \ - echo rm -f $(DESTDIR)$(pkgconfdir)/$$f; \ - rm -f $(DESTDIR)$(pkgconfdir)/$$f; \ - done -else -install-data-local: -uninstall-local: +pamdir = $(PAMDIR) +pam_DATA = netatalk endif diff --git a/config/pam/netatalk.pam.tmpl b/config/pam/netatalk.tmpl similarity index 100% rename from config/pam/netatalk.pam.tmpl rename to config/pam/netatalk.tmpl diff --git a/configure.ac b/configure.ac index 3c8843d1..88f81aaf 100644 --- a/configure.ac +++ b/configure.ac @@ -189,6 +189,9 @@ AC_NETATALK_FHS dnl netatalk lockfile path, must come after AC_NETATALK_FHS AC_NETATALK_LOCKFILE +dnl Check for dbus-glib, for AFP stats on dbus +AC_NETATALK_DBUS_GLIB + CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys $CFLAGS" UAMS_PATH="${uams_path}" diff --git a/contrib/shell_utils/Makefile.am b/contrib/shell_utils/Makefile.am index bb4d9cbf..dc4c7db7 100644 --- a/contrib/shell_utils/Makefile.am +++ b/contrib/shell_utils/Makefile.am @@ -18,6 +18,6 @@ SUFFIXES = .tmpl . CLEANFILES = $(GENERATED_FILES) -bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES) +bin_SCRIPTS = $(PERLSCRIPTS) $(GENERATED_FILES) afpstats -EXTRA_DIST = $(TEMPLATE_FILES) make-casetable.pl make-precompose.h.pl +EXTRA_DIST = $(TEMPLATE_FILES) make-casetable.pl make-precompose.h.pl afpstats diff --git a/contrib/shell_utils/afpstats b/contrib/shell_utils/afpstats new file mode 100755 index 00000000..8c5413c8 --- /dev/null +++ b/contrib/shell_utils/afpstats @@ -0,0 +1,29 @@ +#!/usr/bin/env python + +usage = """Usage: +python afpstats.py +""" + +import sys +from traceback import print_exc +import dbus + +def main(): + bus = dbus.SystemBus() + + try: + remote_object = bus.get_object("org.netatalk.AFPStats", + "/org/netatalk/AFPStats") + + except dbus.DBusException: + print_exc() + sys.exit(1) + + iface = dbus.Interface(remote_object, "org.netatalk.AFPStats") + + reply = iface.GetUsers() + for name in reply: + print name + +if __name__ == '__main__': + main() diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index 2404ad7d..1612344a 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -1,6 +1,10 @@ # Makefile.am for etc/afpd/ pkgconfdir = @PKGCONFDIR@ +BUILT_SOURCES = +EXTRA_DIST = +CLEANFILES = +DISTCLEANFILES = sbin_PROGRAMS = afpd noinst_PROGRAMS = hash fce @@ -61,11 +65,28 @@ if HAVE_ACLS afpd_SOURCES += acls.c endif +if HAVE_DBUS_GLIB +BUILT_SOURCES += afpstats_service_glue.h +EXTRA_DIST += afpstats-service.xml +DISTCLEANFILES += afpstats_service_glue.h + +afpstats_service_glue.h: afpstats-service.xml + $(LIBTOOL) --mode=execute \ + dbus-binding-tool \ + --prefix=afpstats_obj \ + --mode=glib-server \ + --output=afpstats_service_glue.h \ + $(top_srcdir)/etc/afpd/afpstats-service.xml + +afpd_SOURCES += afpstats.c afpstats_obj.c +afpd_CFLAGS += $(DBUS_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION +afpd_LDFLAGS += $(DBUS_LIBS) $(DBUS_GLIB_LIBS) -ldbus-glib-1 +endif noinst_HEADERS = auth.h afp_config.h desktop.h directory.h fce_api_internal.h file.h \ filedir.h fork.h icon.h mangle.h misc.h status.h switch.h \ uam_auth.h uid.h unix.h volume.h hash.h acls.h acl_mappings.h extattrs.h \ - dircache.h afp_zeroconf.h afp_avahi.h afp_mdns.h + dircache.h afp_zeroconf.h afp_avahi.h afp_mdns.h afpstats.h afpstats_obj.h hash_SOURCES = hash.c hash_CFLAGS = -DKAZLIB_TEST_MAIN -I$(top_srcdir)/include diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index 77918c56..646e8d12 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -473,6 +473,8 @@ void afp_over_dsi(AFPObj *obj) int flag = 1; setsockopt(dsi->socket, SOL_TCP, TCP_NODELAY, &flag, sizeof(flag)); + ipc_child_state(obj, DSI_RUNNING); + /* get stuck here until the end */ while (1) { if (sigsetjmp(recon_jmp, 1) != 0) @@ -497,15 +499,6 @@ void afp_over_dsi(AFPObj *obj) exit(0); } -#if 0 - /* got ECONNRESET in read from client => exit*/ - if (dsi->flags & DSI_GOT_ECONNRESET) { - LOG(log_note, logtype_afpd, "afp_over_dsi: client connection reset"); - afp_dsi_close(obj); - exit(0); - } -#endif - if (dsi->flags & DSI_RECONINPROG) { LOG(log_note, logtype_afpd, "afp_over_dsi: failed reconnect"); afp_dsi_close(obj); @@ -516,8 +509,11 @@ void afp_over_dsi(AFPObj *obj) if (dsi_disconnect(dsi) != 0) afp_dsi_die(EXITERR_CLNT); + ipc_child_state(obj, DSI_DISCONNECTED); + while (dsi->flags & DSI_DISCONNECTED) pause(); /* gets interrupted by SIGALARM or SIGURG tickle */ + ipc_child_state(obj, DSI_RUNNING); continue; /* continue receiving until disconnect timer expires * or a primary reconnect succeeds */ } @@ -526,6 +522,7 @@ void afp_over_dsi(AFPObj *obj) LOG(log_debug, logtype_afpd, "afp_over_dsi: got data, ending normal sleep"); dsi->flags &= ~DSI_SLEEPING; dsi->tickle = 0; + ipc_child_state(obj, DSI_RUNNING); } if (reload_request) { diff --git a/etc/afpd/afpstats-service.xml b/etc/afpd/afpstats-service.xml new file mode 100644 index 00000000..099c778a --- /dev/null +++ b/etc/afpd/afpstats-service.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/etc/afpd/afpstats.c b/etc/afpd/afpstats.c new file mode 100644 index 00000000..1dbacdf8 --- /dev/null +++ b/etc/afpd/afpstats.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2013 Frank Lahm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "afpstats_obj.h" +#include "afpstats_service_glue.h" + +/* + * Beware: this struct is accessed and modified from the main thread + * and from this thread, thus be careful to lock and unlock the mutex. + */ +static server_child_t *childs; + +static gpointer afpstats_thread(gpointer _data) +{ + DBusGConnection *bus; + DBusGProxy *bus_proxy; + GError *error = NULL; + GMainLoop *thread_loop; + guint request_name_result; + sigset_t sigs; + + /* Block all signals in this thread */ + sigfillset(&sigs); + pthread_sigmask(SIG_BLOCK, &sigs, NULL); + + dbus_g_object_type_install_info(AFPSTATS_TYPE_OBJECT, &dbus_glib_afpstats_obj_object_info); + + thread_loop = g_main_loop_new(NULL, FALSE); + + if (!(bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error))) { + LOG(log_error, logtype_afpd,"Couldn't connect to system bus: %s", error->message); + return NULL; + } + + if (!(bus_proxy = dbus_g_proxy_new_for_name(bus, "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus"))) { + LOG(log_error, logtype_afpd,"Couldn't create bus proxy"); + return NULL; + } + + if (!dbus_g_proxy_call(bus_proxy, "RequestName", &error, + G_TYPE_STRING, "org.netatalk.AFPStats", + G_TYPE_UINT, 0, + G_TYPE_INVALID, + G_TYPE_UINT, &request_name_result, + G_TYPE_INVALID)) { + LOG(log_error, logtype_afpd, "Failed to acquire DBUS name: %s", error->message); + return NULL; + } + + AFPStatsObj *obj = g_object_new(AFPSTATS_TYPE_OBJECT, NULL); + dbus_g_connection_register_g_object(bus, "/org/netatalk/AFPStats", G_OBJECT(obj)); + + g_main_loop_run(thread_loop); + return thread_loop; +} + +static void my_glib_log(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + LOG(log_error, logtype_afpd, "%s: %s", log_domain, message); +} + +server_child_t *afpstats_get_and_lock_childs(void) +{ + pthread_mutex_lock(&childs->servch_lock); + return childs; +} + +void afpstats_unlock_childs(void) +{ + pthread_mutex_unlock(&childs->servch_lock); +} + +int afpstats_init(server_child_t *childs_in) +{ + GThread *thread; + + childs = childs_in; + g_type_init(); + (void)g_log_set_default_handler(my_glib_log, NULL); + g_thread_init(NULL); + thread = g_thread_create(afpstats_thread, NULL, TRUE, NULL); + + return 0; +} diff --git a/etc/afpd/afpstats.h b/etc/afpd/afpstats.h new file mode 100644 index 00000000..9f742ad7 --- /dev/null +++ b/etc/afpd/afpstats.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Frank Lahm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef AFPD_AFPSTATS_H +#define AFPD_AFPSTATS_H + +#include + +extern int afpstats_init(server_child_t *); +extern server_child_t *afpstats_get_and_lock_childs(void); +extern void afpstats_unlock_childs(void); +#endif diff --git a/etc/afpd/afpstats_obj.c b/etc/afpd/afpstats_obj.c new file mode 100644 index 00000000..755d7a59 --- /dev/null +++ b/etc/afpd/afpstats_obj.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013 Frank Lahm + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "afpstats.h" +#include "afpstats_obj.h" + +struct AFPStatsObj +{ + GObject parent; +}; + +struct AFPStatsObjClass +{ + GObjectClass parent; +}; + +static void afpstats_obj_init(AFPStatsObj *obj) +{ +} + +static void afpstats_obj_class_init(AFPStatsObjClass *klass) +{ +} + +static gpointer afpstats_obj_parent_class = NULL; + +static void afpstats_obj_class_intern_init(gpointer klass) +{ + afpstats_obj_parent_class = g_type_class_peek_parent(klass); + afpstats_obj_class_init((AFPStatsObjClass *)klass); +} + +GType afpstats_obj_get_type(void) +{ + static volatile gsize g_define_type_id__volatile = 0; + if (g_once_init_enter(&g_define_type_id__volatile)) { + GType g_define_type_id = g_type_register_static_simple( + G_TYPE_OBJECT, + g_intern_static_string("AFPStatsObj"), + sizeof(AFPStatsObjClass), + (GClassInitFunc)afpstats_obj_class_intern_init, + sizeof(AFPStatsObj), + (GInstanceInitFunc)afpstats_obj_init, + (GTypeFlags)0); + g_once_init_leave(&g_define_type_id__volatile, g_define_type_id); + } + return g_define_type_id__volatile; +} + +gboolean afpstats_obj_get_users(AFPStatsObj *obj, gchar ***ret, GError **error) +{ + gchar **names; + server_child_t *childs = afpstats_get_and_lock_childs(); + afp_child_t *child; + struct passwd *pw; + int i = 0, j; + char buf[256]; + + names = g_new(char *, childs->servch_count + 1); + + for (j = 0; j < CHILD_HASHSIZE && i < childs->servch_count; j++) { + child = childs->servch_table[j]; + while (child) { + if (child->afpch_valid && (pw = getpwuid(child->afpch_uid))) { + time_t time = child->afpch_logintime; + strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime(&time)); + names[i++] = g_strdup_printf("name: %s, pid: %d, logintime: %s, state: %s, volumes: %s", + pw->pw_name, child->afpch_pid, buf, + child->afpch_state == DSI_RUNNING ? "active" : + child->afpch_state == DSI_SLEEPING ? "sleeping" : + child->afpch_state == DSI_EXTSLEEP ? "sleeping" : + child->afpch_state == DSI_DISCONNECTED ? "disconnected" : + "unknown", + child->afpch_volumes ? child->afpch_volumes : "-"); + } + child = child->afpch_next; + } + } + names[i] = NULL; + *ret = names; + + afpstats_unlock_childs(); + + return TRUE; +} diff --git a/etc/afpd/afpstats_obj.h b/etc/afpd/afpstats_obj.h new file mode 100644 index 00000000..9d830006 --- /dev/null +++ b/etc/afpd/afpstats_obj.h @@ -0,0 +1,19 @@ +#ifndef AFPSTATS_OBJ_H +#define AFPSTATS_OBJ_H + +#include + +typedef struct AFPStatsObj AFPStatsObj; +typedef struct AFPStatsObjClass AFPStatsObjClass; + +GType afpstats_obj_get_type(void); +gboolean afpstats_obj_get_users(AFPStatsObj *obj, gchar ***ret, GError **error); + +#define AFPSTATS_TYPE_OBJECT (afpstats_obj_get_type ()) +#define AFPSTATS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST((object), AFPSTATS_TYPE_OBJECT, AFPStatsObj)) +#define AFPSTATS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), AFPSTATS_TYPE_OBJECT, AFPStatsObjClass)) +#define AFPSTATS_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), AFPSTATS_TYPE_OBJECT)) +#define AFPSTATS_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), AFPSTATS_TYPE_OBJECT)) +#define AFPSTATS_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), AFPSTATS_TYPE_OBJECT, AFPStatsObjClass)) + +#endif /* AFPSTATS_OBJ_H */ diff --git a/etc/afpd/afpstats_service_glue.h b/etc/afpd/afpstats_service_glue.h new file mode 100644 index 00000000..65081c46 --- /dev/null +++ b/etc/afpd/afpstats_service_glue.h @@ -0,0 +1,121 @@ +/* Generated by dbus-binding-tool; do not edit! */ + + +#ifndef __dbus_glib_marshal_afpstats_obj_MARSHAL_H__ +#define __dbus_glib_marshal_afpstats_obj_MARSHAL_H__ + +#include + +G_BEGIN_DECLS + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#define g_marshal_value_peek_variant(v) g_value_get_variant (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_long +#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* BOOLEAN:POINTER,POINTER */ +extern void dbus_glib_marshal_afpstats_obj_BOOLEAN__POINTER_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); +void +dbus_glib_marshal_afpstats_obj_BOOLEAN__POINTER_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_BOOLEAN__POINTER_POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_pointer (param_values + 1), + g_marshal_value_peek_pointer (param_values + 2), + data2); + + g_value_set_boolean (return_value, v_return); +} + +G_END_DECLS + +#endif /* __dbus_glib_marshal_afpstats_obj_MARSHAL_H__ */ + +#include +static const DBusGMethodInfo dbus_glib_afpstats_obj_methods[] = { + { (GCallback) afpstats_obj_get_users, dbus_glib_marshal_afpstats_obj_BOOLEAN__POINTER_POINTER, 0 }, +}; + +const DBusGObjectInfo dbus_glib_afpstats_obj_object_info = { 1, + dbus_glib_afpstats_obj_methods, + 1, +"org.netatalk.AFPStats\0GetUsers\0S\0ret\0O\0F\0N\0as\0\0\0", +"\0", +"\0" +}; + diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index 5246d436..fa60b192 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -375,6 +375,7 @@ int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen if (dsi->flags & DSI_EXTSLEEP) { LOG(log_note, logtype_afpd, "afp_zzz: waking up from extended sleep"); dsi->flags &= ~(DSI_SLEEPING | DSI_EXTSLEEP); + ipc_child_state(obj, DSI_RUNNING); } } else { /* sleep request */ @@ -382,8 +383,10 @@ int afp_zzz(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen if (data & AFPZZZ_EXT_SLEEP) { LOG(log_note, logtype_afpd, "afp_zzz: entering extended sleep"); dsi->flags |= DSI_EXTSLEEP; + ipc_child_state(obj, DSI_EXTSLEEP); } else { LOG(log_note, logtype_afpd, "afp_zzz: entering normal sleep"); + ipc_child_state(obj, DSI_SLEEPING); } } diff --git a/etc/afpd/main.c b/etc/afpd/main.c index a66e4a86..22650479 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -38,6 +38,7 @@ #include "fork.h" #include "uam_auth.h" #include "afp_zeroconf.h" +#include "afpstats.h" #define AFP_LISTENERS 32 #define FDSET_SAFETY 5 @@ -326,6 +327,11 @@ int main(int ac, char **av) /* set limits */ (void)setlimits(); +#ifdef HAVE_DBUS_GLIB + /* Run dbus AFP statics thread */ + (void)afpstats_init(server_children); +#endif + afp_child_t *child; int recon_ipc_fd; pid_t pid; diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 9c7eb2bd..f5122373 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef CNID_DB #include @@ -659,6 +660,31 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume) return (!volume->v_cdb)?-1:0; } +/* + * Send list of open volumes to afpd master via IPC + */ +static void server_ipc_volumes(AFPObj *obj) +{ + struct vol *volume, *vols; + volume = vols = getvolumes(); + bstring openvolnames = bfromcstr(""); + bool firstvol = true; + + while (volume) { + if (volume->v_flags & AFPVOL_OPEN) { + if (!firstvol) + bcatcstr(openvolnames, ", "); + else + firstvol = false; + bcatcstr(openvolnames, volume->v_localname); + } + volume = volume->v_next; + } + + ipc_child_write(obj->ipc_fd, IPC_VOLUMES, blength(openvolnames), bdata(openvolnames)); + bdestroy(openvolnames); +} + /* ------------------------- * we are the user here */ @@ -834,6 +860,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t setmessage(msg); free(vol_mname); + server_ipc_volumes(obj); return( AFP_OK ); } @@ -906,6 +933,7 @@ int afp_closevol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, si (void)chdir("/"); curdir = NULL; closevol(obj, vol); + server_ipc_volumes(obj); return( AFP_OK ); } diff --git a/include/atalk/dsi.h b/include/atalk/dsi.h index 4197dba5..fc1af468 100644 --- a/include/atalk/dsi.h +++ b/include/atalk/dsi.h @@ -154,9 +154,6 @@ typedef struct DSI { #define DSI_RECONSOCKET (1 << 7) /* we have a new socket from primary reconnect */ #define DSI_RECONINPROG (1 << 8) /* used in the new session in reconnect */ #define DSI_AFP_LOGGED_OUT (1 << 9) /* client called afp_logout, quit on next EOF from socket */ -#if 0 -#define DSI_GOT_ECONNRESET (1 << 10) /* got ECONNRESET from client => exit */ -#endif /* basic initialization: dsi_init.c */ extern DSI *dsi_init(AFPObj *obj, const char *hostname, const char *address, const char *port); diff --git a/include/atalk/server_child.h b/include/atalk/server_child.h index 6f8f18a0..5e694018 100644 --- a/include/atalk/server_child.h +++ b/include/atalk/server_child.h @@ -20,10 +20,13 @@ typedef struct afp_child { uid_t afpch_uid; /* user id of connected client (from the worker afpd process) */ int afpch_valid; /* 1 if we have a clientid */ int afpch_killed; /* 1 if we already tried to kill the client */ - uint32_t afpch_time; /* client boot time (from the mac client) */ + uint32_t afpch_boottime; /* client boot time (from the mac client) */ + time_t afpch_logintime; /* time the child was added */ uint32_t afpch_idlen; /* clientid len (from the Mac client) */ char *afpch_clientid; /* clientid (from the Mac client) */ int afpch_ipc_fd; /* socket for IPC bw afpd parent and childs */ + int16_t afpch_state; /* state of AFP session (eg active, sleeping, disconnected) */ + char *afpch_volumes; /* mounted volumes */ struct afp_child **afpch_prevp; struct afp_child *afpch_next; } afp_child_t; @@ -34,7 +37,6 @@ typedef struct { int servch_count; /* Current count of active AFP sessions */ int servch_nsessions; /* Number of allowed AFP sessions */ afp_child_t *servch_table[CHILD_HASHSIZE]; /* Hashtable with data of AFP sesssions */ - void (*servch_cleanup)(const pid_t); /* Cleanup handler */ } server_child_t; /* server_child.c */ @@ -42,6 +44,7 @@ extern server_child_t *server_child_alloc(int); extern afp_child_t *server_child_add(server_child_t *, pid_t, int ipc_fd); extern int server_child_remove(server_child_t *, pid_t); extern void server_child_free(server_child_t *); +extern afp_child_t *server_child_resolve(server_child_t *childs, id_t pid); extern void server_child_kill(server_child_t *, int); extern void server_child_kill_one_by_id(server_child_t *children, pid_t pid, uid_t, diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h index 0765c73c..50eb7edc 100644 --- a/include/atalk/server_ipc.h +++ b/include/atalk/server_ipc.h @@ -6,8 +6,11 @@ #define IPC_DISCOLDSESSION 0 #define IPC_GETSESSION 1 +#define IPC_STATE 2 /* pass AFP session state */ +#define IPC_VOLUMES 3 /* pass list of open volumes */ extern int ipc_server_read(server_child_t *children, int fd); extern int ipc_child_write(int fd, uint16_t command, int len, void *token); +extern int ipc_child_state(AFPObj *obj, uint16_t state); #endif /* IPC_GETSESSION_LOGIN */ diff --git a/libatalk/dsi/dsi_stream.c b/libatalk/dsi/dsi_stream.c index 711a037b..6c502b0b 100644 --- a/libatalk/dsi/dsi_stream.c +++ b/libatalk/dsi/dsi_stream.c @@ -471,10 +471,6 @@ size_t dsi_stream_read(DSI *dsi, void *data, const size_t length) stored += len; } else { /* eof or error */ /* don't log EOF error if it's just after connect (OSX 10.3 probe) */ -#if 0 - if (errno == ECONNRESET) - dsi->flags |= DSI_GOT_ECONNRESET; -#endif if (len || stored || dsi->read_count) { if (! (dsi->flags & DSI_DISCONNECTED)) { LOG(log_error, logtype_dsi, "dsi_stream_read: len:%d, %s", diff --git a/libatalk/util/server_child.c b/libatalk/util/server_child.c index 6c86f483..da78c6a0 100644 --- a/libatalk/util/server_child.c +++ b/libatalk/util/server_child.c @@ -70,11 +70,11 @@ static inline void unhash_child(afp_child_t *child) } } -static afp_child_t *resolve_child(afp_child_t **table, pid_t pid) +afp_child_t *server_child_resolve(server_child_t *childs, id_t pid) { afp_child_t *child; - for (child = table[HASH(pid)]; child; child = child->afpch_next) { + for (child = childs->servch_table[HASH(pid)]; child; child = child->afpch_next) { if (child->afpch_pid == pid) break; } @@ -113,7 +113,7 @@ afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd) } /* if we already have an entry. just return. */ - if ((child = resolve_child(children->servch_table, pid))) + if ((child = server_child_resolve(children, pid))) goto exit; if ((child = calloc(1, sizeof(afp_child_t))) == NULL) @@ -121,6 +121,7 @@ afp_child_t *server_child_add(server_child_t *children, pid_t pid, int ipc_fd) child->afpch_pid = pid; child->afpch_ipc_fd = ipc_fd; + child->afpch_logintime = time(NULL); hash_child(children->servch_table, child); children->servch_count++; @@ -136,9 +137,11 @@ int server_child_remove(server_child_t *children, pid_t pid) int fd; afp_child_t *child; - if (!(child = resolve_child(children->servch_table, pid))) + if (!(child = server_child_resolve(children, pid))) return -1; + pthread_mutex_lock(&children->servch_lock); + unhash_child(child); if (child->afpch_clientid) { free(child->afpch_clientid); @@ -153,8 +156,7 @@ int server_child_remove(server_child_t *children, pid_t pid) free(child); children->servch_count--; - if (children->servch_cleanup) - children->servch_cleanup(pid); + pthread_mutex_unlock(&children->servch_lock); return fd; } @@ -173,6 +175,8 @@ void server_child_free(server_child_t *children) close(child->afpch_ipc_fd); if (child->afpch_clientid) free(child->afpch_clientid); + if (child->afpch_volumes) + free(child->afpch_volumes); free(child); child = tmp; } @@ -225,7 +229,7 @@ int server_child_transfer_session(server_child_t *children, EC_INIT; afp_child_t *child; - if ((child = resolve_child(children->servch_table, pid)) == NULL) { + if ((child = server_child_resolve(children, pid)) == NULL) { LOG(log_note, logtype_default, "Reconnect: no child[%u]", pid); if (kill(pid, 0) == 0) { LOG(log_note, logtype_default, "Reconnect: terminating old session[%u]", pid); @@ -274,13 +278,15 @@ void server_child_kill_one_by_id(server_child_t *children, pid_t pid, afp_child_t *child, *tmp; int i; + pthread_mutex_lock(&children->servch_lock); + for (i = 0; i < CHILD_HASHSIZE; i++) { child = children->servch_table[i]; while (child) { tmp = child->afpch_next; if (child->afpch_pid != pid) { if (child->afpch_idlen == idlen && memcmp(child->afpch_clientid, id, idlen) == 0) { - if ( child->afpch_time != boottime ) { + if ( child->afpch_boottime != boottime ) { /* Client rebooted */ if (uid == child->afpch_uid) { kill_child(child); @@ -299,7 +305,7 @@ void server_child_kill_one_by_id(server_child_t *children, pid_t pid, } } else { /* update childs own slot */ - child->afpch_time = boottime; + child->afpch_boottime = boottime; if (child->afpch_clientid) free(child->afpch_clientid); LOG(log_debug, logtype_default, "Setting client ID for %u", child->afpch_pid); @@ -311,6 +317,8 @@ void server_child_kill_one_by_id(server_child_t *children, pid_t pid, child = tmp; } } + + pthread_mutex_unlock(&children->servch_lock); } /* --------------------------- diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c index 838cece7..fa1778e9 100644 --- a/libatalk/util/server_ipc.c +++ b/libatalk/util/server_ipc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -104,6 +105,45 @@ static int ipc_get_session(struct ipc_header *ipc, server_child_t *children) return 0; } +static int ipc_set_state(struct ipc_header *ipc, server_child_t *children) +{ + EC_INIT; + afp_child_t *child; + + pthread_mutex_lock(&children->servch_lock); + + if ((child = server_child_resolve(children, ipc->child_pid)) == NULL) + EC_FAIL; + + memcpy(&child->afpch_state, ipc->msg, sizeof(uint16_t)); + +EC_CLEANUP: + pthread_mutex_unlock(&children->servch_lock); + EC_EXIT; +} + +static int ipc_set_volumes(struct ipc_header *ipc, server_child_t *children) +{ + EC_INIT; + afp_child_t *child; + + pthread_mutex_lock(&children->servch_lock); + + if ((child = server_child_resolve(children, ipc->child_pid)) == NULL) + EC_FAIL; + + if (child->afpch_volumes) { + free(child->afpch_volumes); + child->afpch_volumes = NULL; + } + if (ipc->len) + child->afpch_volumes = strdup(ipc->msg); + +EC_CLEANUP: + pthread_mutex_unlock(&children->servch_lock); + EC_EXIT; +} + /*********************************************************************************** * Public functions ***********************************************************************************/ @@ -201,6 +241,16 @@ int ipc_server_read(server_child_t *children, int fd) return -1; break; + case IPC_STATE: + if (ipc_set_state(&ipc, children) != 0) + return -1; + break; + + case IPC_VOLUMES: + if (ipc_set_volumes(&ipc, children) != 0) + return -1; + break; + default: LOG (log_info, logtype_afpd, "ipc_read: unknown command: %d", ipc.command); return -1; @@ -252,3 +302,8 @@ int ipc_child_write(int fd, uint16_t command, int len, void *msg) return 0; } + +int ipc_child_state(AFPObj *obj, uint16_t state) +{ + return ipc_child_write(obj->ipc_fd, IPC_STATE, sizeof(uint16_t), &state); +} diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index 72cbaebd..b0f3d8e2 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -1,5 +1,29 @@ dnl Kitchen sink for configuration macros +dnl Check for dbus-glib, for AFP stats +AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ + PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no) + PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.6, have_dbus_glib=yes, have_dbus_glib=no) + AC_SUBST(DBUS_CFLAGS) + AC_SUBST(DBUS_LIBS) + AC_SUBST(DBUS_GLIB_CFLAGS) + AC_SUBST(DBUS_GLIB_LIBS) + AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$have_dbus_glib = xyes -a x$have_dbus = xyes) + + AC_ARG_WITH( + dbus-sysconf-dir, + [AS_HELP_STRING([--with-dbus-sysconf-dir],[Path to dbus system bus security configuration directory (default: ${sysconfdir}/dbus-1/system.d/)])], + ac_cv_dbus_sysdir=$withval, + ac_cv_dbus_sysdir='${sysconfdir}/dbus-1/system.d' + ) + + if test x$have_dbus_glib = xyes -a x$have_dbus = xyes ; then + AC_DEFINE(HAVE_DBUS_GLIB, 1, [Define if support for dbus-glib was found]) + DBUS_SYS_DIR="$ac_cv_dbus_sysdir" + AC_SUBST(DBUS_SYS_DIR) + fi +]) + dnl Whether to enable developer build AC_DEFUN([AC_DEVELOPER], [ AC_MSG_CHECKING([whether to enable developer build]) diff --git a/macros/pam-check.m4 b/macros/pam-check.m4 index 17a92898..26d14b85 100644 --- a/macros/pam-check.m4 +++ b/macros/pam-check.m4 @@ -138,6 +138,13 @@ AC_DEFUN([AC_NETATALK_PATH_PAM], [ AC_DEFINE(USE_PAM, 1, [Define to enable PAM support]) fi + AC_ARG_WITH( + pam-confdir, + [AS_HELP_STRING([--with-pam-confdir=PATH],[Path to PAM config dir (default: $sysconfdir/pam.d)])], + PAMDIR=$withval, + PAMDIR='${sysconfdir}/pam.d' + ) + LIB_REMOVE_USR_LIB(PAM_LIBS) CFLAGS_REMOVE_USR_INCLUDE(PAM_CFLAGS) AC_SUBST(PAMDIR) diff --git a/macros/summary.m4 b/macros/summary.m4 index f4d99863..460efc66 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -55,6 +55,8 @@ dnl AC_MSG_RESULT([ Samba sharemode interop: $neta_cv_have_smbshmd]) AC_MSG_RESULT([ ACL support: $with_acl_support]) AC_MSG_RESULT([ Kerberos support: $with_kerberos]) AC_MSG_RESULT([ LDAP support: $netatalk_cv_ldap]) + AC_MSG_RESULT([ dbus support: $have_dbus_glib]) + AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir]) if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then AC_MSG_RESULT([]) AC_MSG_WARN([ PAM support was configured for your system, but the netatalk PAM configuration file]) From dfae8b42d7696b7a845ae9ac8198656d288f05f3 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 11 Feb 2013 14:42:12 +0100 Subject: [PATCH 33/67] Add dtrace provider 'afp' and dtrace probes There are three dtrace probes: - all AFP functions, passing the function name as argument - AFP read and write, passing the IO size as argument - all CNID functions In order to be able to simply differintiate between disk IO and network IO, replace all occurences of read and write on sockets with send/recv, and replace the use of writev in the logging code with two calls to write. As a result, using dtrace probes for read() and write() syscalls can be used to gather metrics for disk IO, while probing send(), recv() and writev() probe network IO. --- Makefile.am | 4 +-- NEWS | 2 ++ configure.ac | 11 +++++--- etc/afpd/Makefile.am | 10 +++++++ etc/afpd/afp_dsi.c | 6 +++++ etc/afpd/appl.c | 6 ++++- etc/afpd/catsearch.c | 19 +++++++++----- etc/afpd/directory.c | 23 +++++++++++----- etc/afpd/enumerate.c | 7 ++++- etc/afpd/file.c | 54 +++++++++++++++++++++++++++++++------- etc/afpd/filedir.c | 14 ++++++++-- etc/afpd/fork.c | 7 +++++ include/atalk/.gitignore | 2 +- include/atalk/Makefile.am | 13 ++++++++- include/atalk/afp_dtrace.d | 10 +++++++ include/atalk/globals.h | 13 +++++++++ libatalk/dsi/dsi_stream.c | 4 +-- libatalk/util/logger.c | 7 ++--- libatalk/util/socket.c | 2 +- macros/netatalk.m4 | 33 +++++++++++++++++++++++ macros/summary.m4 | 1 + test/afpd/Makefile.am | 9 +++++++ 22 files changed, 214 insertions(+), 43 deletions(-) create mode 100644 include/atalk/afp_dtrace.d diff --git a/Makefile.am b/Makefile.am index 01005985..36a8c3cd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,9 +1,9 @@ # Makefile.am for top level of netatalk package if USE_BUILTIN_LIBEVENT -SUBDIRS = libevent libatalk bin config etc man contrib distrib include doc macros test +SUBDIRS = libevent include libatalk bin config etc man contrib distrib doc macros test else -SUBDIRS = libatalk bin config etc man contrib distrib include doc macros test +SUBDIRS = include libatalk bin config etc man contrib distrib doc macros test endif EXTRA_DIST = CONTRIBUTORS COPYRIGHT COPYING NEWS VERSION diff --git a/NEWS b/NEWS index df015fa5..c0ec3619 100644 --- a/NEWS +++ b/NEWS @@ -19,6 +19,8 @@ Changes in 3.0.3 program `afpstats`. Requires dbus, dbus-glib any python-dbus. configure option --dbus-sysconf-dir for specifying dbus system security configuration files. +* NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available + probes. Changes in 3.0.2 ================ diff --git a/configure.ac b/configure.ac index 88f81aaf..566df4f4 100644 --- a/configure.ac +++ b/configure.ac @@ -183,16 +183,19 @@ AC_NETATALK_LIBEVENT dnl libatalk API checks AC_DEVELOPER +dnl Check for dtrace +AC_NETATALK_DTRACE + +dnl Check for dbus-glib, for AFP stats on dbus +AC_NETATALK_DBUS_GLIB + dnl FHS stuff has to be done last because it overrides other defaults AC_NETATALK_FHS dnl netatalk lockfile path, must come after AC_NETATALK_FHS AC_NETATALK_LOCKFILE -dnl Check for dbus-glib, for AFP stats on dbus -AC_NETATALK_DBUS_GLIB - -CFLAGS="-I\$(top_srcdir)/include -I\$(top_srcdir)/sys $CFLAGS" +CFLAGS="-I\$(top_srcdir)/include -I\$(top_builddir)/include $CFLAGS" UAMS_PATH="${uams_path}" AC_SUBST(LIBS) diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index 1612344a..335f4293 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -46,6 +46,7 @@ afpd_SOURCES = \ unix.c \ volume.c + afpd_LDADD = \ $(top_builddir)/libatalk/libatalk.la \ @LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@ @@ -83,6 +84,15 @@ afpd_CFLAGS += $(DBUS_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION afpd_LDFLAGS += $(DBUS_LIBS) $(DBUS_GLIB_LIBS) -ldbus-glib-1 endif +if WITH_DTRACE +DTRACE_OBJ = afpd-afp_dsi.o afpd-fork.o afpd-appl.o afpd-catsearch.o afpd-directory.o afpd-enumerate.o afpd-file.o afpd-filedir.o +afp_dtrace.o: $(top_srcdir)/include/atalk/afp_dtrace.d $(DTRACE_OBJ) + if test -f afp_dtrace.o ; then rm -f afp_dtrace.o ; fi + $(LIBTOOL) --mode=execute dtrace -G -s $(top_srcdir)/include/atalk/afp_dtrace.d -o afp_dtrace.o $(DTRACE_OBJ) +afpd_LDADD += afp_dtrace.o @DTRACE_LIBS@ +CLEANFILES += afp_dtrace.o +endif + noinst_HEADERS = auth.h afp_config.h desktop.h directory.h fce_api_internal.h file.h \ filedir.h fork.h icon.h mangle.h misc.h status.h switch.h \ uam_auth.h uid.h unix.h volume.h hash.h acls.h acl_mappings.h extattrs.h \ diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index 646e8d12..5082ee70 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -603,10 +603,12 @@ void afp_over_dsi(AFPObj *obj) LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function)); + AFP_AFPFUNC_START(function, (char *)AfpNum2name(function)); err = (*afp_switch[function])(obj, (char *)dsi->commands, dsi->cmdlen, (char *)&dsi->data, &dsi->datalen); + AFP_AFPFUNC_DONE(function, (char *)AfpNum2name(function)); LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s", AfpNum2name(function), AfpErr2name(err)); @@ -644,10 +646,14 @@ void afp_over_dsi(AFPObj *obj) LOG(log_debug, logtype_afpd, "<== Start AFP command: %s", AfpNum2name(function)); + AFP_AFPFUNC_START(function, (char *)AfpNum2name(function)); + err = (*afp_switch[function])(obj, (char *)dsi->commands, dsi->cmdlen, (char *)&dsi->data, &dsi->datalen); + AFP_AFPFUNC_DONE(function, (char *)AfpNum2name(function)); + LOG(log_debug, logtype_afpd, "==> Finished AFP command: %s -> %s", AfpNum2name(function), AfpErr2name(err)); diff --git a/etc/afpd/appl.c b/etc/afpd/appl.c index 04dd92d6..f53803e0 100644 --- a/etc/afpd/appl.c +++ b/etc/afpd/appl.c @@ -170,7 +170,11 @@ makemacpath(const struct vol *vol, char *mpath, int mpathlen, struct dir *dir, c } /* next part */ - if ((uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL ) { + AFP_CNID_START("cnid_resolve"); + uname = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen); + AFP_CNID_DONE(); + + if (uname == NULL) { afp_errno = AFPERR_NOOBJ; ret = NULL; goto exit; diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c index 9ffea6e2..63a9607c 100644 --- a/etc/afpd/catsearch.c +++ b/etc/afpd/catsearch.c @@ -743,11 +743,14 @@ static int catsearch_db(const AFPObj *obj, LOG(log_debug, logtype_afpd, "catsearch_db: %s", buffer); - if ((num_matches = cnid_find(vol->v_cdb, - buffer, - strlen(uname), - resbuf, - sizeof(resbuf))) == -1) { + AFP_CNID_START("cnid_find"); + num_matches = cnid_find(vol->v_cdb, + buffer, + strlen(uname), + resbuf, + sizeof(resbuf)); + AFP_CNID_DONE(); + if (num_matches == -1) { result = AFPERR_MISC; goto catsearch_end; } @@ -763,8 +766,12 @@ static int catsearch_db(const AFPObj *obj, memcpy(&cnid, resbuf + cur_pos * sizeof(cnid_t), sizeof(cnid_t)); did = cnid; - if ((name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1)) == NULL) + AFP_CNID_START("cnid_resolve"); + name = cnid_resolve(vol->v_cdb, &did, resolvebuf, 12 + MAXPATHLEN + 1); + AFP_CNID_DONE(); + if (name == NULL) goto next; + LOG(log_debug, logtype_afpd, "catsearch_db: {pos: %u, name:%s, cnid: %u}", cur_pos, name, ntohl(cnid)); if ((dir = dirlookup(vol, did)) == NULL) diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index eb1cdf58..d58023e2 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -497,12 +497,15 @@ struct dir *dirlookup_bypath(const struct vol *vol, const char *path) cfrombstr(l->entry[i]), blength(l->entry[i]))) == NULL) { - if ((cnid = cnid_add(vol->v_cdb, /* 6. */ - &st, - did, - cfrombstr(l->entry[i]), - blength(l->entry[i]), - 0)) == CNID_INVALID) + AFP_CNID_START("cnid_add"); + cnid = cnid_add(vol->v_cdb, /* 6. */ + &st, + did, + cfrombstr(l->entry[i]), + blength(l->entry[i]), + 0); + AFP_CNID_DONE(); + if (cnid == CNID_INVALID) EC_FAIL; if ((dir = dirlookup(vol, cnid)) == NULL) /* 7. */ @@ -607,7 +610,11 @@ struct dir *dirlookup(const struct vol *vol, cnid_t did) /* Get it from the database */ cnid = did; LOG(log_debug, logtype_afpd, "dirlookup(did: %u): querying CNID database", ntohl(did)); - if ((upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen)) == NULL) { + + AFP_CNID_START("cnid_resolve"); + upath = cnid_resolve(vol->v_cdb, &cnid, buffer, buflen); + AFP_CNID_DONE(); + if (upath == NULL) { afp_errno = AFPERR_NOOBJ; err = 1; goto exit; @@ -2329,7 +2336,9 @@ int deletecurdir(struct vol *vol) err = netatalk_rmdir_all_errors(-1, cfrombstr(fdir->d_u_name)); if ( err == AFP_OK || err == AFPERR_NOOBJ) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, fdir->d_did); + AFP_CNID_DONE(); dir_remove( vol, fdir ); } else { LOG(log_error, logtype_afpd, "deletecurdir(\"%s\"): netatalk_rmdir_all_errors error", diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c index 5f0e1644..340f79ae 100644 --- a/etc/afpd/enumerate.c +++ b/etc/afpd/enumerate.c @@ -365,9 +365,14 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, if (ad_convert(sd.sd_last, &s_path.st, vol, &convname) == 0) { if (convname) { s_path.u_name = (char *)convname; + AFP_CNID_START("cnid_lookup"); s_path.id = cnid_lookup(vol->v_cdb, &s_path.st, curdir->d_did, sd.sd_last, strlen(sd.sd_last)); + AFP_CNID_DONE(); if (s_path.id != CNID_INVALID) { - if (cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)) != 0) + AFP_CNID_START("cnid_update"); + int cnid_up_ret = cnid_update(vol->v_cdb, s_path.id, &s_path.st, curdir->d_did, (char *)convname, strlen(convname)); + AFP_CNID_DONE(); + if (cnid_up_ret != 0) LOG(log_error, logtype_afpd, "enumerate: error updating CNID of \"%s\"", fullpathname(convname)); } } diff --git a/etc/afpd/file.c b/etc/afpd/file.c index e7859659..bd516087 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -219,7 +219,10 @@ uint32_t get_id(struct vol *vol, catching moved files */ adcnid = ad_getid(adp, st->st_dev, st->st_ino, 0, vol->v_stamp); /* (1) */ + AFP_CNID_START("cnid_add"); dbcnid = cnid_add(vol->v_cdb, st, did, upath, len, adcnid); /* (2) */ + AFP_CNID_DONE(); + /* Throw errors if cnid_add fails. */ if (dbcnid == CNID_INVALID) { switch (errno) { @@ -1602,8 +1605,15 @@ int deletefile(const struct vol *vol, int dirfd, char *file, int checkAttrib) err = AFPERR_BUSY; } else if (!(err = vol->vfs->vfs_deletefile(vol, dirfd, file)) && !(err = netatalk_unlinkat(dirfd, file )) ) { cnid_t id; - if (checkAttrib && (id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)))) { - cnid_delete(vol->v_cdb, id); + if (checkAttrib) { + AFP_CNID_START("cnid_get"); + id = cnid_get(vol->v_cdb, curdir->d_did, file, strlen(file)); + AFP_CNID_DONE(); + if (id) { + AFP_CNID_START("cnid_delete"); + cnid_delete(vol->v_cdb, id); + AFP_CNID_DONE(); + } } } @@ -1676,7 +1686,10 @@ int afp_createid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si return AFPERR_PARAM; } st = &s_path->st; - if ((id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)))) { + AFP_CNID_START("cnid_lookup"); + id = cnid_lookup(vol->v_cdb, st, did, upath, len = strlen(upath)); + AFP_CNID_DONE(); + if (id) { memcpy(rbuf, &id, sizeof(id)); *rbuflen = sizeof(id); return AFPERR_EXISTID; @@ -1709,7 +1722,9 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data) return 0; /* update or add to cnid */ + AFP_CNID_START("cnid_add"); aint = cnid_add(vol->v_cdb, &path.st, did, de->d_name, strlen(de->d_name), 0); /* ignore errors */ + AFP_CNID_DONE(); return 0; } @@ -1788,7 +1803,10 @@ int afp_resolveid(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_ return AFPERR_NOID; } retry: - if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { + AFP_CNID_START("cnid_resolve"); + upath = cnid_resolve(vol->v_cdb, &id, buffer, len); + AFP_CNID_DONE(); + if (upath == NULL) { return AFPERR_NOID; /* was AFPERR_BADID, but help older Macs */ } @@ -1891,7 +1909,10 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ ibuf += sizeof(id); fileid = id; - if (NULL == (upath = cnid_resolve(vol->v_cdb, &id, buffer, len)) ) { + AFP_CNID_START("cnid_resolve"); + upath = cnid_resolve(vol->v_cdb, &id, buffer, len); + AFP_CNID_DONE(); + if (upath == NULL) { return AFPERR_NOID; } @@ -1924,7 +1945,9 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ return AFPERR_BADTYPE; delete: + AFP_CNID_START("cnid_delete"); if (cnid_delete(vol->v_cdb, fileid)) { + AFP_CNID_DONE(); switch (errno) { case EROFS: return AFPERR_VLOCK; @@ -1935,7 +1958,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ return AFPERR_PARAM; } } - + AFP_CNID_DONE(); return err; } @@ -2063,7 +2086,9 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* look for the source cnid. if it doesn't exist, don't worry about * it. */ + AFP_CNID_START("cnid_lookup"); sid = cnid_lookup(vol->v_cdb, &srcst, sdir->d_did, supath,slen = strlen(supath)); + AFP_CNID_DONE(); if (NULL == ( dir = dirlookup( vol, did )) ) { err = afp_errno; /* was AFPERR_PARAM */ @@ -2106,7 +2131,9 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U /* look for destination id. */ upath = path->u_name; + AFP_CNID_START("cnid_lookup"); did = cnid_lookup(vol->v_cdb, &destst, curdir->d_did, upath, dlen = strlen(upath)); + AFP_CNID_DONE(); /* construct a temp name. * NOTE: the temp file will be in the dest file's directory. it @@ -2140,13 +2167,20 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U goto err_dest_to_src; of_rename(vol, s_of, curdir, temp, curdir, path->m_name); - /* id's need switching. src -> dest and dest -> src. + /* + * id's need switching. src -> dest and dest -> src. * we need to re-stat() if it was a cross device copy. - */ - if (sid) + */ + if (sid) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, sid); - if (did) + AFP_CNID_DONE(); + } + if (did) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, did); + AFP_CNID_DONE(); + } if ((did && ( (crossdev && ostat(upath, &srcst, vol_syml_opt(vol)) < 0) || cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0)) diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 5a23f28e..c349f532 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -248,7 +248,9 @@ static int moveandrename(struct vol *vol, if (!isdir) { if ((oldunixname = strdup(mtoupath(vol, oldname, sdir->d_did, utf8_encoding(vol->v_obj)))) == NULL) return AFPERR_PARAM; /* can't convert */ + AFP_CNID_START("cnid_get"); id = cnid_get(vol->v_cdb, sdir->d_did, oldunixname, strlen(oldunixname)); + AFP_CNID_DONE(); #ifndef HAVE_ATFUNCS /* Need full path */ @@ -378,7 +380,9 @@ static int moveandrename(struct vol *vol, } /* fix up the catalog entry */ + AFP_CNID_START("cnid_update"); cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath)); + AFP_CNID_DONE(); } exit: @@ -521,10 +525,16 @@ int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size delcnid = deldir->d_did; dir_remove(vol, deldir); } - if (delcnid == CNID_INVALID) + if (delcnid == CNID_INVALID) { + AFP_CNID_START("cnid_get"); delcnid = cnid_get(vol->v_cdb, curdir->d_did, upath, strlen(upath)); - if (delcnid != CNID_INVALID) + AFP_CNID_DONE(); + } + if (delcnid != CNID_INVALID) { + AFP_CNID_START("cnid_delete"); cnid_delete(vol->v_cdb, delcnid); + AFP_CNID_DONE(); + } fce_register(FCE_DIR_DELETE, fullpathname(upath), NULL, fce_dir); } else { /* we have to cache this, the structs are lost in deletcurdir*/ diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 7b24b7f2..776d2f63 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -791,6 +791,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si goto afp_read_err; } + AFP_READ_START((long)reqcount); + /* reqcount isn't always truthful. we need to deal with that. */ size = ad_size(ofork->of_ad, eid); @@ -883,6 +885,8 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si afp_read_done: if (obj->options.flags & OPTION_AFP_READ_LOCK) ad_tmplock(ofork->of_ad, eid, ADLOCK_CLR, saveoff, savereqcount, ofork->of_refnum); + + AFP_READ_DONE(); return err; afp_read_err: @@ -1153,6 +1157,8 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s goto afp_write_err; } + AFP_WRITE_START((long)reqcount); + saveoff = offset; if (obj->options.flags & OPTION_AFP_READ_LOCK) { if (ad_tmplock(ofork->of_ad, eid, ADLOCK_WR, saveoff, reqcount, ofork->of_refnum) < 0) { @@ -1227,6 +1233,7 @@ static int write_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, s ofork->of_vol->v_appended += (newsize > oldsize) ? (newsize - oldsize) : 0; *rbuflen = set_off_t (offset, rbuf, is64); + AFP_WRITE_DONE(); return( AFP_OK ); afp_write_err: diff --git a/include/atalk/.gitignore b/include/atalk/.gitignore index 4ee83854..d935e1e6 100644 --- a/include/atalk/.gitignore +++ b/include/atalk/.gitignore @@ -1,4 +1,4 @@ Makefile Makefile.in *.o -lockrpc.gen.h \ No newline at end of file +afp_dtrace.h diff --git a/include/atalk/Makefile.am b/include/atalk/Makefile.am index 93d28929..42085187 100644 --- a/include/atalk/Makefile.am +++ b/include/atalk/Makefile.am @@ -1,6 +1,8 @@ # Makefile.am for include/atalk/ atalkincludedir = $(includedir)/atalk +BUILT_SOURCES = +CLEANFILES = atalkinclude_HEADERS = \ adouble.h \ @@ -40,4 +42,13 @@ noinst_HEADERS = \ ftw.h \ dsi.h \ ldapconfig.h \ - fce_api.h \ No newline at end of file + fce_api.h + +EXTRA_DIST = afp_dtrace.d + +if WITH_DTRACE +BUILT_SOURCES += afp_dtrace.h +CLEANFILES += afp_dtrace.h +afp_dtrace.h: $(top_srcdir)/include/atalk/afp_dtrace.d + $(LIBTOOL) --mode=execute dtrace -o afp_dtrace.h -h -s $(top_srcdir)/include/atalk/afp_dtrace.d +endif diff --git a/include/atalk/afp_dtrace.d b/include/atalk/afp_dtrace.d new file mode 100644 index 00000000..e9ee9893 --- /dev/null +++ b/include/atalk/afp_dtrace.d @@ -0,0 +1,10 @@ +provider afp { + probe afpfunc__start(int func, char *funcname); + probe afpfunc__done(int func, char *funcname); + probe read__start(long size); + probe read__done(); + probe write__start(long size); + probe write__done(); + probe cnid__start(char *cnidfunc); + probe cnid__done(); +}; diff --git a/include/atalk/globals.h b/include/atalk/globals.h index 925f4560..e5fbb292 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -19,6 +19,19 @@ #include #include #include +#ifdef WITH_DTRACE +#include +#else +/* List of empty dtrace macros */ +#define AFP_AFPFUNC_START(a,b) +#define AFP_AFPFUNC_DONE(a, b) +#define AFP_CNID_START(a) +#define AFP_CNID_DONE() +#define AFP_READ_START(a) +#define AFP_READ_DONE() +#define AFP_WRITE_START(a) +#define AFP_WRITE_DONE() +#endif /* #define DOSFILELEN 12 */ /* Type1, DOS-compat*/ #define MACFILELEN 31 /* Type2, HFS-compat */ diff --git a/libatalk/dsi/dsi_stream.c b/libatalk/dsi/dsi_stream.c index 6c502b0b..da58f87c 100644 --- a/libatalk/dsi/dsi_stream.c +++ b/libatalk/dsi/dsi_stream.c @@ -115,7 +115,7 @@ static int dsi_peek(DSI *dsi) if (FD_ISSET(dsi->socket, &readfds)) { len = dsi->end - dsi->eof; /* it's ensured above that there's space */ - if ((len = read(dsi->socket, dsi->eof, len)) <= 0) { + if ((len = recv(dsi->socket, dsi->eof, len, 0)) <= 0) { if (len == 0) { LOG(log_error, logtype_dsi, "dsi_peek: EOF"); return -1; @@ -213,7 +213,7 @@ static size_t dsi_buffered_stream_read(DSI *dsi, uint8_t *data, const size_t len buflen = MIN(8192, dsi->end - dsi->eof); if (buflen > 0) { ssize_t ret; - ret = read(dsi->socket, dsi->eof, buflen); + ret = recv(dsi->socket, dsi->eof, buflen, 0); if (ret > 0) dsi->eof += ret; } diff --git a/libatalk/util/logger.c b/libatalk/util/logger.c index 55630d1b..94423426 100644 --- a/libatalk/util/logger.c +++ b/libatalk/util/logger.c @@ -594,11 +594,8 @@ void make_log_entry(enum loglevels loglevel, enum logtypes logtype, loglevel, logtype); /* If default wasnt setup its fd is -1 */ - iov[0].iov_base = log_details_buffer; - iov[0].iov_len = strlen(log_details_buffer); - iov[1].iov_base = temp_buffer; - iov[1].iov_len = strlen(temp_buffer); - writev( fd, iov, 2); + write(fd, log_details_buffer, strlen(log_details_buffer)); + write(fd, temp_buffer, strlen(temp_buffer)); } else { write(fd, temp_buffer, strlen(temp_buffer)); } diff --git a/libatalk/util/socket.c b/libatalk/util/socket.c index eda69c6c..1df0b96b 100644 --- a/libatalk/util/socket.c +++ b/libatalk/util/socket.c @@ -104,7 +104,7 @@ ssize_t readt(int socket, void *data, const size_t length, int setnonblocking, i end.tv_sec += timeout; while (stored < length) { - len = read(socket, (char *) data + stored, length - stored); + len = recv(socket, (char *) data + stored, length - stored, 0); if (len == -1) { switch (errno) { case EINTR: diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index b0f3d8e2..55c6d9e4 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -1,5 +1,38 @@ dnl Kitchen sink for configuration macros +dnl Check for dtrace +AC_DEFUN([AC_NETATALK_DTRACE], [ + AC_ARG_WITH(dtrace, + AS_HELP_STRING( + [--with-dtrace], + [Enable dtrace probes (default: enabled if dtrace found)] + ), + [WDTRACE=$withval], + [WDTRACE=auto] + ) + if test "x$WDTRACE" = "xyes" -o "x$WDTRACE" = "xauto" ; then + AC_CHECK_PROG([atalk_cv_have_dtrace], [dtrace], [yes], [no]) + if test "x$atalk_cv_have_dtrace" = "xno" ; then + if test "x$WDTRACE" = "xyes" ; then + AC_MSG_FAILURE([dtrace requested but not found]) + fi + WDTRACE="no" + else + WDTRACE="yes" + fi + fi + + if test x"$WDTRACE" = x"yes" ; then + AC_DEFINE([WITH_DTRACE], [1], [dtrace probes]) + DTRACE_LIBS="" + if test x"$this_os" = x"freebsd" ; then + DTRACE_LIBS="-lelf" + fi + AC_SUBST(DTRACE_LIBS) + fi + AM_CONDITIONAL(WITH_DTRACE, test "x$WDTRACE" = "xyes") +]) + dnl Check for dbus-glib, for AFP stats AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no) diff --git a/macros/summary.m4 b/macros/summary.m4 index 460efc66..2b682a46 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -57,6 +57,7 @@ dnl AC_MSG_RESULT([ Samba sharemode interop: $neta_cv_have_smbshmd]) AC_MSG_RESULT([ LDAP support: $netatalk_cv_ldap]) AC_MSG_RESULT([ dbus support: $have_dbus_glib]) AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir]) + AC_MSG_RESULT([ dtrace probes: $WDTRACE]) if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then AC_MSG_RESULT([]) AC_MSG_WARN([ PAM support was configured for your system, but the netatalk PAM configuration file]) diff --git a/test/afpd/Makefile.am b/test/afpd/Makefile.am index 01278ecd..34e28f48 100644 --- a/test/afpd/Makefile.am +++ b/test/afpd/Makefile.am @@ -64,3 +64,12 @@ test_LDADD = \ @LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@ test_LDFLAGS = -export-dynamic + +if WITH_DTRACE +DTRACE_OBJ = test-afp_dsi.o test-fork.o test-appl.o test-catsearch.o test-directory.o test-enumerate.o test-file.o test-filedir.o +afp_dtrace.o: $(top_srcdir)/include/atalk/afp_dtrace.d $(DTRACE_OBJ) + if test -f afp_dtrace.o ; then rm -f afp_dtrace.o ; fi + $(LIBTOOL) --mode=execute dtrace -G -s $(top_srcdir)/include/atalk/afp_dtrace.d -o afp_dtrace.o $(DTRACE_OBJ) +test_LDADD += afp_dtrace.o @DTRACE_LIBS@ +CLEANFILES += afp_dtrace.o +endif From b8131f67b3a0ec21aa2055908ea59fc5559c6f72 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Thu, 21 Feb 2013 14:48:09 +0100 Subject: [PATCH 34/67] Add checking for and linking with libgthread --- etc/afpd/Makefile.am | 4 ++-- macros/netatalk.m4 | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index 335f4293..2e242d95 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -80,8 +80,8 @@ afpstats_service_glue.h: afpstats-service.xml $(top_srcdir)/etc/afpd/afpstats-service.xml afpd_SOURCES += afpstats.c afpstats_obj.c -afpd_CFLAGS += $(DBUS_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION -afpd_LDFLAGS += $(DBUS_LIBS) $(DBUS_GLIB_LIBS) -ldbus-glib-1 +afpd_CFLAGS += $(DBUS_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GTHREAD_CFLAGS) -DDBUS_COMPILATION +afpd_LDFLAGS += $(DBUS_LIBS) $(DBUS_GLIB_LIBS) $(DBUS_GTHREAD_LIBS) -ldbus-glib-1 endif if WITH_DTRACE diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index 55c6d9e4..70ada56c 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -37,10 +37,13 @@ dnl Check for dbus-glib, for AFP stats AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no) PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.6, have_dbus_glib=yes, have_dbus_glib=no) + PKG_CHECK_MODULES(DBUS_GTHREAD, gthread-2.0, have_dbus_gthread=yes, have_dbus_gthread=no) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) AC_SUBST(DBUS_GLIB_CFLAGS) AC_SUBST(DBUS_GLIB_LIBS) + AC_SUBST(DBUS_GTHREAD_CFLAGS) + AC_SUBST(DBUS_GTHREAD_LIBS) AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$have_dbus_glib = xyes -a x$have_dbus = xyes) AC_ARG_WITH( From cc6053806460d7bccfc45ac85529bf696136aba6 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 21 Feb 2013 15:19:02 +0100 Subject: [PATCH 35/67] Reload groups when reloading volumes Reload the user groups every time the volume configuration changes and also to call initgroups() again with the possibly changed groups. FR #71 --- NEWS | 1 + etc/afpd/auth.c | 44 ++--------------------------------- include/atalk/unix.h | 5 +++- libatalk/util/netatalk_conf.c | 15 +++++++++--- libatalk/util/unix.c | 42 +++++++++++++++++++++++++++++++++ 5 files changed, 61 insertions(+), 46 deletions(-) diff --git a/NEWS b/NEWS index c0ec3619..070b773c 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ Changes in 3.0.3 system security configuration files. * NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available probes. +* UPD: Reload groups when reloading volumes. FR #71. Changes in 3.0.2 ================ diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index fa60b192..bec624dc 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -39,6 +39,7 @@ extern void afp_get_cmdline( int *ac, char ***av ); #include #include #include +#include #include "auth.h" #include "uam_auth.h" @@ -210,23 +211,6 @@ static int set_auth_switch(const AFPObj *obj, int expired) return AFP_OK; } -#define GROUPSTR_BUFSIZE 1024 -static const char *print_groups(int ngroups, gid_t *groups) -{ - static char groupsstr[GROUPSTR_BUFSIZE]; - int i; - char *s = groupsstr; - - if (ngroups == 0) - return "-"; - - for (i = 0; (i < ngroups) && (s < &groupsstr[GROUPSTR_BUFSIZE]); i++) { - s += snprintf(s, &groupsstr[GROUPSTR_BUFSIZE] - s, " %u", groups[i]); - } - - return groupsstr; -} - static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expired) { #ifdef ADMIN_GRP @@ -241,32 +225,8 @@ static int login(AFPObj *obj, struct passwd *pwd, void (*logout)(void), int expi LOG(log_note, logtype_afpd, "%s Login by %s", afp_versions[afp_version_index].av_name, pwd->pw_name); - if (initgroups( pwd->pw_name, pwd->pw_gid ) < 0) { -#ifdef RUN_AS_USER - LOG(log_info, logtype_afpd, "running with uid %d", geteuid()); -#else /* RUN_AS_USER */ - LOG(log_error, logtype_afpd, "login: %s", strerror(errno)); - return AFPERR_BADUAM; -#endif /* RUN_AS_USER */ - - } - - /* Basically if the user is in the admin group, we stay root */ - - if ((obj->ngroups = getgroups( 0, NULL )) < 0 ) { - LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) ); - return AFPERR_BADUAM; - } - - if ( NULL == (obj->groups = calloc(obj->ngroups, sizeof(gid_t))) ) { - LOG(log_error, logtype_afpd, "login: %s calloc: %d", obj->ngroups); + if (set_groups(obj, pwd) != 0) return AFPERR_BADUAM; - } - - if (( obj->ngroups = getgroups(obj->ngroups, obj->groups )) < 0 ) { - LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno) ); - return AFPERR_BADUAM; - } #ifdef ADMIN_GRP LOG(log_debug, logtype_afpd, "obj->options.admingid == %d", obj->options.admingid); diff --git a/include/atalk/unix.h b/include/atalk/unix.h index d3378ccb..c12bf5bc 100644 --- a/include/atalk/unix.h +++ b/include/atalk/unix.h @@ -23,6 +23,8 @@ #include #include +#include + #define NETATALK_DIOSZ_STACK 65536 #define NETATALK_DIOSZ_HEAP (1024*1024) @@ -48,5 +50,6 @@ extern int copy_ea(const char *ea, int sfd, const char *src, const char *dst, mo extern void become_root(void); extern void unbecome_root(void); extern int gmem(gid_t gid, int ngroups, gid_t *groups); - +extern int set_groups(AFPObj *obj, struct passwd *pwd); +extern const char *print_groups(int ngroups, gid_t *groups); #endif /* ATALK_UNIX_H */ diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 75561245..b51b2a0d 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -1323,6 +1323,9 @@ int load_volumes(AFPObj *obj) LOG(log_debug, logtype_afpd, "load_volumes: BEGIN"); + if (obj->uid) + pwent = getpwuid(obj->uid); + if (Volumes) { if (!volfile_changed(&obj->options)) goto EC_CLEANUP; @@ -1330,6 +1333,15 @@ int load_volumes(AFPObj *obj) for (vol = Volumes; vol; vol = vol->v_next) { vol->v_deleted = 1; } + if (obj->uid) { + become_root(); + ret = set_groups(obj, pwent); + unbecome_root(); + if (ret != 0) { + LOG(log_error, logtype_afpd, "load_volumes: set_groups: %s", strerror(errno)); + EC_FAIL; + } + } } else { LOG(log_debug, logtype_afpd, "load_volumes: no volumes yet"); EC_ZERO_LOG( lstat(obj->options.configfile, &st) ); @@ -1354,9 +1366,6 @@ int load_volumes(AFPObj *obj) break; } - if (obj->uid) - pwent = getpwuid(obj->uid); - if (obj->iniconfig) iniparser_freedict(obj->iniconfig); LOG(log_debug, logtype_afpd, "load_volumes: loading: %s", obj->options.configfile); diff --git a/libatalk/util/unix.c b/libatalk/util/unix.c index 7c80e22d..37bfe140 100644 --- a/libatalk/util/unix.c +++ b/libatalk/util/unix.c @@ -507,3 +507,45 @@ char *strtok_quote(char *s, const char *delim) } return token; } + +int set_groups(AFPObj *obj, struct passwd *pwd) +{ + if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) + LOG(log_error, logtype_afpd, "initgroups(%s, %d): %s", pwd->pw_name, pwd->pw_gid, strerror(errno)); + + if ((obj->ngroups = getgroups(0, NULL)) < 0) { + LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno)); + return -1; + } + + if (obj->groups) + free(obj->groups); + if (NULL == (obj->groups = calloc(obj->ngroups, sizeof(gid_t))) ) { + LOG(log_error, logtype_afpd, "login: %s calloc: %d", obj->ngroups); + return -1; + } + + if ((obj->ngroups = getgroups(obj->ngroups, obj->groups)) < 0 ) { + LOG(log_error, logtype_afpd, "login: %s getgroups: %s", pwd->pw_name, strerror(errno)); + return -1; + } + + return 0; +} + +#define GROUPSTR_BUFSIZE 1024 +const char *print_groups(int ngroups, gid_t *groups) +{ + static char groupsstr[GROUPSTR_BUFSIZE]; + int i; + char *s = groupsstr; + + if (ngroups == 0) + return "-"; + + for (i = 0; (i < ngroups) && (s < &groupsstr[GROUPSTR_BUFSIZE]); i++) { + s += snprintf(s, &groupsstr[GROUPSTR_BUFSIZE] - s, " %u", groups[i]); + } + + return groupsstr; +} From 2a15eb027015d72b88434c862432e932c853c44b Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Fri, 22 Feb 2013 10:53:55 +0100 Subject: [PATCH 36/67] Add a distinct variable for storing result of checks --- macros/netatalk.m4 | 8 ++++++-- macros/summary.m4 | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index 70ada56c..f26f2d9e 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -35,6 +35,7 @@ AC_DEFUN([AC_NETATALK_DTRACE], [ dnl Check for dbus-glib, for AFP stats AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ + atalk_cv_with_dbus=no PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no) PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.6, have_dbus_glib=yes, have_dbus_glib=no) PKG_CHECK_MODULES(DBUS_GTHREAD, gthread-2.0, have_dbus_gthread=yes, have_dbus_gthread=no) @@ -44,7 +45,10 @@ AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ AC_SUBST(DBUS_GLIB_LIBS) AC_SUBST(DBUS_GTHREAD_CFLAGS) AC_SUBST(DBUS_GTHREAD_LIBS) - AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$have_dbus_glib = xyes -a x$have_dbus = xyes) + if test test x$have_dbus_glib = xyes -a x$have_dbus = xyes -a x$have_dbus_gthread = xyes ; then + atalk_cv_with_dbus=yes + fi + AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$atalk_cv_with_dbus = xyes) AC_ARG_WITH( dbus-sysconf-dir, @@ -53,7 +57,7 @@ AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ ac_cv_dbus_sysdir='${sysconfdir}/dbus-1/system.d' ) - if test x$have_dbus_glib = xyes -a x$have_dbus = xyes ; then + if test x$atalk_cv_with_dbus = xyes ; then AC_DEFINE(HAVE_DBUS_GLIB, 1, [Define if support for dbus-glib was found]) DBUS_SYS_DIR="$ac_cv_dbus_sysdir" AC_SUBST(DBUS_SYS_DIR) diff --git a/macros/summary.m4 b/macros/summary.m4 index 2b682a46..59abd693 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -55,7 +55,7 @@ dnl AC_MSG_RESULT([ Samba sharemode interop: $neta_cv_have_smbshmd]) AC_MSG_RESULT([ ACL support: $with_acl_support]) AC_MSG_RESULT([ Kerberos support: $with_kerberos]) AC_MSG_RESULT([ LDAP support: $netatalk_cv_ldap]) - AC_MSG_RESULT([ dbus support: $have_dbus_glib]) + AC_MSG_RESULT([ dbus support: $atalk_cv_with_dbus]) AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir]) AC_MSG_RESULT([ dtrace probes: $WDTRACE]) if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then From 5180f4d273ef05e2cbb387ec958f78d182041b9b Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 22 Feb 2013 12:56:43 +0100 Subject: [PATCH 37/67] Remove duplicated test --- macros/netatalk.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index f26f2d9e..f77233b5 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -45,7 +45,7 @@ AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ AC_SUBST(DBUS_GLIB_LIBS) AC_SUBST(DBUS_GTHREAD_CFLAGS) AC_SUBST(DBUS_GTHREAD_LIBS) - if test test x$have_dbus_glib = xyes -a x$have_dbus = xyes -a x$have_dbus_gthread = xyes ; then + if test x$have_dbus_glib = xyes -a x$have_dbus = xyes -a x$have_dbus_gthread = xyes ; then atalk_cv_with_dbus=yes fi AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$atalk_cv_with_dbus = xyes) From 4624723f612106a5b5a04ccc930188a46ecb492b Mon Sep 17 00:00:00 2001 From: HAT Date: Fri, 22 Feb 2013 23:30:10 +0900 Subject: [PATCH 38/67] configure summary show paths --- macros/pam-check.m4 | 8 +++++--- macros/summary.m4 | 15 ++++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/macros/pam-check.m4 b/macros/pam-check.m4 index 26d14b85..609c92dc 100644 --- a/macros/pam-check.m4 +++ b/macros/pam-check.m4 @@ -140,11 +140,13 @@ AC_DEFUN([AC_NETATALK_PATH_PAM], [ AC_ARG_WITH( pam-confdir, - [AS_HELP_STRING([--with-pam-confdir=PATH],[Path to PAM config dir (default: $sysconfdir/pam.d)])], - PAMDIR=$withval, - PAMDIR='${sysconfdir}/pam.d' + [AS_HELP_STRING([--with-pam-confdir=PATH],[Path to PAM config dir (default: ${sysconfdir}/pam.d)])], + ac_cv_pamdir=$withval, + ac_cv_pamdir='${sysconfdir}/pam.d' ) + PAMDIR="$ac_cv_pamdir" + LIB_REMOVE_USR_LIB(PAM_LIBS) CFLAGS_REMOVE_USR_INCLUDE(PAM_CFLAGS) AC_SUBST(PAMDIR) diff --git a/macros/summary.m4 b/macros/summary.m4 index 59abd693..7f5e6499 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -9,8 +9,6 @@ AC_DEFUN([AC_NETATALK_CONFIG_SUMMARY], [ else AC_MSG_RESULT([ none]) fi - AC_MSG_RESULT([ Netatalk lockfile:]) - AC_MSG_RESULT([ $ac_cv_netatalk_lock]) AC_MSG_RESULT([ AFP:]) AC_MSG_RESULT([ Extended Attributes: $neta_cv_eas]) AC_MSG_RESULT([ ACL support: $with_acl_support]) @@ -56,16 +54,23 @@ dnl AC_MSG_RESULT([ Samba sharemode interop: $neta_cv_have_smbshmd]) AC_MSG_RESULT([ Kerberos support: $with_kerberos]) AC_MSG_RESULT([ LDAP support: $netatalk_cv_ldap]) AC_MSG_RESULT([ dbus support: $atalk_cv_with_dbus]) - AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir]) AC_MSG_RESULT([ dtrace probes: $WDTRACE]) - if test x"$use_pam_so" = x"yes" -a x"$netatalk_cv_install_pam" = x"no"; then + AC_MSG_RESULT([ Paths:]) + AC_MSG_RESULT([ Netatalk lockfile: $ac_cv_netatalk_lock]) + if test x"$atalk_cv_with_dbus" = x"yes"; then + AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir]) + fi + if test x"$use_pam_so" = x"yes"; then + if test x"$netatalk_cv_install_pam" = x"yes"; then + AC_MSG_RESULT([ pam config directory: $ac_cv_pamdir]) + else AC_MSG_RESULT([]) AC_MSG_WARN([ PAM support was configured for your system, but the netatalk PAM configuration file]) AC_MSG_WARN([ cannot be installed. Please install the config/netatalk.pamd file manually.]) AC_MSG_WARN([ If you're running Solaris or BSD you'll have to edit /etc/pam.conf to get PAM working.]) AC_MSG_WARN([ You can also re-run configure and specify --without-pam to disable PAM support.]) + fi fi - ]) From ffb71866c2ba0fbb68e05dbb3b6c40975f96c9e3 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 24 Feb 2013 10:15:05 +0100 Subject: [PATCH 39/67] Remove unneeded include --- etc/afpd/afpstats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/afpstats.c b/etc/afpd/afpstats.c index 1dbacdf8..b50dc33c 100644 --- a/etc/afpd/afpstats.c +++ b/etc/afpd/afpstats.c @@ -21,8 +21,8 @@ #include #include #include + #include -#include #include #include From d12639596d43e40e48ea6fad0eba47bb5832ef61 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 25 Feb 2013 12:12:48 +0100 Subject: [PATCH 40/67] Add PATH to helpstring --- macros/netatalk.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index f77233b5..c52617ed 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -52,7 +52,7 @@ AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ AC_ARG_WITH( dbus-sysconf-dir, - [AS_HELP_STRING([--with-dbus-sysconf-dir],[Path to dbus system bus security configuration directory (default: ${sysconfdir}/dbus-1/system.d/)])], + [AS_HELP_STRING([--with-dbus-sysconf-dir=PATH],[Path to dbus system bus security configuration directory (default: ${sysconfdir}/dbus-1/system.d/)])], ac_cv_dbus_sysdir=$withval, ac_cv_dbus_sysdir='${sysconfdir}/dbus-1/system.d' ) From eebad2c649b5e3a77d5b6e71456371b7313ec6a5 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 25 Feb 2013 18:07:01 +0100 Subject: [PATCH 41/67] Fix distcheck error caused by pkgconfig stuff --- contrib/misc/libevent.patch | 42 +++++++++++++++++++++++++++++++------ libevent/Makefile.am | 8 +------ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/contrib/misc/libevent.patch b/contrib/misc/libevent.patch index 7d69713e..14245d2d 100644 --- a/contrib/misc/libevent.patch +++ b/contrib/misc/libevent.patch @@ -1,8 +1,35 @@ diff --git a/libevent/Makefile.am b/libevent/Makefile.am -index 46f6d34..dda19b2 100644 +index 09505bd..8114ad3 100644 --- a/libevent/Makefile.am +++ b/libevent/Makefile.am -@@ -173,7 +173,7 @@ NO_UNDEFINED = +@@ -86,9 +86,6 @@ if INSTALL_LIBEVENT + dist_bin_SCRIPTS = event_rpcgen.py + endif + +-pkgconfigdir=$(libdir)/pkgconfig +-LIBEVENT_PKGCONFIG=libevent.pc +- + # These sources are conditionally added by configure.in or conditionally + # included from other files. + PLATFORM_DEPENDENT_SRC = \ +@@ -108,16 +105,13 @@ EXTRA_DIST = \ + LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la + if PTHREADS + LIBEVENT_LIBS_LA += libevent_pthreads.la +-LIBEVENT_PKGCONFIG += libevent_pthreads.pc + endif + if OPENSSL + LIBEVENT_LIBS_LA += libevent_openssl.la +-LIBEVENT_PKGCONFIG += libevent_openssl.pc + endif + + if INSTALL_LIBEVENT + lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA) +-pkgconfig_DATA = $(LIBEVENT_PKGCONFIG) + else + noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA) + endif +@@ -196,7 +190,7 @@ NO_UNDEFINED = MAYBE_CORE = endif @@ -11,9 +38,12 @@ index 46f6d34..dda19b2 100644 libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC) libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS) -@@ -221,3 +221,5 @@ FORCE: - - DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h +@@ -249,5 +243,7 @@ doxygen: FORCE + doxygen $(srcdir)/Doxyfile + FORCE: -+install: +-DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h ++DISTCLEANFILES = *~ ./include/event2/event-config.h + ++install: + diff --git a/libevent/Makefile.am b/libevent/Makefile.am index 87f3f146..8114ad36 100644 --- a/libevent/Makefile.am +++ b/libevent/Makefile.am @@ -86,9 +86,6 @@ if INSTALL_LIBEVENT dist_bin_SCRIPTS = event_rpcgen.py endif -pkgconfigdir=$(libdir)/pkgconfig -LIBEVENT_PKGCONFIG=libevent.pc - # These sources are conditionally added by configure.in or conditionally # included from other files. PLATFORM_DEPENDENT_SRC = \ @@ -108,16 +105,13 @@ EXTRA_DIST = \ LIBEVENT_LIBS_LA = libevent.la libevent_core.la libevent_extra.la if PTHREADS LIBEVENT_LIBS_LA += libevent_pthreads.la -LIBEVENT_PKGCONFIG += libevent_pthreads.pc endif if OPENSSL LIBEVENT_LIBS_LA += libevent_openssl.la -LIBEVENT_PKGCONFIG += libevent_openssl.pc endif if INSTALL_LIBEVENT lib_LTLIBRARIES = $(LIBEVENT_LIBS_LA) -pkgconfig_DATA = $(LIBEVENT_PKGCONFIG) else noinst_LTLIBRARIES = $(LIBEVENT_LIBS_LA) endif @@ -249,7 +243,7 @@ doxygen: FORCE doxygen $(srcdir)/Doxyfile FORCE: -DISTCLEANFILES = *~ libevent.pc ./include/event2/event-config.h +DISTCLEANFILES = *~ ./include/event2/event-config.h install: From 793ceb303ae22266e55f8b681ab21f00aebd35e9 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Wed, 27 Feb 2013 08:57:55 +0100 Subject: [PATCH 42/67] Change pkg-config check for dbus-glib --- macros/netatalk.m4 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index c52617ed..c190405f 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -37,7 +37,7 @@ dnl Check for dbus-glib, for AFP stats AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ atalk_cv_with_dbus=no PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.1, have_dbus=yes, have_dbus=no) - PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.6, have_dbus_glib=yes, have_dbus_glib=no) + PKG_CHECK_MODULES(DBUS_GLIB, dbus-glib-1, have_dbus_glib=yes, have_dbus_glib=no) PKG_CHECK_MODULES(DBUS_GTHREAD, gthread-2.0, have_dbus_gthread=yes, have_dbus_gthread=no) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) From bb8bc51e54795edffc1d2b70cb232eba79b97ffb Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Mon, 4 Mar 2013 17:45:19 +0100 Subject: [PATCH 43/67] New option 'afpstats' --- NEWS | 4 +++- etc/afpd/main.c | 3 ++- include/atalk/globals.h | 1 + libatalk/util/netatalk_conf.c | 2 ++ man/man5/afp.conf.5.tmpl | 15 ++++++++++----- 5 files changed, 18 insertions(+), 7 deletions(-) diff --git a/NEWS b/NEWS index 070b773c..7f43cf0f 100644 --- a/NEWS +++ b/NEWS @@ -18,7 +18,9 @@ Changes in 3.0.3 * NEW: AFP stats about active session via dbus IPC. Client side python program `afpstats`. Requires dbus, dbus-glib any python-dbus. configure option --dbus-sysconf-dir for specifying dbus - system security configuration files. + system security configuration files. + New option 'afpstats' (default: no) which determines whether + to enable the feature or not. * NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available probes. * UPD: Reload groups when reloading volumes. FR #71. diff --git a/etc/afpd/main.c b/etc/afpd/main.c index 22650479..141d420c 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -329,7 +329,8 @@ int main(int ac, char **av) #ifdef HAVE_DBUS_GLIB /* Run dbus AFP statics thread */ - (void)afpstats_init(server_children); + if (obj.options.flags & OPTION_DBUS_AFPSTATS) + (void)afpstats_init(server_children); #endif afp_child_t *child; diff --git a/include/atalk/globals.h b/include/atalk/globals.h index e5fbb292..96f062a0 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -55,6 +55,7 @@ #define OPTION_ACL2MACCESS (1 << 8) #define OPTION_NOZEROCONF (1 << 9) #define OPTION_SHARE_RESERV (1 << 11) /* whether to use Solaris fcntl F_SHARE locks */ +#define OPTION_DBUS_AFPSTATS (1 << 12) /* whether to run dbus thread for afpstats */ #define PASSWD_NONE 0 #define PASSWD_SET (1 << 0) diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index b51b2a0d..fdc7e556 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -1719,6 +1719,8 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->flags |= OPTION_NOSENDFILE; if (iniparser_getboolean(config, INISEC_GLOBAL, "solaris share reservations", 1)) options->flags |= OPTION_SHARE_RESERV; + if (iniparser_getboolean(config, INISEC_GLOBAL, "afpstats", 0)) + options->flags |= OPTION_DBUS_AFPSTATS; if (iniparser_getboolean(config, INISEC_GLOBAL, "afp read locks", 0)) options->flags |= OPTION_AFP_READ_LOCK; if (!iniparser_getboolean(config, INISEC_GLOBAL, "save password", 1)) diff --git a/man/man5/afp.conf.5.tmpl b/man/man5/afp.conf.5.tmpl index c03ad30a..6840bf7d 100644 --- a/man/man5/afp.conf.5.tmpl +++ b/man/man5/afp.conf.5.tmpl @@ -2,12 +2,12 @@ .\" Title: afp.conf .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] .\" Generator: DocBook XSL Stylesheets v1.78.0 -.\" Date: 19 Jan 2013 +.\" Date: 19 Feb 2013 .\" Manual: Netatalk 3.0 .\" Source: Netatalk 3.0 .\" Language: English .\" -.TH "AFP\&.CONF" "5" "19 Jan 2013" "Netatalk 3.0" "Netatalk 3.0" +.TH "AFP\&.CONF" "5" "19 Feb 2013" "Netatalk 3.0" "Netatalk 3.0" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -508,6 +508,11 @@ afp read locks = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR Whether to apply locks to the byte region read in FPRead calls\&. The AFP spec mandates this, but it\*(Aqs not really in line with UNIX semantics and is a performance hug\&. .RE .PP +afpstats = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR +.RS 4 +Whether to provide AFP runtime statistics (connected users, open volumes) via dbus\&. +.RE +.PP basedir regex = \fIregex\fR \fB(H)\fR .RS 4 Regular expression which matches the parent directory of the user homes\&. If @@ -871,7 +876,7 @@ cnid scheme = \fIbackend\fR \fB(V)\fR set the CNID backend to be used for the volume, default is [:DEFAULT_CNID_SCHEME:] available schemes: [:COMPILED_BACKENDS:] .RE .PP -ea = \fInone|auto|sys|ad\fR +ea = \fInone|auto|sys|ad\fR \fB(V)\fR .RS 4 Specify how Extended Attributes are stored\&. @@ -914,7 +919,7 @@ specifies the Mac client charset for this Volume, e\&.g\&. \fIMAC_CYRILLIC\fR\&. If not specified the global setting is applied\&. This setting is only required if you need volumes, where the Mac charset differs from the one globally set in the [Global] section\&. .RE .PP -casefold = \fBoption\fR +casefold = \fBoption\fR \fB(V)\fR .RS 4 The casefold option handles, if the case of filenames should be changed\&. The available options are: .sp @@ -951,7 +956,7 @@ is for directories only\&. Don\*(Aqt use with "\fBunix priv = no\fR"\&. .\} .nf file perm = 0660 directory perm = - 0770 + 0770 .fi .if n \{\ .RE From cc423db772cec28174dae0076beda17115d7088a Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 5 Mar 2013 09:32:28 +0100 Subject: [PATCH 44/67] Possible fixes to afpstats dbus issue Initialize afpstats before calling configinit in main() thus ensuring dbus glib thread initilisation is performed as we need it. Use private dbus connection from dbus_g_bus_get_private() which should help with issues seen where our avahi dbus thread crashed. --- etc/afpd/afpstats.c | 12 ++++++++---- etc/afpd/main.c | 11 +++++------ 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/etc/afpd/afpstats.c b/etc/afpd/afpstats.c index b50dc33c..80d3e6f5 100644 --- a/etc/afpd/afpstats.c +++ b/etc/afpd/afpstats.c @@ -44,6 +44,7 @@ static gpointer afpstats_thread(gpointer _data) DBusGConnection *bus; DBusGProxy *bus_proxy; GError *error = NULL; + GMainContext *ctxt; GMainLoop *thread_loop; guint request_name_result; sigset_t sigs; @@ -52,11 +53,12 @@ static gpointer afpstats_thread(gpointer _data) sigfillset(&sigs); pthread_sigmask(SIG_BLOCK, &sigs, NULL); - dbus_g_object_type_install_info(AFPSTATS_TYPE_OBJECT, &dbus_glib_afpstats_obj_object_info); + ctxt = g_main_context_new(); + thread_loop = g_main_loop_new(ctxt, FALSE); - thread_loop = g_main_loop_new(NULL, FALSE); + dbus_g_object_type_install_info(AFPSTATS_TYPE_OBJECT, &dbus_glib_afpstats_obj_object_info); - if (!(bus = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error))) { + if (!(bus = dbus_g_bus_get_private(DBUS_BUS_SYSTEM, ctxt, &error))) { LOG(log_error, logtype_afpd,"Couldn't connect to system bus: %s", error->message); return NULL; } @@ -110,8 +112,10 @@ int afpstats_init(server_child_t *childs_in) childs = childs_in; g_type_init(); - (void)g_log_set_default_handler(my_glib_log, NULL); g_thread_init(NULL); + dbus_g_thread_init(); + (void)g_log_set_default_handler(my_glib_log, NULL); + thread = g_thread_create(afpstats_thread, NULL, TRUE, NULL); return 0; diff --git a/etc/afpd/main.c b/etc/afpd/main.c index 141d420c..cd65f7a9 100644 --- a/etc/afpd/main.c +++ b/etc/afpd/main.c @@ -312,6 +312,11 @@ int main(int ac, char **av) sigaddset(&sigs, SIGCHLD); pthread_sigmask(SIG_BLOCK, &sigs, NULL); +#ifdef HAVE_DBUS_GLIB + /* Run dbus AFP statics thread */ + if (obj.options.flags & OPTION_DBUS_AFPSTATS) + (void)afpstats_init(server_children); +#endif if (configinit(&obj) != 0) { LOG(log_error, logtype_afpd, "main: no servers configured"); afp_exit(EXITERR_CONF); @@ -327,12 +332,6 @@ int main(int ac, char **av) /* set limits */ (void)setlimits(); -#ifdef HAVE_DBUS_GLIB - /* Run dbus AFP statics thread */ - if (obj.options.flags & OPTION_DBUS_AFPSTATS) - (void)afpstats_init(server_children); -#endif - afp_child_t *child; int recon_ipc_fd; pid_t pid; From 8912a30f5695b1be34165acc62c3062397f40dd1 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 6 Mar 2013 18:35:15 +0100 Subject: [PATCH 45/67] Check for dbus_g_bus_get_private(), older dbus-glib versions seem to miss it --- macros/netatalk.m4 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index c190405f..fbf9d490 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -46,7 +46,13 @@ AC_DEFUN([AC_NETATALK_DBUS_GLIB], [ AC_SUBST(DBUS_GTHREAD_CFLAGS) AC_SUBST(DBUS_GTHREAD_LIBS) if test x$have_dbus_glib = xyes -a x$have_dbus = xyes -a x$have_dbus_gthread = xyes ; then - atalk_cv_with_dbus=yes + saved_CFLAGS=$CFLAGS + saved_LIBS=$LIBS + CFLAGS="$CFLAGS $DBUS_GLIB_CFLAGS" + LIBS="$LIBS $DBUS_GLIB_LIBS" + AC_CHECK_FUNC([dbus_g_bus_get_private], [atalk_cv_with_dbus=yes], [atalk_cv_with_dbus=no]) + CFLAGS="$saved_CFLAGS" + LIBS="$saved_LIBS" fi AM_CONDITIONAL(HAVE_DBUS_GLIB, test x$atalk_cv_with_dbus = xyes) From 7894add23ff7428af48e22f7bd11b7edb984f236 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Wed, 6 Mar 2013 19:10:06 +0100 Subject: [PATCH 46/67] Add IPC commands to string array --- include/atalk/server_ipc.h | 1 + libatalk/util/server_ipc.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/atalk/server_ipc.h b/include/atalk/server_ipc.h index 50eb7edc..0c38a7b7 100644 --- a/include/atalk/server_ipc.h +++ b/include/atalk/server_ipc.h @@ -4,6 +4,7 @@ #include #include +/* Remember to add IPC commands to server_ipc.c:ipc_cmd_str[] */ #define IPC_DISCOLDSESSION 0 #define IPC_GETSESSION 1 #define IPC_STATE 2 /* pass AFP session state */ diff --git a/libatalk/util/server_ipc.c b/libatalk/util/server_ipc.c index fa1778e9..e49d165d 100644 --- a/libatalk/util/server_ipc.c +++ b/libatalk/util/server_ipc.c @@ -43,7 +43,9 @@ typedef struct ipc_header { } ipc_header_t; static char *ipc_cmd_str[] = { "IPC_DISCOLDSESSION", - "IPC_GETSESSION"}; + "IPC_GETSESSION", + "IPC_STATE", + "IPC_VOLUMES"}; /* * Pass afp_socket to old disconnected session if one has a matching token (token = pid) From fa873cb4f32758ea6f5e3492d9e4828cfcbacdea Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Thu, 7 Mar 2013 19:03:30 +0100 Subject: [PATCH 47/67] Fix an issue caused by read-only ._ ressource forks Fixes bug #502. --- NEWS | 2 ++ etc/afpd/fork.c | 2 -- libatalk/adouble/ad_open.c | 43 ++++++++++++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/NEWS b/NEWS index 7f43cf0f..8a628754 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,8 @@ Changes in 3.0.3 * NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available probes. * UPD: Reload groups when reloading volumes. FR #71. +* FIX: Attempt to read read-only ._ rfork results in disconnect. + Fixes bugs #502. Changes in 3.0.2 ================ diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 776d2f63..7f5487ee 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -328,8 +328,6 @@ int afp_openfork(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, si } else { eid = ADEID_RFORK; adflags |= ADFLAGS_RF; - if (!(access & OPENACC_WR)) - adflags |= ADFLAGS_NORF; } if (access & OPENACC_WR) { diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 3cedebab..ef971bb9 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -766,7 +766,8 @@ static int ad_header_upgrade_ea(struct adouble *ad _U_, const char *name _U_) * * We're called because opening ADFLAGS_HF caused an error. * 1. In case ad_open is called with ADFLAGS_NOHF the error is suppressed. - * 2. If ad_open was called with ADFLAGS_DF we may have opened the datafork and thus + * 2. Open non-existent ressource fork, this will just result in first read return EOF + * 3. If ad_open was called with ADFLAGS_DF we may have opened the datafork and thus * ought to close it before returning with an error condition. */ static int ad_error(struct adouble *ad, int adflags) @@ -775,7 +776,9 @@ static int ad_error(struct adouble *ad, int adflags) if (adflags & ADFLAGS_NOHF) { /* 1 */ return 0; } - if (adflags & (ADFLAGS_DF | ADFLAGS_SETSHRMD | ADFLAGS_CHECK_OF)) { /* 2 */ + if ((adflags & ADFLAGS_RDONLY) && (adflags & ADFLAGS_RF) && (errno == ENOENT)) /* 2 */ + return 0; + if (adflags & (ADFLAGS_DF | ADFLAGS_SETSHRMD | ADFLAGS_CHECK_OF)) { /* 3 */ ad_close( ad, ADFLAGS_DF ); err = errno; } @@ -1203,7 +1206,7 @@ static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble LOG(log_debug, logtype_ad, "ad_open_rf_v2(\"%s\"): BEGIN", fullpathname(path)); - if (!AD_META_OPEN(ad) && !(adflags & ADFLAGS_NORF)) + if (!AD_META_OPEN(ad) && !(adflags & (ADFLAGS_NORF | ADFLAGS_RDONLY))) EC_FAIL; if (AD_META_OPEN(ad)) ad->ad_reso_refcount++; @@ -1256,12 +1259,34 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble #else EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags) ); if ((ad_reso_fileno(ad) = open(rfpath, oflags)) == -1) { - if (!(adflags & ADFLAGS_CREATE)) - EC_FAIL; - oflags |= O_CREAT; - EC_NEG1_LOG( ad_reso_fileno(ad) = open(rfpath, oflags, mode) ); - LOG(log_debug, logtype_ad, "ad_open_rf(\"%s\"): created adouble rfork: \"%s\"", - path, rfpath); + if (!(adflags & ADFLAGS_CREATE)) { + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + if (!(adflags & ADFLAGS_RDONLY)) { + LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(rfpath), strerror(errno)); + EC_FAIL; + } + oflags &= ~O_RDWR; + oflags |= O_RDONLY; + if ((ad_reso_fileno(ad) = open(rfpath, oflags)) == -1) { + LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(rfpath), strerror(errno)); + EC_FAIL; + } + break; + case ENOENT: + EC_EXIT_STATUS(0); + default: + LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(rfpath), strerror(errno)); + EC_FAIL; + } + } else { + oflags |= O_CREAT; + EC_NEG1_LOG( ad_reso_fileno(ad) = open(rfpath, oflags, mode) ); + LOG(log_debug, logtype_ad, "ad_open_rf(\"%s\"): created adouble rfork: \"%s\"", + path, rfpath); + } } #endif opened = 1; From 40ec781c1ddb2686c589e4184bc08fa266f28b40 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Fri, 8 Mar 2013 18:29:13 +0100 Subject: [PATCH 48/67] File's ressource fork can't be read if metadata EA is missing Fixes bug #501. --- NEWS | 4 +++- etc/afpd/file.c | 28 ++++++++++++++++--------- include/atalk/adouble.h | 1 + libatalk/adouble/ad_open.c | 43 +++++++++++++++++++------------------- 4 files changed, 43 insertions(+), 33 deletions(-) diff --git a/NEWS b/NEWS index 8a628754..ba0c0cc7 100644 --- a/NEWS +++ b/NEWS @@ -25,7 +25,9 @@ Changes in 3.0.3 probes. * UPD: Reload groups when reloading volumes. FR #71. * FIX: Attempt to read read-only ._ rfork results in disconnect. - Fixes bugs #502. + Fixes bug #502. +* FIX: File's ressource fork can't be read if metadata EA is missing. + Fixes bug #501. Changes in 3.0.2 ================ diff --git a/etc/afpd/file.c b/etc/afpd/file.c index bd516087..be1fafe5 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -459,18 +459,23 @@ int getmetadata(const AFPObj *obj, data += sizeof( aint ); break; - case FILPBIT_RFLEN : - if ( adp ) { + case FILPBIT_RFLEN: { + off_t rlen; + if (adp) { if (adp->ad_rlen > 0xffffffff) aint = 0xffffffff; else aint = htonl( adp->ad_rlen); } else { - aint = 0; + rlen = ad_reso_size(path->u_name, 0, NULL); + if (rlen > 0xffffffff) + rlen = 0xffffffff; + aint = htonl(rlen); } memcpy(data, &aint, sizeof( aint )); data += sizeof( aint ); break; + } /* Current client needs ProDOS info block for this file. Use simple heuristic and let the Mac "type" string tell @@ -538,15 +543,18 @@ int getmetadata(const AFPObj *obj, data += sizeof( aint ); break; case FILPBIT_EXTRFLEN: - aint = 0; - if (adp) + if (adp) { aint = htonl(adp->ad_rlen >> 32); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); - if (adp) + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); aint = htonl(adp->ad_rlen); - memcpy(data, &aint, sizeof( aint )); - data += sizeof( aint ); + memcpy(data, &aint, sizeof( aint )); + data += sizeof( aint ); + } else { + int64_t rlen = hton64(ad_reso_size(path->u_name, 0, NULL)); + memcpy(data, &rlen, sizeof(rlen)); + data += sizeof(rlen); + } break; case FILPBIT_UNIXPR : /* accessmode may change st_mode with ACLs */ diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index 6e76e51b..fd870876 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -409,6 +409,7 @@ extern int ad_metadata (const char *, int, struct adouble *); extern int ad_metadataat (int, const char *, int, struct adouble *); extern mode_t ad_hf_mode(mode_t mode); extern int ad_valid_header_osx(const char *path); +extern off_t ad_reso_size(const char *path, int adflags, struct adouble *ad); /* ad_conv.c */ extern int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, const char **newpath); diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index ef971bb9..3b641d66 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -113,7 +113,7 @@ static int ad_mkrf_ea(const char *path); #endif static int ad_header_read_ea(const char *path, struct adouble *ad, const struct stat *hst); static int ad_header_upgrade_ea(struct adouble *ad, const char *name); -static int ad_reso_size(const char *path, int adflags, struct adouble *ad); +off_t ad_reso_size(const char *path, int adflags, struct adouble *ad); static int ad_mkrf_osx(const char *path); @@ -1105,7 +1105,7 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble if (ad_meta_fileno(ad) != -1) ad->ad_mdp->adf_refcount++; - (void)ad_reso_size(path, adflags, ad); + ad->ad_rlen = ad_reso_size(path, adflags, ad); EC_CLEANUP: if (ret != 0 && opened && ad_meta_fileno(ad) != -1) { @@ -1128,7 +1128,6 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a int ret = 0; memset(ad->ad_eid, 0, sizeof( ad->ad_eid )); - ad->ad_rlen = 0; switch (ad->ad_vers) { case AD_VERSION2: @@ -1151,48 +1150,47 @@ static int ad_open_hf(const char *path, int adflags, int mode, struct adouble *a } /*! - * Get resofork length for adouble:ea + * Get resofork length for adouble:ea, parameter 'ad' may be NULL */ -static int ad_reso_size(const char *path, int adflags, struct adouble *ad) +off_t ad_reso_size(const char *path, int adflags, struct adouble *ad) { EC_INIT; struct stat st; + off_t rlen; - if (adflags & ADFLAGS_DIR) { - ad->ad_rlen = 0; - goto EC_CLEANUP; - } + if (adflags & ADFLAGS_DIR) + EC_FAIL; LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): BEGIN", path); #ifdef HAVE_EAFD ssize_t easz; - if (ad_reso_fileno(ad) != -1) { + if (ad && ad_reso_fileno(ad) != -1) { EC_NEG1( fstat(ad_reso_fileno(ad), &st) ); - ad->ad_rlen = st.st_size; - } else if (ad_meta_fileno(ad) != -1) { - EC_NEG1( (ad->ad_rlen = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0)) ); + rlen = st.st_size; + } else if (ad && ad_meta_fileno(ad) != -1) { + EC_NEG1( (rlen = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_RESO, NULL, 0)) ); } else { - EC_NEG1( (ad->ad_rlen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) ); + EC_NEG1( (rlen = sys_lgetxattr(path, AD_EA_RESO, NULL, 0)) ); } #else const char *rfpath; - EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags)); + EC_NULL_LOG( rfpath = ad_path_osx(path, adflags)); EC_ZERO( lstat(rfpath, &st)); if (st.st_size > ADEDOFF_RFORK_OSX) - ad->ad_rlen = st.st_size - ADEDOFF_RFORK_OSX; + rlen = st.st_size - ADEDOFF_RFORK_OSX; else - ad->ad_rlen = 0; + rlen = 0; #endif - LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): size: %zd", path, ad->ad_rlen); + LOG(log_debug, logtype_ad, "ad_reso_size(\"%s\"): size: %zd", path, rlen); EC_CLEANUP: if (ret != 0) - ad->ad_rlen = 0; - EC_EXIT; + rlen = 0; + return rlen; } static int ad_open_rf_v2(const char *path, int adflags, int mode, struct adouble *ad) @@ -1241,7 +1239,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble } ad->ad_rfp->adf_flags &= ~( O_TRUNC | O_CREAT ); ad->ad_rfp->adf_refcount++; - EC_NEG1_LOG( ad_reso_size(path, adflags, ad)); + EC_NEG1_LOG( ad->ad_rlen = ad_reso_size(path, adflags, ad)); goto EC_CLEANUP; } #ifdef HAVE_EAFD @@ -1312,7 +1310,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble } #endif - (void)ad_reso_size(path, adflags, ad); + ad->ad_rlen = ad_reso_size(path, adflags, ad); EC_CLEANUP: if (ret != 0) { @@ -1586,6 +1584,7 @@ static void ad_init_func(struct adouble *ad) ad_reso_fileno(ad) = -1; ad_meta_fileno(ad) = -1; ad->ad_refcount = 1; + ad->ad_rlen = 0; return; } From c74dd3730ea1927d5083242fce4dc042f9a8646c Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sat, 9 Mar 2013 13:50:37 +0100 Subject: [PATCH 49/67] Solaris fixes for bugs #501 and #502 --- libatalk/adouble/ad_open.c | 30 +++++++++++++++++++++++++----- libatalk/vfs/extattr.c | 1 + 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 3b641d66..cd45fef2 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1247,12 +1247,32 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble EC_FAIL; if ((ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), AD_EA_RESO, oflags)) == -1) { if (!(adflags & ADFLAGS_CREATE)) { - errno = ENOENT; - EC_FAIL; + switch (errno) { + case EACCES: + case EPERM: + case EROFS: + if (!(adflags & ADFLAGS_RDONLY)) { + LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(path), strerror(errno)); + EC_FAIL; + } + oflags &= ~O_RDWR; + oflags |= O_RDONLY; + if ((ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), AD_EA_RESO, oflags)) == -1) { + LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(path), strerror(errno)); + EC_FAIL; + } + break; + case ENOENT: + EC_EXIT_STATUS(0); + default: + LOG(log_error, logtype_ad, "ad_open_rf_ea(\"%s\"): \"%s\"", fullpathname(path), strerror(errno)); + EC_FAIL; + } + } else { + oflags |= O_CREAT; + EC_NEG1_LOG( ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), + AD_EA_RESO, oflags, 0666) ); } - oflags |= O_CREAT; - EC_NEG1_LOG( ad_reso_fileno(ad) = sys_getxattrfd(ad_meta_fileno(ad), - AD_EA_RESO, oflags, 0666) ); } #else EC_NULL_LOG( rfpath = ad->ad_ops->ad_path(path, adflags) ); diff --git a/libatalk/vfs/extattr.c b/libatalk/vfs/extattr.c index 5206aa6d..73724d53 100644 --- a/libatalk/vfs/extattr.c +++ b/libatalk/vfs/extattr.c @@ -910,6 +910,7 @@ static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode) switch (errno) { case ENOENT: case EEXIST: + case EACCES: break; default: LOG(log_debug, logtype_default, "openat(\"%s\"): %s", From 88ddeb8cb78c2a9d5954f53a92f3d7c9cfd05957 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Sat, 9 Mar 2013 14:23:33 +0100 Subject: [PATCH 50/67] Conversion from adouble v2 to ea for directories Fixes bug #500. --- NEWS | 2 ++ libatalk/adouble/ad_conv.c | 1 + 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index ba0c0cc7..42f7d498 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,8 @@ Changes in 3.0.3 Fixes bug #502. * FIX: File's ressource fork can't be read if metadata EA is missing. Fixes bug #501. +* FIX: Conversion from adouble v2 to ea for directories. + Fixes bug #500. Changes in 3.0.2 ================ diff --git a/libatalk/adouble/ad_conv.c b/libatalk/adouble/ad_conv.c index 151ab9fd..486b0313 100644 --- a/libatalk/adouble/ad_conv.c +++ b/libatalk/adouble/ad_conv.c @@ -65,6 +65,7 @@ static int ad_conv_v22ea_hf(const char *path, const struct stat *sp, const struc switch (S_IFMT & sp->st_mode) { case S_IFREG: + case S_IFDIR: break; default: return 0; From dd933a956fca517a8c9407d46da89a665b88d4cd Mon Sep 17 00:00:00 2001 From: HAT Date: Mon, 11 Mar 2013 00:23:30 +0900 Subject: [PATCH 51/67] afpd -V show dbus and dtrace --- etc/afpd/afp_options.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index bac65d59..932e6a65 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -165,6 +165,20 @@ static void show_version_extended(void ) #else puts( "No" ); #endif + + printf( " D-Bus support:\t" ); +#ifdef HAVE_DBUS_GLIB + puts( "Yes" ); +#else + puts( "No" ); +#endif + + printf( " DTrace probes:\t" ); +#ifdef WITH_DTRACE + puts( "Yes" ); +#else + puts( "No" ); +#endif } /* From 5ec122952ff5835479f7441291dc8fdbb7796de1 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 5 Mar 2013 17:40:22 +0100 Subject: [PATCH 52/67] sys_lsetxattr error messages when mounting read only filesystem Fixes bug #504. --- NEWS | 2 ++ include/atalk/adouble.h | 1 + libatalk/adouble/ad_conv.c | 3 +++ libatalk/adouble/ad_open.c | 4 ++++ libatalk/util/netatalk_conf.c | 2 ++ 5 files changed, 12 insertions(+) diff --git a/NEWS b/NEWS index 42f7d498..35f9ea2b 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,8 @@ Changes in 3.0.3 Fixes bug #501. * FIX: Conversion from adouble v2 to ea for directories. Fixes bug #500. +* FIX: Error messages when mounting read-only filesystems. + Fixes bug #504. Changes in 3.0.2 ================ diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index fd870876..de0598b5 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -245,6 +245,7 @@ struct adouble { #define ADFLAGS_TRUNC (1<<12) /* truncate, open called with O_TRUNC */ #define ADVOL_NODEV (1 << 0) +#define ADVOL_RO (1 << 1) #define ADVOL_UNIXPRIV (1 << 2) /* adouble unix priv */ #define ADVOL_INVDOTS (1 << 3) /* dot files (.DS_Store) are invisible) */ #define ADVOL_FOLLO_SYML (1 << 4) diff --git a/libatalk/adouble/ad_conv.c b/libatalk/adouble/ad_conv.c index 486b0313..c68cad45 100644 --- a/libatalk/adouble/ad_conv.c +++ b/libatalk/adouble/ad_conv.c @@ -264,6 +264,9 @@ int ad_convert(const char *path, const struct stat *sp, const struct vol *vol, c if (newpath) *newpath = NULL; + if (vol->v_flags & AFPVOL_RO) + EC_EXIT_STATUS(0); + if ((vol->v_adouble == AD_VERSION_EA) && !(vol->v_flags & AFPVOL_NOV2TOEACONV)) EC_ZERO( ad_conv_v22ea(path, sp, vol) ); diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index cd45fef2..4e1253d1 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1087,6 +1087,10 @@ static int ad_open_hf_ea(const char *path, int adflags, int mode, struct adouble errno = ENOENT; EC_FAIL; } + if ((adflags & ADFLAGS_CREATE) && (ad->ad_options & ADVOL_RO)) { + errno = EROFS; + EC_FAIL; + } LOG(log_debug, logtype_ad, "ad_open_hf_ea(\"%s\"): creating metadata EA", path); diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index fdc7e556..6445d3fe 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -801,6 +801,8 @@ static struct vol *creatvol(AFPObj *obj, volume->v_ad_options |= ADVOL_INVDOTS; if ((volume->v_flags & AFPVOL_FOLLOWSYM)) volume->v_ad_options |= ADVOL_FOLLO_SYML; + if ((volume->v_flags & AFPVOL_RO)) + volume->v_ad_options |= ADVOL_RO; /* Mac to Unix conversion flags*/ if ((volume->v_flags & AFPVOL_EILSEQ)) From 8813338fe4a13634917fe6426ae97f5b14df54e2 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Mon, 11 Mar 2013 17:19:28 +0100 Subject: [PATCH 53/67] Permissions of ._ AppleDouble rfork after conversion from v2 to ea. Fixes bug #505. --- NEWS | 3 +++ libatalk/adouble/ad_conv.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 35f9ea2b..5456a411 100644 --- a/NEWS +++ b/NEWS @@ -32,6 +32,9 @@ Changes in 3.0.3 Fixes bug #500. * FIX: Error messages when mounting read-only filesystems. Fixes bug #504. +* FIX: Permissions of ._ AppleDouble ressource fork after conversion + from v2 to ea. + Fixes bug #505. Changes in 3.0.2 ================ diff --git a/libatalk/adouble/ad_conv.c b/libatalk/adouble/ad_conv.c index c68cad45..b1785c01 100644 --- a/libatalk/adouble/ad_conv.c +++ b/libatalk/adouble/ad_conv.c @@ -157,6 +157,8 @@ static int ad_conv_v22ea_rf(const char *path, const struct stat *sp, const struc EC_ZERO_LOG( copy_fork(ADEID_RFORK, &adea, &adv2) ); adea.ad_rlen = adv2.ad_rlen; ad_flush(&adea); + fchmod(ad_reso_fileno(&adea), sp->st_mode & 0666); + fchown(ad_reso_fileno(&adea), sp->st_uid, sp->st_gid); } EC_CLEANUP: From 2311c1e2f37a20e67782624e386093d6eaa6373c Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Mon, 11 Mar 2013 18:42:23 +0100 Subject: [PATCH 54/67] afpstats-service.xml afpstats_service_glue.h were missing in distribution --- etc/afpd/Makefile.am | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index 2e242d95..ddff6c3e 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -2,7 +2,7 @@ pkgconfdir = @PKGCONFDIR@ BUILT_SOURCES = -EXTRA_DIST = +EXTRA_DIST = afpstats-service.xml afpstats_service_glue.h CLEANFILES = DISTCLEANFILES = @@ -68,7 +68,6 @@ endif if HAVE_DBUS_GLIB BUILT_SOURCES += afpstats_service_glue.h -EXTRA_DIST += afpstats-service.xml DISTCLEANFILES += afpstats_service_glue.h afpstats_service_glue.h: afpstats-service.xml From 02de0f4014590e78965a3445a7a1eba0173a174b Mon Sep 17 00:00:00 2001 From: HAT Date: Fri, 15 Mar 2013 20:32:21 +0900 Subject: [PATCH 55/67] of_findname(): missing argument --- etc/afpd/filedir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index c349f532..8feac755 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -265,7 +265,7 @@ static int moveandrename(struct vol *vol, #ifdef HAVE_ATFUNCS opened = of_findnameat(sdir_fd, &path); #else - opened = of_findname(&path); + opened = of_findname(vol, &path); #endif /* HAVE_ATFUNCS */ if (opened) { From fa5fcf44a4a5498a3083a24985c98ffb42fbce9c Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Fri, 15 Mar 2013 09:19:40 +0100 Subject: [PATCH 56/67] Use FreeBSD sendfile() capability to send protocol header When transmitting file contents to a client with sendfile(), on every platform other then Solaris (where we use sendfilev()), we send the AFP the protocol header with an additional send with MSG_MORE before calling sendfile(). FreeBSD sendfile() supports sending protocol header (and trailer) data similarly to Solaris sendfilev(). --- NEWS | 2 ++ etc/afpd/fork.c | 2 +- libatalk/dsi/dsi_stream.c | 35 +++++++++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index 5456a411..3fe240b2 100644 --- a/NEWS +++ b/NEWS @@ -35,6 +35,8 @@ Changes in 3.0.3 * FIX: Permissions of ._ AppleDouble ressource fork after conversion from v2 to ea. Fixes bug #505. +* UPD: Use FreeBSD sendfile() capability to send protocol header. + From FR #75. Changes in 3.0.2 ================ diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 7f5487ee..577cd471 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -798,7 +798,7 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si "afp_read(fork: %" PRIu16 " [%s], off: %" PRIu64 ", len: %" PRIu64 ", size: %" PRIu64 ")", ofork->of_refnum, (ofork->of_flags & AFPFORK_DATA) ? "data" : "reso", offset, reqcount, size); - if (offset > size) { + if (offset >= size) { err = AFPERR_EOF; goto afp_read_err; } diff --git a/libatalk/dsi/dsi_stream.c b/libatalk/dsi/dsi_stream.c index da58f87c..7579e252 100644 --- a/libatalk/dsi/dsi_stream.c +++ b/libatalk/dsi/dsi_stream.c @@ -344,6 +344,16 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz int sfvcnt; struct sendfilevec vec[2]; ssize_t nwritten; +#elif defined(FREEBSD) + ssize_t nwritten; + void *hdrp; + struct sf_hdtr hdr; + struct iovec iovec; + hdr.headers = &iovec; + hdr.hdr_cnt = 1; + hdr.trailers = NULL; + hdr.trl_cnt = 0; + hdrp = &hdr; #endif LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(off: %jd, len: %zu)", (intmax_t)offset, length); @@ -372,6 +382,9 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz vec[1].sfv_flag = 0; vec[1].sfv_off = offset; vec[1].sfv_len = length; +#elif defined(FREEBSD) + iovec.iov_base = block; + iovec.iov_len = DSI_BLOCKSIZ; #else dsi_stream_write(dsi, block, sizeof(block), DSI_MSG_MORE); #endif @@ -380,6 +393,10 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz #ifdef HAVE_SENDFILEV nwritten = 0; len = sendfilev(dsi->socket, vec, sfvcnt, &nwritten); +#elif defined(FREEBSD) + len = sendfile(fromfd, dsi->socket, pos, total - written, hdrp, &nwritten, 0); + if (len == 0) + len = nwritten; #else len = sys_sendfile(dsi->socket, fromfd, &pos, total - written); #endif @@ -388,16 +405,14 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz case EINTR: case EAGAIN: len = 0; -#ifdef HAVE_SENDFILEV +#if defined(HAVE_SENDFILEV) || defined(FREEBSD) len = (size_t)nwritten; -#else -#if defined(SOLARIS) || defined(FREEBSD) +#elif defined(SOLARIS) if (pos > offset) { /* we actually have sent sth., adjust counters and keep trying */ len = pos - offset; offset = pos; } -#endif /* defined(SOLARIS) || defined(FREEBSD) */ #endif /* HAVE_SENDFILEV */ if (dsi_peek(dsi) != 0) { @@ -426,6 +441,18 @@ ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const siz vec[0].sfv_off += len; vec[0].sfv_len -= len; } +#elif defined(FREEBSD) + if (hdrp) { + if (len >= iovec.iov_len) { + hdrp = NULL; + len -= iovec.iov_len; /* len now contains how much sendfile() actually sent from the file */ + } else { + iovec.iov_len -= len; + iovec.iov_base += len; + len = 0; + } + } + pos += len; #endif /* HAVE_SENDFILEV */ LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: wrote: %zd", len); written += len; From aabcb6c09a4606d833a5793188502fcd08595493 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 19 Mar 2013 12:18:34 +0100 Subject: [PATCH 57/67] read_file() clobbered the AFP error code --- etc/afpd/fork.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 577cd471..ea6cbeec 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -839,9 +839,11 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si *rbuflen = MIN(reqcount, *rbuflen); - err = read_file(ofork, eid, offset, rbuf, rbuflen); - if (err < 0) + cc = read_file(ofork, eid, offset, rbuf, rbuflen); + if (cc < 0) { + err = cc; goto afp_read_done; + } LOG(log_debug, logtype_afpd, "afp_read(name: \"%s\", offset: %jd, reqcount: %jd): got %jd bytes from file", From df482c7788ac6accb3499c153a6527f5abf833aa Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 19 Mar 2013 13:15:10 +0100 Subject: [PATCH 58/67] Fix ressource fork refcounting --- libatalk/adouble/ad_open.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 4e1253d1..e4af84d8 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1242,6 +1242,7 @@ static int ad_open_rf_ea(const char *path, int adflags, int mode, struct adouble EC_FAIL; } ad->ad_rfp->adf_flags &= ~( O_TRUNC | O_CREAT ); + ad->ad_reso_refcount++; ad->ad_rfp->adf_refcount++; EC_NEG1_LOG( ad->ad_rlen = ad_reso_size(path, adflags, ad)); goto EC_CLEANUP; From 023609beb221be242a4aca3bceee9d19e396f496 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Tue, 19 Mar 2013 15:26:03 +0100 Subject: [PATCH 59/67] Increase IO size when sendfile() is not used If sendfile() support is disabled, the current code results in an IO size of 8k for transferring requested data to the client. Eg: - client request to read DSI quantum size bytes (~250k) from a file - afpd process loops read(8k, file) -> send(8k, client) until all 250k have been transferred This should be modified to read the whole 250k in one swoop from the file to a buffer and then send the whole buffer in one swoop to the client. From FR #76. --- NEWS | 2 ++ etc/afpd/fork.c | 14 +++++++++----- libatalk/dsi/dsi_stream.c | 12 +++++++----- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/NEWS b/NEWS index 3fe240b2..1f9f31c4 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,8 @@ Changes in 3.0.3 Fixes bug #505. * UPD: Use FreeBSD sendfile() capability to send protocol header. From FR #75. +* UPD: Increase IO size when sendfile() is not used. + From FR #76. Changes in 3.0.2 ================ diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index ea6cbeec..4e47b91b 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -837,9 +837,9 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si } #endif - *rbuflen = MIN(reqcount, *rbuflen); + *rbuflen = MIN(reqcount, dsi->server_quantum); - cc = read_file(ofork, eid, offset, rbuf, rbuflen); + cc = read_file(ofork, eid, offset, ibuf, rbuflen); if (cc < 0) { err = cc; goto afp_read_done; @@ -856,18 +856,22 @@ static int read_fork(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, si * we know that we're sending some data. if we fail, something * horrible happened. */ - if ((cc = dsi_readinit(dsi, rbuf, *rbuflen, reqcount, err)) < 0) + if ((cc = dsi_readinit(dsi, ibuf, *rbuflen, reqcount, err)) < 0) goto afp_read_exit; *rbuflen = cc; while (*rbuflen > 0) { - cc = read_file(ofork, eid, offset, rbuf, rbuflen); + /* + * This loop isn't really entered anymore, we've already + * sent the whole requested block in dsi_readinit(). + */ + cc = read_file(ofork, eid, offset, ibuf, rbuflen); if (cc < 0) goto afp_read_exit; offset += *rbuflen; /* dsi_read() also returns buffer size of next allocation */ - cc = dsi_read(dsi, rbuf, *rbuflen); /* send it off */ + cc = dsi_read(dsi, ibuf, *rbuflen); /* send it off */ if (cc < 0) goto afp_read_exit; *rbuflen = cc; diff --git a/libatalk/dsi/dsi_stream.c b/libatalk/dsi/dsi_stream.c index 7579e252..05c36fc8 100644 --- a/libatalk/dsi/dsi_stream.c +++ b/libatalk/dsi/dsi_stream.c @@ -523,6 +523,7 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length) { char block[DSI_BLOCKSIZ]; struct iovec iov[2]; + int iovecs = 2; size_t towrite; ssize_t len; @@ -549,7 +550,7 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length) towrite = sizeof(block) + length; dsi->write_count += towrite; while (towrite > 0) { - if (((len = writev(dsi->socket, iov, 2)) == -1 && errno == EINTR) || (len == 0)) + if (((len = writev(dsi->socket, iov, iovecs)) == -1 && errno == EINTR) || (len == 0)) continue; if ((size_t)len == towrite) /* wrote everything out */ @@ -570,12 +571,13 @@ int dsi_stream_send(DSI *dsi, void *buf, size_t length) iov[0].iov_base = (char *) iov[0].iov_base + len; iov[0].iov_len -= len; } else { /* skip to data */ - if (iov[0].iov_len) { + if (iovecs == 2) { + iovecs = 1; len -= iov[0].iov_len; - iov[0].iov_len = 0; + iov[0] = iov[1]; } - iov[1].iov_base = (char *) iov[1].iov_base + len; - iov[1].iov_len -= len; + iov[0].iov_base = (char *) iov[0].iov_base + len; + iov[0].iov_len -= len; } } From c00bb5bf3000d12310dd6d7c63ea20944de033bf Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Thu, 21 Mar 2013 17:21:59 +0100 Subject: [PATCH 60/67] Can't set Finder label on symlinked folder with "follow symlinks = yes" Fixes bug #508. --- NEWS | 2 ++ libatalk/adouble/ad_open.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 1f9f31c4..736a3375 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,8 @@ Changes in 3.0.3 From FR #75. * UPD: Increase IO size when sendfile() is not used. From FR #76. +* FIX: Can't set Finder label on symlinked folder with "follow symlinks = yes". + Fixes bug #508. Changes in 3.0.2 ================ diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index e4af84d8..a2f6f00e 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -624,7 +624,7 @@ static int ad_header_read_ea(const char *path, struct adouble *ad, const struct if (ad_meta_fileno(ad) != -1) header_len = sys_fgetxattr(ad_meta_fileno(ad), AD_EA_META, ad->ad_data, AD_DATASZ_EA); else - header_len = sys_lgetxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA); + header_len = sys_getxattr(path, AD_EA_META, ad->ad_data, AD_DATASZ_EA); if (header_len < 1) { LOG(log_debug, logtype_ad, "ad_header_read_ea: %s", strerror(errno)); return -1; From 2297286a5be343d5a3b1838453f84612be1f7a9e Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 22 Mar 2013 13:11:48 +0100 Subject: [PATCH 61/67] Fix a debug message --- libatalk/acl/uuid.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libatalk/acl/uuid.c b/libatalk/acl/uuid.c index c1bc065f..ff58c3dd 100644 --- a/libatalk/acl/uuid.c +++ b/libatalk/acl/uuid.c @@ -254,6 +254,7 @@ int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) { uid = ntohl(tmp); if ((pwd = getpwuid(uid)) == NULL) { /* not found, add negative entry to cache */ + *name = NULL; add_cachebyuuid(uuidp, "UUID_ENOENT", UUID_ENOENT, 0); ret = -1; } else { @@ -263,7 +264,7 @@ int getnamefromuuid(const uuidp_t uuidp, char **name, uuidtype_t *type) { } LOG(log_debug, logtype_afpd, "getnamefromuuid{local}: UUID: %s -> name: %s, type:%s", - uuid_bin2string(uuidp), *name, uuidtype[(*type) & UUIDTYPESTR_MASK]); + uuid_bin2string(uuidp), *name ? *name : "-", uuidtype[(*type) & UUIDTYPESTR_MASK]); return ret; } else if (memcmp(uuidp, local_group_uuid, 12) == 0) { *type = UUID_GROUP; From b9a9ac3498b7ae48c11b2bec6be1aff810cd37d2 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Thu, 14 Mar 2013 19:54:52 +0100 Subject: [PATCH 62/67] Setting POSIX ACLs on Linux The VFS module for setting ACLs on Linux returned an error when try to set an ACL for a file that doesn't have a ressource fork. Fix this by checking for ENOENT errno and then returning with 0 from the VFS stack. --- NEWS | 2 + etc/afpd/acls.c | 20 ++++++---- libatalk/vfs/acl.c | 3 +- libatalk/vfs/vfs.c | 94 +++++++++++++++------------------------------- 4 files changed, 47 insertions(+), 72 deletions(-) diff --git a/NEWS b/NEWS index 736a3375..3f7c312c 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,8 @@ Changes in 3.0.3 From FR #76. * FIX: Can't set Finder label on symlinked folder with "follow symlinks = yes". Fixes bug #508. +* FIX: Setting POSIX ACLs on Linux + Fixes bug #506. Changes in 3.0.2 ================ diff --git a/etc/afpd/acls.c b/etc/afpd/acls.c index 56ffeea9..6f2abdf3 100644 --- a/etc/afpd/acls.c +++ b/etc/afpd/acls.c @@ -1157,17 +1157,21 @@ static int set_acl(const struct vol *vol, } LOG(log_debug7, logtype_afpd, "set_acl: copied %d trivial ACEs", trivial_ace_count); - /* Ressourcefork first. - Note: for dirs we set the same ACL on the .AppleDouble/.Parent _file_. This - might be strange for ACE_DELETE_CHILD and for inheritance flags. */ + /* Ressourcefork first */ if ((ret = (vol->vfs->vfs_acl(vol, name, ACE_SETACL, new_aces_count, new_aces))) != 0) { - LOG(log_error, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno)); - if (errno == (EACCES | EPERM)) + LOG(log_debug, logtype_afpd, "set_acl: error setting acl: %s", strerror(errno)); + switch (errno) { + case EACCES: + case EPERM: EC_STATUS(AFPERR_ACCESS); - else if (errno == ENOENT) - EC_STATUS(AFPERR_NOITEM); - else + break; + case ENOENT: + EC_STATUS(AFP_OK); + break; + default: EC_STATUS(AFPERR_MISC); + break; + } goto EC_CLEANUP; } if ((ret = (acl(name, ACE_SETACL, new_aces_count, new_aces))) != 0) { diff --git a/libatalk/vfs/acl.c b/libatalk/vfs/acl.c index c936f178..d7c8eb62 100644 --- a/libatalk/vfs/acl.c +++ b/libatalk/vfs/acl.c @@ -108,7 +108,7 @@ int remove_acl_vfs(const char *name) /* Remove default ACL if it's a dir */ - EC_ZERO_LOG_ERR(stat(name, &st), AFPERR_MISC); + EC_ZERO_ERR(stat(name, &st), AFPERR_MISC); if (S_ISDIR(st.st_mode)) { EC_NULL_LOG_ERR(acl = acl_init(0), AFPERR_MISC); EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, acl), AFPERR_MISC); @@ -129,6 +129,7 @@ int remove_acl_vfs(const char *name) EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, acl), AFPERR_MISC); EC_CLEANUP: + if (errno == ENOENT) EC_STATUS(0); if (acl) acl_free(acl); EC_EXIT; diff --git a/libatalk/vfs/vfs.c b/libatalk/vfs/vfs.c index a349cfe8..d79ac05e 100644 --- a/libatalk/vfs/vfs.c +++ b/libatalk/vfs/vfs.c @@ -355,24 +355,17 @@ static int RF_solaris_acl(VFS_FUNC_ARGS_ACL) struct stat st; int len; - if ((stat(path, &st)) != 0) - return -1; - if (S_ISDIR(st.st_mode)) { - len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path); - if (len < 0 || len >= MAXPATHLEN) - return -1; - /* set acl on .AppleDouble dir first */ - if ((acl(buf, cmd, count, aces)) != 0) - return -1; - /* now set ACL on ressource fork */ - if ((acl(vol->ad_path(path, ADFLAGS_DIR), cmd, count, aces)) != 0) - return -1; - } else - /* set ACL on ressource fork */ - if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0) - return -1; - - return 0; + if ((stat(path, &st)) != 0) { + if (errno == ENOENT) + return AFP_OK; + return AFPERR_MISC; + } + if (!S_ISDIR(st.st_mode)) { + /* set ACL on ressource fork */ + if ((acl(vol->ad_path(path, ADFLAGS_HF), cmd, count, aces)) != 0) + return AFPERR_MISC; + } + return AFP_OK; } static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL) @@ -381,20 +374,15 @@ static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL) static char buf[ MAXPATHLEN + 1]; int len; - if (dir) { - len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path); - if (len < 0 || len >= MAXPATHLEN) - return AFPERR_MISC; - /* remove ACL from .AppleDouble/.Parent first */ - if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR))) != AFP_OK) - return ret; - /* now remove from .AppleDouble dir */ - if ((ret = remove_acl_vfs(buf)) != AFP_OK) - return ret; - } else - /* remove ACL from ressource fork */ - if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK) - return ret; + if (dir) + return AFP_OK; + + /* remove ACL from ressource fork */ + if ((ret = remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF))) != AFP_OK) { + if (errno == ENOENT) + return AFP_OK; + return ret; + } return AFP_OK; } @@ -404,55 +392,35 @@ static int RF_solaris_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL) static int RF_posix_acl(VFS_FUNC_ARGS_ACL) { EC_INIT; - static char buf[ MAXPATHLEN + 1]; struct stat st; - int len; if (stat(path, &st) == -1) EC_FAIL; - if (S_ISDIR(st.st_mode)) { - len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path); - if (len < 0 || len >= MAXPATHLEN) - EC_FAIL; - /* set acl on .AppleDouble dir first */ - EC_ZERO_LOG(acl_set_file(buf, type, acl)); - - if (type == ACL_TYPE_ACCESS) - /* set ACL on ressource fork (".Parent") too */ - EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_DIR), type, acl)); - } else { + if (!S_ISDIR(st.st_mode)) { /* set ACL on ressource fork */ - EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl)); + EC_ZERO_ERR( acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl), AFPERR_MISC ); } EC_CLEANUP: - if (ret != 0) - return AFPERR_MISC; - return AFP_OK; + if (errno == ENOENT) + EC_STATUS(AFP_OK); + EC_EXIT; } static int RF_posix_remove_acl(VFS_FUNC_ARGS_REMOVE_ACL) { EC_INIT; - static char buf[ MAXPATHLEN + 1]; - int len; - if (dir) { - len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path); - if (len < 0 || len >= MAXPATHLEN) - return AFPERR_MISC; - /* remove ACL from .AppleDouble/.Parent first */ - EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_DIR)), AFPERR_MISC); + if (dir) + EC_EXIT_STATUS(AFP_OK); - /* now remove from .AppleDouble dir */ - EC_ZERO_LOG_ERR(remove_acl_vfs(buf), AFPERR_MISC); - } else { - /* remove ACL from ressource fork */ - EC_ZERO_LOG_ERR(remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC); - } + /* remove ACL from ressource fork */ + EC_ZERO_ERR( remove_acl_vfs(vol->ad_path(path, ADFLAGS_HF)), AFPERR_MISC ); EC_CLEANUP: + if (errno == ENOENT) + EC_STATUS(AFP_OK); EC_EXIT; } #endif From c608237210fbed8516b8426ef8ae804773f0cb25 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 22 Mar 2013 14:37:06 +0100 Subject: [PATCH 63/67] Only configure libevent when used --- macros/netatalk.m4 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index fbf9d490..3d4576e6 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -106,7 +106,9 @@ AC_DEFUN([AC_NETATALK_LIBEVENT], [ AC_MSG_ERROR([--with-libevent requires a path]) fi AC_MSG_RESULT([$use_bundled_libevent]) - AC_CONFIG_SUBDIRS([libevent]) + if test x"$use_bundled_libevent" = x"yes" ; then + AC_CONFIG_SUBDIRS([libevent]) + fi AC_SUBST(LIBEVENT_CFLAGS) AC_SUBST(LIBEVENT_LDFLAGS) AM_CONDITIONAL(USE_BUILTIN_LIBEVENT, test x"$use_bundled_libevent" = x"yes") From cc7d5d2543c91fe2461a7bd482bf8969638e89b9 Mon Sep 17 00:00:00 2001 From: HAT Date: Sat, 23 Mar 2013 00:12:15 +0900 Subject: [PATCH 64/67] new configure option --with-init-dir=PATH --- NEWS | 1 + distrib/initscripts/Makefile.am | 14 +++++++------- macros/netatalk.m4 | 18 +++++++++++++++++- macros/summary.m4 | 3 +++ 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 3f7c312c..0828927a 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ Changes in 3.0.3 system security configuration files. New option 'afpstats' (default: no) which determines whether to enable the feature or not. +* NEW: configure option --with-init-dir * NEW: dtrace probes, cf include/atalk/afp_dtrace.d for available probes. * UPD: Reload groups when reloading volumes. FR #71. diff --git a/distrib/initscripts/Makefile.am b/distrib/initscripts/Makefile.am index 2d1cb3ab..79dcfb3f 100644 --- a/distrib/initscripts/Makefile.am +++ b/distrib/initscripts/Makefile.am @@ -54,7 +54,7 @@ uninstall: uninstall-startup if USE_REDHAT_SYSV -sysvdir = /etc/rc.d/init.d +sysvdir = $(INIT_DIR) sysv_SCRIPTS = netatalk $(sysv_SCRIPTS): rc.redhat @@ -76,7 +76,7 @@ endif if USE_SYSTEMD -servicedir = /lib/systemd/system +servicedir = $(INIT_DIR) service_DATA = netatalk.service netatalk.service: service.systemd @@ -98,7 +98,7 @@ endif if USE_SUSE_SYSV -sysvdir = /etc/init.d +sysvdir = $(INIT_DIR) sysv_SCRIPTS = netatalk $(sysv_SCRIPTS): rc.suse @@ -120,7 +120,7 @@ endif if USE_NETBSD -sysvdir = /etc/rc.d +sysvdir = $(INIT_DIR) sysv_SCRIPTS = netatalk netatalk: rc.netbsd @@ -141,7 +141,7 @@ endif if USE_SOLARIS -servicedir = /lib/svc/manifest/network/ +servicedir = $(INIT_DIR) service_DATA = netatalk.xml install-data-hook: @@ -158,7 +158,7 @@ endif if USE_GENTOO -sysvdir = /etc/init.d +sysvdir = $(INIT_DIR) sysv_SCRIPTS = netatalk $(sysv_SCRIPTS): rc.gentoo @@ -180,7 +180,7 @@ endif if USE_DEBIAN -sysvdir = /etc/init.d +sysvdir = $(INIT_DIR) sysv_SCRIPTS = netatalk $(sysv_SCRIPTS): rc.debian diff --git a/macros/netatalk.m4 b/macros/netatalk.m4 index 3d4576e6..beceeef9 100644 --- a/macros/netatalk.m4 +++ b/macros/netatalk.m4 @@ -355,7 +355,7 @@ AC_ARG_ENABLE(shell-check, ) ]) -dnl Check for optional sysv initscript install +dnl Check for optional initscript install AC_DEFUN([AC_NETATALK_INIT_STYLE], [ AC_ARG_WITH(init-style, [ --with-init-style use OS specific init config [[redhat-sysv|redhat-systemd|suse-sysv|suse-systemd|gentoo|netbsd|debian|solaris|systemd]]], @@ -367,36 +367,46 @@ AC_DEFUN([AC_NETATALK_INIT_STYLE], [ ;; "redhat-sysv") AC_MSG_RESULT([enabling redhat-style sysv initscript support]) + ac_cv_init_dir="/etc/rc.d/init.d" ;; "redhat-systemd") AC_MSG_RESULT([enabling redhat-style systemd support]) + ac_cv_init_dir="/lib/systemd/system" ;; "suse") AC_MSG_ERROR([--with-init-style=suse is obsoleted. Use suse-sysv or suse-systemd.]) ;; "suse-sysv") AC_MSG_RESULT([enabling suse-style sysv initscript support]) + ac_cv_init_dir="/etc/init.d" ;; "suse-systemd") AC_MSG_RESULT([enabling suse-style systemd support (>=openSUSE12.1)]) + ac_cv_init_dir="/lib/systemd/system" ;; "gentoo") AC_MSG_RESULT([enabling gentoo-style initscript support]) + ac_cv_init_dir="/etc/init.d" ;; "netbsd") AC_MSG_RESULT([enabling netbsd-style initscript support]) + ac_cv_init_dir="/etc/rc.d" ;; "debian") AC_MSG_RESULT([enabling debian-style initscript support]) + ac_cv_init_dir="/etc/init.d" ;; "solaris") AC_MSG_RESULT([enabling solaris-style SMF support]) + ac_cv_init_dir="/lib/svc/manifest/network/" ;; "systemd") AC_MSG_RESULT([enabling general systemd support]) + ac_cv_init_dir="/lib/systemd/system" ;; "none") AC_MSG_RESULT([disabling init-style support]) + ac_cv_init_dir="none" ;; *) AC_MSG_ERROR([illegal init-style]) @@ -411,6 +421,12 @@ AC_DEFUN([AC_NETATALK_INIT_STYLE], [ AM_CONDITIONAL(USE_SYSTEMD, test x$init_style = xsystemd || test x$init_style = xredhat-systemd || test x$init_style = xsuse-systemd) AM_CONDITIONAL(USE_UNDEF, test x$init_style = xnone) + AC_ARG_WITH(init-dir, + [ --with-init-dir=PATH path to OS specific init directory], + ac_cv_init_dir="$withval", ac_cv_init_dir="$ac_cv_init_dir" + ) + INIT_DIR="$ac_cv_init_dir" + AC_SUBST(INIT_DIR, ["$ac_cv_init_dir"]) ]) dnl OS specific configuration diff --git a/macros/summary.m4 b/macros/summary.m4 index 7f5e6499..b8db2579 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -57,6 +57,9 @@ dnl AC_MSG_RESULT([ Samba sharemode interop: $neta_cv_have_smbshmd]) AC_MSG_RESULT([ dtrace probes: $WDTRACE]) AC_MSG_RESULT([ Paths:]) AC_MSG_RESULT([ Netatalk lockfile: $ac_cv_netatalk_lock]) + if test "x$init_style" != x"none"; then + AC_MSG_RESULT([ init directory: $ac_cv_init_dir]) + fi if test x"$atalk_cv_with_dbus" = x"yes"; then AC_MSG_RESULT([ dbus system directory: $ac_cv_dbus_sysdir]) fi From 7a54dad08c63cde0ca7bac77d2103683905edd35 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Sun, 24 Mar 2013 09:35:19 +0100 Subject: [PATCH 65/67] Add afpstats manpage and update afp.conf --- man/man1/.gitignore | 2 +- man/man1/Makefile.am | 4 ++-- man/man1/afpstats.1.tmpl | 50 ++++++++++++++++++++++++++++++++++++++++ man/man5/afp.conf.5.tmpl | 2 +- 4 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 man/man1/afpstats.1.tmpl diff --git a/man/man1/.gitignore b/man/man1/.gitignore index c767a967..39ffeb2f 100644 --- a/man/man1/.gitignore +++ b/man/man1/.gitignore @@ -6,6 +6,6 @@ apple_mv.1 apple_rm.1 asip-status.pl.1 afpldaptest.1 +afpstats.1 uniconv.1 -.gitignore *.o diff --git a/man/man1/Makefile.am b/man/man1/Makefile.am index fe81a7d7..20dede4e 100644 --- a/man/man1/Makefile.am +++ b/man/man1/Makefile.am @@ -12,8 +12,8 @@ SUFFIXES= .tmpl . -e s@:DEFAULT_CNID_SCHEME:@${DEFAULT_CNID_SCHEME}@ \ <$< >$@ -GENERATED_MANS = uniconv.1 asip-status.pl.1 afpldaptest.1 -TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl afpldaptest.1.tmpl +GENERATED_MANS = uniconv.1 asip-status.pl.1 afpldaptest.1 afpstats.1 +TEMPLATE_FILES = uniconv.1.tmpl asip-status.pl.1.tmpl afpldaptest.1.tmpl afpstats.1.tmpl NONGENERATED_MANS = ad.1 \ afppasswd.1 \ diff --git a/man/man1/afpstats.1.tmpl b/man/man1/afpstats.1.tmpl new file mode 100644 index 00000000..b7980996 --- /dev/null +++ b/man/man1/afpstats.1.tmpl @@ -0,0 +1,50 @@ +'\" t +.\" Title: afpstats +.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] +.\" Generator: DocBook XSL Stylesheets v1.78.0 +.\" Date: 24 Mar 2013 +.\" Manual: Netatalk 3.0 +.\" Source: Netatalk 3.0 +.\" Language: English +.\" +.TH "AFPSTATS" "1" "24 Mar 2013" "Netatalk 3.0" "Netatalk 3.0" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +afpstats \- List AFP statistics +.SH "SYNOPSIS" +.HP \w'\fBafpstats\fR\fB\fR\ 'u +\fBafpstats\fR\fB\fR +.SH "DESCRIPTION" +.PP +\fBafpstats\fR +list AFP statistics via D\-Bus IPC\&. +.SH "NOTE" +.PP +\fBafpd\fR +must support D\-Bus\&. Check it by "\fBafpd \-V\fR"\&. +.PP +"\fBafpstats = yes\fR" must be set in +:ETCDIR:/afp\&.conf\&. +.SH "SEE ALSO" +.PP +\fBafpd\fR(8), +\fBafp.conf\fR(5), +\fBdbus-daemon\fR(1) diff --git a/man/man5/afp.conf.5.tmpl b/man/man5/afp.conf.5.tmpl index 6840bf7d..60ec8d0e 100644 --- a/man/man5/afp.conf.5.tmpl +++ b/man/man5/afp.conf.5.tmpl @@ -1035,7 +1035,7 @@ The default setting is false thus symlinks are not followed on the server\&. Thi .PP invisible dots = \fIBOOLEAN\fR (default: \fIno\fR) \fB(V)\fR .RS 4 -make dot files invisible\&. +make dot files invisible\&. WARNING: enabling this option will lead to unwanted sideeffects were OS X applications when saving files to a temporary file starting with a dot first, then renaming the temp file to its final name, result in the saved file being invisible\&. The only thing this option is useful for is making files that start with a dot invisible on Mac OS 9\&. It\*(Aqs completely useless on Mac OS X, as both in Finder and in Terminal files starting with a dot are hidden anyway\&. .RE .PP network ids = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(V)\fR From 8764a9e3373ff77c4846302146fe9aa3cc1d5af2 Mon Sep 17 00:00:00 2001 From: Ralph Boehme Date: Fri, 22 Mar 2013 13:53:10 +0100 Subject: [PATCH 66/67] Fix "ad ls" segfault if requested object is not in an AFP volume Fixes bug #496. --- NEWS | 2 ++ bin/ad/ad_ls.c | 2 +- bin/ad/ad_util.c | 8 +++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 0828927a..c85c245d 100644 --- a/NEWS +++ b/NEWS @@ -44,6 +44,8 @@ Changes in 3.0.3 Fixes bug #508. * FIX: Setting POSIX ACLs on Linux Fixes bug #506. +* FIX: "ad ls" segfault if requested object is not in an AFP volume. + Fixes bug #496. Changes in 3.0.2 ================ diff --git a/bin/ad/ad_ls.c b/bin/ad/ad_ls.c index d8362595..b5947e17 100644 --- a/bin/ad/ad_ls.c +++ b/bin/ad/ad_ls.c @@ -227,7 +227,7 @@ static void print_flags(char *path, afpvol_t *vol, const struct stat *st) if (S_ISDIR(st->st_mode)) adflags = ADFLAGS_DIR; - if (vol->vol->v_path == NULL) + if (vol->vol == NULL || vol->vol->v_path == NULL) return; ad_init(&ad, vol->vol); diff --git a/bin/ad/ad_util.c b/bin/ad/ad_util.c index 897bdf3b..fbe85235 100644 --- a/bin/ad/ad_util.c +++ b/bin/ad/ad_util.c @@ -138,9 +138,11 @@ int openvol(AFPObj *obj, const char *path, afpvol_t *vol) void closevol(afpvol_t *vol) { - if (vol->vol->v_cdb) { - cnid_close(vol->vol->v_cdb); - vol->vol->v_cdb = NULL; + if (vol->vol) { + if (vol->vol->v_cdb) { + cnid_close(vol->vol->v_cdb); + vol->vol->v_cdb = NULL; + } } memset(vol, 0, sizeof(afpvol_t)); } From 6741897de929042ac6efdf1fe6d1b46fea7d940a Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Tue, 26 Mar 2013 10:17:03 +0100 Subject: [PATCH 67/67] Prepare 3.0.3 release --- VERSION | 2 +- libatalk/Makefile.am | 6 +- libatalk/libatalk-3.0.3.abi | 566 ++++++++++++++++++++++++++++++++++++ 3 files changed, 571 insertions(+), 3 deletions(-) create mode 100644 libatalk/libatalk-3.0.3.abi diff --git a/VERSION b/VERSION index 226bf924..282895a8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.0.3dev \ No newline at end of file +3.0.3 \ No newline at end of file diff --git a/libatalk/Makefile.am b/libatalk/Makefile.am index 732aeea8..00712dda 100644 --- a/libatalk/Makefile.am +++ b/libatalk/Makefile.am @@ -18,7 +18,7 @@ # current+1:0:0 # -VERSION_INFO = 3:0:0 +VERSION_INFO = 4:0:0 # History: VERSION_INFO # @@ -30,6 +30,7 @@ VERSION_INFO = 3:0:0 # 3.0 1:0:0 # 3.0.1 2:0:0 # 3.0.2 3:0:0 +# 3.0.3 4:0:0 SUBDIRS = acl adouble bstring compat cnid dsi iniparser tdb util unicode vfs @@ -94,4 +95,5 @@ EXTRA_DIST = \ libatalk-3.0beta2.abi \ libatalk-3.0.abi \ libatalk-3.0.1.abi \ - libatalk-3.0.2.abi + libatalk-3.0.2.abi \ + libatalk-3.0.3.abi diff --git a/libatalk/libatalk-3.0.3.abi b/libatalk/libatalk-3.0.3.abi new file mode 100644 index 00000000..17e9539a --- /dev/null +++ b/libatalk/libatalk-3.0.3.abi @@ -0,0 +1,566 @@ +acl_ldap_freeconfig: void (void) +acl_ldap_readconfig: int (dictionary *) +ad_close: int (struct adouble *, int) +ad_convert: int (const char *, const struct stat *, const struct vol *, const char **) +ad_copy_header: int (struct adouble *, struct adouble *) +add_cachebyname: int (const char *, const uuidp_t, const uuidtype_t, const long unsigned int) +add_cachebyuuid: int (uuidp_t, const char *, uuidtype_t, const long unsigned int) +add_charset: charset_t (const char *) +ad_dir: char *(const char *) +ad_dtruncate: int (struct adouble *, const off_t) +adflags2logstr: const char *(int) +ad_flush: int (struct adouble *) +ad_forcegetid: uint32_t (struct adouble *) +adf_pread: ssize_t (struct ad_fd *, void *, size_t, off_t) +adf_pwrite: ssize_t (struct ad_fd *, const void *, size_t, off_t) +ad_getattr: int (const struct adouble *, uint16_t *) +ad_getdate: int (const struct adouble *, unsigned int, uint32_t *) +ad_getentryoff: off_t (const struct adouble *, int) +ad_getfuid: uid_t (void) +ad_getid: uint32_t (struct adouble *, const dev_t, const ino_t, const cnid_t, const void *) +ad_hf_mode: mode_t (mode_t) +ad_init: void (struct adouble *, const struct vol *) +ad_init_old: void (struct adouble *, int, int) +ad_lock: int (struct adouble *, uint32_t, int, off_t, off_t, int) +ad_metadata: int (const char *, int, struct adouble *) +ad_metadataat: int (int, const char *, int, struct adouble *) +ad_mkdir: int (const char *, mode_t) +ad_mode: int (const char *, mode_t) +ad_open: int (struct adouble *, const char *, int, ...) +ad_openat: int (struct adouble *, int, const char *, int, ...) +ad_openforks: uint16_t (struct adouble *, uint16_t) +ad_path: const char *(const char *, int) +ad_path_ea: const char *(const char *, int) +ad_path_osx: const char *(const char *, int) +ad_read: ssize_t (struct adouble *, const uint32_t, off_t, char *, const size_t) +ad_readfile_init: int (const struct adouble *, const int, off_t *, const int) +ad_rebuild_adouble_header_ea: int (struct adouble *) +ad_rebuild_adouble_header_v2: int (struct adouble *) +ad_refresh: int (const char *, struct adouble *) +ad_reso_size: off_t (const char *, int, struct adouble *) +ad_rtruncate: int (struct adouble *, const off_t) +ad_setattr: int (const struct adouble *, const uint16_t) +ad_setdate: int (struct adouble *, unsigned int, uint32_t) +ad_setfuid: int (const uid_t) +ad_setid: int (struct adouble *, const dev_t, const ino_t, const uint32_t, const cnid_t, const void *) +ad_setname: int (struct adouble *, const char *) +ad_size: off_t (const struct adouble *, const uint32_t) +ad_stat: int (const char *, struct stat *) +ad_testlock: int (struct adouble *, int, const off_t) +ad_tmplock: int (struct adouble *, uint32_t, int, off_t, off_t, int) +ad_unlock: void (struct adouble *, const int, int) +ad_valid_header_osx: int (const char *) +ad_write: ssize_t (struct adouble *, uint32_t, off_t, int, const char *, size_t) +afp_config_free: void (AFPObj *) +afp_config_parse: int (AFPObj *, char *) +allow_severity: 5 +apply_ip_mask: void (struct sockaddr *, int) +atalk_iconv: size_t (atalk_iconv_t, const char **, size_t *, char **, size_t *) +atalk_iconv_close: int (atalk_iconv_t) +atalk_iconv_open: atalk_iconv_t (const char *, const char *) +atalk_register_charset: int (struct charset_functions *) +balloc: int (bstring, int) +ballocmin: int (bstring, int) +basename_safe: const char *(const char *) +bassign: int (bstring, const_bstring) +bassignblk: int (bstring, const void *, int) +bassigncstr: int (bstring, const char *) +bassignformat: int (bstring, const char *, ...) +bassigngets: int (bstring, bNgetc, void *, char) +bassignmidstr: int (bstring, const_bstring, int, int) +bcatblk: int (bstring, const void *, int) +bcatcstr: int (bstring, const char *) +bconcat: int (bstring, const_bstring) +bconchar: int (bstring, char) +bcstrfree: int (char *) +bdelete: int (bstring, int, int) +bdestroy: int (bstring) +become_root: void (void) +bfindreplace: int (bstring, const_bstring, const_bstring, int) +bfindreplacecaseless: int (bstring, const_bstring, const_bstring, int) +bformat: bstring (const char *, ...) +bformata: int (bstring, const char *, ...) +bfromcstr: bstring (const char *) +bfromcstralloc: bstring (int, const char *) +bgetsa: int (bstring, bNgetc, void *, char) +bgetstream: bstring (bNgetc, void *, char) +binchr: int (const_bstring, int, const_bstring) +binchrr: int (const_bstring, int, const_bstring) +binsert: int (bstring, int, const_bstring, unsigned char) +binsertch: int (bstring, int, int, unsigned char) +binstr: int (const_bstring, int, const_bstring) +binstrcaseless: int (const_bstring, int, const_bstring) +binstrr: int (const_bstring, int, const_bstring) +binstrrcaseless: int (const_bstring, int, const_bstring) +biseq: int (const_bstring, const_bstring) +biseqcaseless: int (const_bstring, const_bstring) +biseqcstr: int (const_bstring, const char *) +biseqcstrcaseless: int (const_bstring, const char *) +bisstemeqblk: int (const_bstring, const void *, int) +bisstemeqcaselessblk: int (const_bstring, const void *, int) +bjoin: bstring (const struct bstrList *, const_bstring) +bjoinInv: bstring (const struct bstrList *, const_bstring) +blk2bstr: bstring (const void *, int) +bltrimws: int (bstring) +bmidstr: bstring (const_bstring, int, int) +bninchr: int (const_bstring, int, const_bstring) +bninchrr: int (const_bstring, int, const_bstring) +bpattern: int (bstring, int) +bread: bstring (bNread, void *) +breada: int (bstring, bNread, void *) +brefcstr: bstring (char *) +breplace: int (bstring, int, int, const_bstring, unsigned char) +brtrimws: int (bstring) +bsbufflength: int (struct bStream *, int) +bsclose: void *(struct bStream *) +bseof: int (const struct bStream *) +bsetstr: int (bstring, int, const_bstring, unsigned char) +bsopen: struct bStream *(bNread, void *) +bspeek: int (bstring, const struct bStream *) +bsplit: struct bstrList *(const_bstring, unsigned char) +bsplitcb: int (const_bstring, unsigned char, int, int (*)(void *, int, int), void *) +bsplits: struct bstrList *(const_bstring, const_bstring) +bsplitscb: int (const_bstring, const_bstring, int, int (*)(void *, int, int), void *) +bsplitstr: struct bstrList *(const_bstring, const_bstring) +bsplitstrcb: int (const_bstring, const_bstring, int, int (*)(void *, int, int), void *) +bsread: int (bstring, struct bStream *, int) +bsreada: int (bstring, struct bStream *, int) +bsreadln: int (bstring, struct bStream *, char) +bsreadlna: int (bstring, struct bStream *, char) +bsreadlns: int (bstring, struct bStream *, const_bstring) +bsreadlnsa: int (bstring, struct bStream *, const_bstring) +bssplitscb: int (struct bStream *, const_bstring, int (*)(void *, int, const_bstring), void *) +bssplitstrcb: int (struct bStream *, const_bstring, int (*)(void *, int, const_bstring), void *) +bstr2cstr: char *(const_bstring, char) +bstrchrp: int (const_bstring, int, int) +bstrcmp: int (const_bstring, const_bstring) +bstrcpy: bstring (const_bstring) +bstricmp: int (const_bstring, const_bstring) +bstrListAlloc: int (struct bstrList *, int) +bstrListAllocMin: int (struct bstrList *, int) +bstrListCreate: struct bstrList *(void) +bstrListCreateMin: struct bstrList *(int) +bstrListDestroy: int (struct bstrList *) +bstrListPop: bstring (struct bstrList *) +bstrListPush: int (struct bstrList *, bstring) +bstrncmp: int (const_bstring, const_bstring, int) +bstrnicmp: int (const_bstring, const_bstring, int) +bstrrchrp: int (const_bstring, int, int) +bsunread: int (struct bStream *, const_bstring) +btolower: int (bstring) +btoupper: int (bstring) +btrimws: int (bstring) +btrunc: int (bstring, int) +bunrefcstr: int (bstring) +bvcformata: int (bstring, int, const char *, struct __va_list_tag *) +charset_decompose: size_t (charset_t, char *, size_t, char *, size_t) +charset_mac_centraleurope: {name = "MAC_CENTRALEUROPE", kTextEncoding = 29, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0} +charset_mac_chinese_simp: {name = "MAC_CHINESE_SIMP", kTextEncoding = 25, pull = , push = , flags = 85, iname = "EUC-CN", prev = 0x0, next = 0x0} +charset_mac_chinese_trad: {name = "MAC_CHINESE_TRAD", kTextEncoding = 2, pull = , push = , flags = 85, iname = "BIG-5", prev = 0x0, next = 0x0} +charset_mac_cyrillic: {name = "MAC_CYRILLIC", kTextEncoding = 7, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0} +charset_mac_greek: {name = "MAC_GREEK", kTextEncoding = 6, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0} +charset_mac_hebrew: {name = "MAC_HEBREW", kTextEncoding = 5, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0} +charset_mac_japanese: {name = "MAC_JAPANESE", kTextEncoding = 1, pull = , push = , flags = 85, iname = "SHIFT_JIS", prev = 0x0, next = 0x0} +charset_mac_korean: {name = "MAC_KOREAN", kTextEncoding = 3, pull = , push = , flags = 85, iname = "EUC-KR", prev = 0x0, next = 0x0} +charset_mac_roman: {name = "MAC_ROMAN", kTextEncoding = 0, pull = , push = , flags = 21, iname = 0x0, prev = 0x0, next = 0x0} +charset_mac_turkish: {name = "MAC_TURKISH", kTextEncoding = 35, pull = , push = , flags = 17, iname = 0x0, prev = 0x0, next = 0x0} +charset_precompose: size_t (charset_t, char *, size_t, char *, size_t) +charset_strlower: size_t (charset_t, const char *, size_t, char *, size_t) +charset_strupper: size_t (charset_t, const char *, size_t, char *, size_t) +charset_to_ucs2_allocate: size_t (charset_t, uint16_t **, const char *) +charset_to_utf8_allocate: size_t (charset_t, char **, const char *) +charset_utf8: {name = "UTF8", kTextEncoding = 134217987, pull = , push = , flags = 22, iname = 0x0, prev = 0x0, next = 0x0} +charset_utf8_mac: {name = "UTF8-MAC", kTextEncoding = 134217987, pull = , push = , flags = 27, iname = 0x0, prev = 0x0, next = 0x0} +check_lockfile: int (const char *, const char *) +cjk_char_pull: size_t (uint16_t, uint16_t *, const uint32_t *) +cjk_char_push: size_t (uint16_t, uint8_t *) +cjk_compose: uint16_t (uint16_t, uint16_t, const uint32_t *, size_t) +cjk_compose_seq: uint16_t (const uint16_t *, size_t *, const uint32_t *, size_t) +cjk_generic_pull: size_t (size_t (*)(uint16_t *, const uint8_t *, size_t *), void *, char **, size_t *, char **, size_t *) +cjk_generic_push: size_t (size_t (*)(uint8_t *, const uint16_t *, size_t *), void *, char **, size_t *, char **, size_t *) +cjk_lookup: uint16_t (uint16_t, const cjk_index_t *, const uint16_t *) +cnid_add: cnid_t (struct _cnid_db *, const struct stat *, const cnid_t, const char *, const size_t, cnid_t) +cnid_close: void (struct _cnid_db *) +cnid_dbd_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t) +cnid_dbd_close: void (struct _cnid_db *) +cnid_dbd_delete: int (struct _cnid_db *, const cnid_t) +cnid_dbd_find: int (struct _cnid_db *, const char *, size_t, void *, size_t) +cnid_dbd_get: cnid_t (struct _cnid_db *, cnid_t, const char *, size_t) +cnid_dbd_getstamp: int (struct _cnid_db *, void *, const size_t) +cnid_dbd_lookup: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t) +cnid_dbd_module: {name = "dbd", db_list = {next = 0x0, prev = 0x0}, cnid_open = 0, flags = 0} +cnid_dbd_open: struct _cnid_db *(struct cnid_open_args *) +cnid_dbd_rebuild_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t) +cnid_dbd_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t) +cnid_dbd_update: int (struct _cnid_db *, cnid_t, const struct stat *, cnid_t, const char *, size_t) +cnid_dbd_wipe: int (struct _cnid_db *) +cnid_delete: int (struct _cnid_db *, cnid_t) +cnid_find: int (struct _cnid_db *, const char *, size_t, void *, size_t) +cnid_get: cnid_t (struct _cnid_db *, const cnid_t, char *, const size_t) +cnid_getstamp: int (struct _cnid_db *, void *, const size_t) +cnid_init: void (void) +cnid_last_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t) +cnid_last_close: void (struct _cnid_db *) +cnid_last_delete: int (struct _cnid_db *, const cnid_t) +cnid_last_get: cnid_t (struct _cnid_db *, cnid_t, const char *, size_t) +cnid_last_lookup: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t) +cnid_last_module: {name = "last", db_list = {next = 0x0, prev = 0x0}, cnid_open = 0, flags = 0} +cnid_last_open: struct _cnid_db *(struct cnid_open_args *) +cnid_last_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t) +cnid_last_update: int (struct _cnid_db *, cnid_t, const struct stat *, cnid_t, const char *, size_t) +cnid_lookup: cnid_t (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t) +cnid_open: struct _cnid_db *(const char *, mode_t, char *, int, const char *, const char *) +cnid_rebuild_add: cnid_t (struct _cnid_db *, const struct stat *, const cnid_t, char *, const size_t, cnid_t) +cnid_register: void (struct _cnid_module *) +cnid_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t) +cnid_tdb_add: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t, cnid_t) +cnid_tdb_close: void (struct _cnid_db *) +cnid_tdb_delete: int (struct _cnid_db *, const cnid_t) +cnid_tdb_get: cnid_t (struct _cnid_db *, cnid_t, const char *, size_t) +cnid_tdb_lookup: cnid_t (struct _cnid_db *, const struct stat *, cnid_t, const char *, size_t) +cnid_tdb_module: {name = "tdb", db_list = {next = 0x0, prev = 0x0}, cnid_open = 0, flags = 12} +cnid_tdb_open: struct _cnid_db *(struct cnid_open_args *) +cnid_tdb_resolve: char *(struct _cnid_db *, cnid_t *, void *, size_t) +cnid_tdb_update: int (struct _cnid_db *, cnid_t, const struct stat *, cnid_t, const char *, size_t) +cnid_update: int (struct _cnid_db *, const cnid_t, const struct stat *, const cnid_t, char *, const size_t) +cnid_wipe: int (struct _cnid_db *) +compare_ip: int (const struct sockaddr *, const struct sockaddr *) +convert_charset: size_t (charset_t, charset_t, charset_t, const char *, size_t, char *, size_t, uint16_t *) +convert_string: size_t (charset_t, charset_t, const void *, size_t, void *, size_t) +convert_string_allocate: size_t (charset_t, charset_t, const void *, size_t, char **) +copy_ea: int (const char *, int, const char *, const char *, mode_t) +copy_file: int (int, const char *, const char *, mode_t) +copy_file_fd: int (int, int) +copy_fork: int (int, struct adouble *, struct adouble *) +create_lockfile: int (const char *, const char *) +daemonize: int (int, int) +decompose_w: size_t (uint16_t *, size_t, uint16_t *, size_t *) +deny_severity: 3 +dequeue: void *(q_t *) +_diacasemap: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 231, 203, 229, 128, 204, 129, 130, 131, 233, 230, 232, 234, 237, 235, 236, 132, 238, 241, 239, 133, 205, 242, 244, 243, 134, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 198, 183, 184, 184, 186, 187, 188, 189, 174, 175, 192, 193, 194, 195, 196, 197, 198, 199...} +_dialowermap: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 138, 140, 141, 142, 150, 154, 159, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 132, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 190, 191, 176, 177, 178, 179, 180, 181, 198, 183, 185, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199...} +dictionary_del: void (dictionary *) +dictionary_dump: void (dictionary *, FILE *) +dictionary_get: const char *(const dictionary *, const char *, const char *, const char *) +dictionary_hash: unsigned int (char *) +dictionary_new: dictionary *(int) +dictionary_set: int (dictionary *, char *, char *, char *) +dictionary_unset: void (dictionary *, char *, char *) +dir_rx_set: int (mode_t) +dsi_attention: int (DSI *, AFPUserBytes) +dsi_close: void (DSI *) +dsi_cmdreply: int (DSI *, const int) +dsi_disconnect: int (DSI *) +dsi_free: void (DSI *) +dsi_getsession: int (DSI *, server_child_t *, int, afp_child_t **) +dsi_getstatus: void (DSI *) +dsi_init: DSI *(AFPObj *, const char *, const char *, const char *) +dsi_opensession: void (DSI *) +dsi_read: ssize_t (DSI *, void *, const size_t) +dsi_readdone: void (DSI *) +dsi_readinit: ssize_t (DSI *, void *, const size_t, const size_t, const int) +dsi_stream_read: size_t (DSI *, void *, const size_t) +dsi_stream_read_file: ssize_t (DSI *, const int, off_t, const size_t, const int) +dsi_stream_receive: int (DSI *) +dsi_stream_send: int (DSI *, void *, size_t) +dsi_stream_write: ssize_t (DSI *, void *, const size_t, int) +dsi_tcp_init: int (DSI *, const char *, const char *, const char *) +dsi_tickle: int (DSI *) +dsi_write: size_t (DSI *, void *, const size_t) +dsi_writeflush: void (DSI *) +dsi_writeinit: size_t (DSI *, void *, const size_t) +ea_chmod_dir: int (const struct vol *, const char *, mode_t, struct stat *) +ea_chmod_file: int (const struct vol *, const char *, mode_t, struct stat *) +ea_chown: int (const struct vol *, const char *, uid_t, gid_t) +ea_close: int (struct ea *) +ea_copyfile: int (const struct vol *, int, const char *, const char *) +ea_deletefile: int (const struct vol *, int, const char *) +ea_open: int (const struct vol *, const char *, eaflags_t, struct ea *) +ea_openat: int (const struct vol *, int, const char *, eaflags_t, struct ea *) +ea_path: char *(const struct ea *, const char *, int) +ea_renamefile: int (const struct vol *, int, const char *, const char *) +enqueue: qnode_t *(q_t *, void *) +fault_setup: void (void (*)(void *)) +fdset_add_fd: void (int, struct pollfd **, struct polldata **, int *, int *, int, enum fdtype, void *) +fdset_del_fd: void (struct pollfd **, struct polldata **, int *, int *, int) +find_charset_functions: struct charset_functions *(const char *) +_fini: +free_charset_names: void (void) +freeifacelist: void (char **) +fullpathname: const char *(const char *) +getcwdpath: const char *(void) +getdefextmap: struct extmap *(void) +get_eacontent: int (const struct vol *, char *, size_t *, const char *, int, const char *, int) +get_easize: int (const struct vol *, char *, size_t *, const char *, int, const char *) +getextmap: struct extmap *(const char *) +getifacelist: char **(void) +getip_port: unsigned int (const struct sockaddr *) +getip_string: const char *(const struct sockaddr *) +getnamefromuuid: int (const uuidp_t, char **, uuidtype_t *) +getuuidfromname: int (const char *, uuidtype_t, unsigned char *) +getvolbyname: struct vol *(const char *) +getvolbypath: struct vol *(AFPObj *, const char *) +getvolbyvid: struct vol *(const uint16_t) +getvolumes: struct vol *(void) +gmem: int (gid_t, int, gid_t *) +iniparser_dump: void (const dictionary *, FILE *) +iniparser_dump_ini: void (const dictionary *, FILE *) +iniparser_find_entry: int (const dictionary *, const char *) +iniparser_freedict: void (dictionary *) +iniparser_getboolean: int (const dictionary *, const char *, const char *, int) +iniparser_getdouble: double (const dictionary *, const char *, const char *, double) +iniparser_getint: int (const dictionary *, const char *, const char *, int) +iniparser_getnsec: int (const dictionary *) +iniparser_getsecname: const char *(const dictionary *, int) +iniparser_getstrdup: char *(const dictionary *, const char *, const char *, const char *) +iniparser_getstring: const char *(const dictionary *, const char *, const char *, const char *) +iniparser_load: dictionary *(const char *) +iniparser_set: int (dictionary *, char *, char *, char *) +iniparser_unset: void (dictionary *, char *, char *) +_init: +init_iconv: void (void) +initline: void (int, char *) +initvol_vfs: void (struct vol *) +ipc_child_state: int (AFPObj *, uint16_t) +ipc_child_write: int (int, uint16_t, int, void *) +ipc_server_read: int (server_child_t *, int) +islower_sp: int (uint32_t) +islower_w: int (uint16_t) +isupper_sp: int (uint32_t) +isupper_w: int (uint16_t) +ldap_auth_dn: 0x0 +ldap_auth_method: 0 +ldap_auth_pw: 0x0 +ldap_config_valid: 0 +ldap_getnamefromuuid: int (const char *, char **, uuidtype_t *) +ldap_getuuidfromname: int (const char *, uuidtype_t, char **) +ldap_group_attr: 0x0 +ldap_groupbase: 0x0 +ldap_groupscope: 0 +ldap_name_attr: 0x0 +ldap_prefs: {{pref = 0x0, name = "ldap server", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap auth method", strorint = 1, intfromarray = 1, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap auth dn", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap auth pw", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap userbase", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap userscope", strorint = 1, intfromarray = 1, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap groupbase", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap groupscope", strorint = 1, intfromarray = 1, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap uuid attr", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap uuid string", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap name attr", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap group attr", strorint = 0, intfromarray = 0, valid = -1, valid_save = -1}, {pref = 0x0, name = "ldap uid attr", strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}, {pref = 0x0, name = "ldap uuid encoding", strorint = 1, intfromarray = 1, valid = 0, valid_save = 0}, {pref = 0x0, name = 0x0, strorint = 0, intfromarray = 0, valid = 0, valid_save = 0}} +ldap_server: 0x0 +ldap_uid_attr: 0x0 +ldap_userbase: 0x0 +ldap_userscope: 0 +ldap_uuid_attr: 0x0 +ldap_uuid_encoding: 0 +ldap_uuid_string: 0x0 +list_eas: int (const struct vol *, char *, size_t *, const char *, int) +load_charset: int (struct vol *) +load_volumes: int (AFPObj *) +localuuid_from_id: void (unsigned char *, uuidtype_t, unsigned int) +lock_reg: int (int, int, int, off_t, int, off_t) +log_config: {inited = false, syslog_opened = false, console = false, processname = '\0' , syslog_facility = 0, syslog_display_options = 0} +make_log_entry: void (enum loglevels, enum logtypes, const char *, int, char *, ...) +make_tdb_data: unsigned char *(uint32_t, const struct stat *, const cnid_t, const char *, const size_t) +mb_generic_pull: size_t (int (*)(uint16_t *, const unsigned char *), void *, char **, size_t *, char **, size_t *) +mb_generic_push: size_t (int (*)(unsigned char *, uint16_t), void *, char **, size_t *, char **, size_t *) +netatalk_panic: void (const char *) +netatalk_rmdir: int (int, const char *) +netatalk_rmdir_all_errors: int (int, const char *) +netatalk_unlink: int (const char *) +netatalk_unlinkat: int (int, const char *) +nftw: int (const char *, nftw_func_t, dir_notification_func_t, int, int) +ochdir: int (const char *, int) +ochmod: int (char *, mode_t, const struct stat *, int) +ochown: int (const char *, uid_t, gid_t, int) +opendirat: DIR *(int, const char *) +openflags2logstr: const char *(int) +ostat: int (const char *, struct stat *, int) +ostatat: int (int, const char *, struct stat *, int) +parseline: int (int, char *) +posix_chmod: int (const char *, mode_t) +posix_fchmod: int (int, mode_t) +precompose_w: size_t (uint16_t *, size_t, uint16_t *, size_t *) +prefs_array: {{pref = "ldap auth method", valuestring = "none", value = 0}, {pref = "ldap auth method", valuestring = "simple", value = 128}, {pref = "ldap auth method", valuestring = "sasl", value = 163}, {pref = "ldap userscope", valuestring = "base", value = 0}, {pref = "ldap userscope", valuestring = "one", value = 1}, {pref = "ldap userscope", valuestring = "sub", value = 2}, {pref = "ldap groupscope", valuestring = "base", value = 0}, {pref = "ldap groupscope", valuestring = "one", value = 1}, {pref = "ldap groupscope", valuestring = "sub", value = 2}, {pref = "ldap uuid encoding", valuestring = "ms-guid", value = 1}, {pref = "ldap uuid encoding", valuestring = "string", value = 0}, {pref = 0x0, valuestring = 0x0, value = 0}} +prequeue: qnode_t *(q_t *, void *) +print_groups: const char *(int, gid_t *) +queue_destroy: void (q_t *, void (*)(void *)) +queue_init: q_t *(void) +randombytes: void (void *, int) +readt: ssize_t (int, void *, const size_t, int, int) +realpath_safe: char *(const char *) +recv_fd: int (int, int) +rel_path_in_vol: bstring (const char *, const char *) +remove_acl_vfs: int (const char *) +remove_ea: int (const struct vol *, const char *, const char *, int) +run_cmd: int (const char *, char **) +search_cachebyname: int (const char *, uuidtype_t *, unsigned char *) +search_cachebyuuid: int (uuidp_t, char **, uuidtype_t *) +send_fd: int (int, int) +server_child_add: afp_child_t *(server_child_t *, pid_t, int) +server_child_alloc: server_child_t *(int) +server_child_free: void (server_child_t *) +server_child_kill: void (server_child_t *, int) +server_child_kill_one_by_id: void (server_child_t *, pid_t, uid_t, uint32_t, char *, uint32_t) +server_child_remove: int (server_child_t *, pid_t) +server_child_resolve: afp_child_t *(server_child_t *, id_t) +server_child_transfer_session: int (server_child_t *, pid_t, uid_t, int, uint16_t) +server_lock: pid_t (char *, char *, int) +server_reset_signal: void (void) +set_charset_name: int (charset_t, const char *) +set_ea: int (const struct vol *, const char *, const char *, const char *, size_t, int) +setfilmode: int (const struct vol *, const char *, mode_t, struct stat *) +set_groups: int (AFPObj *, struct passwd *) +setnonblock: int (int, int) +set_processname: void (const char *) +setuplog: void (const char *, const char *) +statat: int (int, const char *, struct stat *) +strcasechr_sp: uint16_t *(const uint16_t *, uint32_t) +strcasechr_w: uint16_t *(const uint16_t *, uint16_t) +strcasecmp_w: int (const uint16_t *, const uint16_t *) +strcasestr_w: uint16_t *(const uint16_t *, const uint16_t *) +strcat_w: uint16_t *(uint16_t *, const uint16_t *) +strchr_w: uint16_t *(const uint16_t *, uint16_t) +strcmp_w: int (const uint16_t *, const uint16_t *) +strdiacasecmp: int (const char *, const char *) +strdup_w: uint16_t *(const uint16_t *) +stripped_slashes_basename: char *(char *) +strlcat: size_t (char *, const char *, size_t) +strlcpy: size_t (char *, const char *, size_t) +strlen_w: size_t (const uint16_t *) +strlower_w: int (uint16_t *) +strncasecmp_w: int (const uint16_t *, const uint16_t *, size_t) +strncat_w: uint16_t *(uint16_t *, const uint16_t *, const size_t) +strncmp_w: int (const uint16_t *, const uint16_t *, size_t) +strncpy_w: uint16_t *(uint16_t *, const uint16_t *, const size_t) +strndiacasecmp: int (const char *, const char *, size_t) +strndup_w: uint16_t *(const uint16_t *, size_t) +strnlen_w: size_t (const uint16_t *, size_t) +strstr_w: uint16_t *(const uint16_t *, const uint16_t *) +strtok_quote: char *(char *, const char *) +strupper_w: int (uint16_t *) +sys_ea_copyfile: int (const struct vol *, int, const char *, const char *) +sys_fgetxattr: ssize_t (int, const char *, void *, size_t) +sys_fsetxattr: int (int, const char *, const void *, size_t, int) +sys_ftruncate: int (int, off_t) +sys_get_eacontent: int (const struct vol *, char *, size_t *, const char *, int, const char *, int) +sys_get_easize: int (const struct vol *, char *, size_t *, const char *, int, const char *) +sys_getxattr: ssize_t (const char *, const char *, void *, size_t) +sys_getxattrfd: int (int, const char *, int, ...) +sys_lgetxattr: ssize_t (const char *, const char *, void *, size_t) +sys_list_eas: int (const struct vol *, char *, size_t *, const char *, int) +sys_listxattr: ssize_t (const char *, char *, size_t) +sys_llistxattr: ssize_t (const char *, char *, size_t) +sys_lremovexattr: int (const char *, const char *) +sys_lsetxattr: int (const char *, const char *, const void *, size_t, int) +sys_remove_ea: int (const struct vol *, const char *, const char *, int) +sys_removexattr: int (const char *, const char *) +sys_sendfile: ssize_t (int, int, off_t *, size_t) +sys_set_ea: int (const struct vol *, const char *, const char *, const char *, size_t, int) +sys_setxattr: int (const char *, const char *, const void *, size_t, int) +tdb_add_flags: void (struct tdb_context *, unsigned int) +tdb_allocate: tdb_off_t (struct tdb_context *, tdb_len_t, struct tdb_record *) +tdb_alloc_read: unsigned char *(struct tdb_context *, tdb_off_t, tdb_len_t) +tdb_append: int (struct tdb_context *, TDB_DATA, TDB_DATA) +tdb_brlock: int (struct tdb_context *, tdb_off_t, int, int, int, size_t) +tdb_brlock_upgrade: int (struct tdb_context *, tdb_off_t, size_t) +tdb_chainlock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_mark: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_nonblock: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_read: int (struct tdb_context *, TDB_DATA) +tdb_chainlock_unmark: int (struct tdb_context *, TDB_DATA) +tdb_chainunlock: int (struct tdb_context *, TDB_DATA) +tdb_chainunlock_read: int (struct tdb_context *, TDB_DATA) +tdb_check: int (struct tdb_context *, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_close: int (struct tdb_context *) +tdb_convert: void *(void *, uint32_t) +tdb_delete: int (struct tdb_context *, TDB_DATA) +tdb_do_delete: int (struct tdb_context *, tdb_off_t, struct tdb_record *) +tdb_dump_all: void (struct tdb_context *) +tdb_enable_seqnum: void (struct tdb_context *) +tdb_error: enum TDB_ERROR (struct tdb_context *) +tdb_errorstr: const char *(struct tdb_context *) +tdb_exists: int (struct tdb_context *, TDB_DATA) +tdb_expand: int (struct tdb_context *, tdb_off_t) +tdb_fd: int (struct tdb_context *) +tdb_fetch: TDB_DATA (struct tdb_context *, TDB_DATA) +tdb_find_lock_hash: tdb_off_t (struct tdb_context *, TDB_DATA, uint32_t, int, struct tdb_record *) +tdb_firstkey: TDB_DATA (struct tdb_context *) +tdb_free: int (struct tdb_context *, tdb_off_t, struct tdb_record *) +tdb_freelist_size: int (struct tdb_context *) +tdb_get_flags: int (struct tdb_context *) +tdb_get_logging_private: void *(struct tdb_context *) +tdb_get_seqnum: int (struct tdb_context *) +tdb_hash_size: int (struct tdb_context *) +tdb_increment_seqnum_nonblock: void (struct tdb_context *) +tdb_io_init: void (struct tdb_context *) +tdb_lock: int (struct tdb_context *, int, int) +tdb_lockall: int (struct tdb_context *) +tdb_lockall_mark: int (struct tdb_context *) +tdb_lockall_nonblock: int (struct tdb_context *) +tdb_lockall_read: int (struct tdb_context *) +tdb_lockall_read_nonblock: int (struct tdb_context *) +tdb_lockall_unmark: int (struct tdb_context *) +tdb_lock_nonblock: int (struct tdb_context *, int, int) +tdb_lock_record: int (struct tdb_context *, tdb_off_t) +tdb_log_fn: tdb_log_func (struct tdb_context *) +tdb_map_size: size_t (struct tdb_context *) +tdb_mmap: void (struct tdb_context *) +tdb_munmap: int (struct tdb_context *) +tdb_name: const char *(struct tdb_context *) +tdb_nextkey: TDB_DATA (struct tdb_context *, TDB_DATA) +tdb_null: {dptr = 0x0, dsize = 0} +tdb_ofs_read: int (struct tdb_context *, tdb_off_t, tdb_off_t *) +tdb_ofs_write: int (struct tdb_context *, tdb_off_t, tdb_off_t *) +tdb_open: struct tdb_context *(const char *, int, int, int, mode_t) +tdb_open_ex: struct tdb_context *(const char *, int, int, int, mode_t, const struct tdb_logging_context *, tdb_hash_func) +tdb_parse_data: int (struct tdb_context *, TDB_DATA, tdb_off_t, tdb_len_t, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_parse_record: int (struct tdb_context *, TDB_DATA, int (*)(TDB_DATA, TDB_DATA, void *), void *) +tdb_printfreelist: int (struct tdb_context *) +tdb_rec_free_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *) +tdb_rec_read: int (struct tdb_context *, tdb_off_t, struct tdb_record *) +tdb_rec_write: int (struct tdb_context *, tdb_off_t, struct tdb_record *) +tdb_remove_flags: void (struct tdb_context *, unsigned int) +tdb_reopen: int (struct tdb_context *) +tdb_reopen_all: int (int) +tdb_repack: int (struct tdb_context *) +tdb_setalarm_sigptr: void (struct tdb_context *, volatile sig_atomic_t *) +tdb_set_logging_function: void (struct tdb_context *, const struct tdb_logging_context *) +tdb_set_max_dead: void (struct tdb_context *, int) +tdb_store: int (struct tdb_context *, TDB_DATA, TDB_DATA, int) +_tdb_transaction_cancel: int (struct tdb_context *) +tdb_transaction_cancel: int (struct tdb_context *) +tdb_transaction_commit: int (struct tdb_context *) +tdb_transaction_lock: int (struct tdb_context *, int) +tdb_transaction_prepare_commit: int (struct tdb_context *) +tdb_transaction_recover: int (struct tdb_context *) +tdb_transaction_start: int (struct tdb_context *) +tdb_transaction_unlock: int (struct tdb_context *) +tdb_traverse: int (struct tdb_context *, tdb_traverse_func, void *) +tdb_traverse_read: int (struct tdb_context *, tdb_traverse_func, void *) +tdb_unlock: int (struct tdb_context *, int, int) +tdb_unlockall: int (struct tdb_context *) +tdb_unlockall_read: int (struct tdb_context *) +tdb_unlock_record: int (struct tdb_context *, tdb_off_t) +tdb_validate_freelist: int (struct tdb_context *, int *) +tdb_wipe_all: int (struct tdb_context *) +tdb_write_lock_record: int (struct tdb_context *, tdb_off_t) +tdb_write_unlock_record: int (struct tdb_context *, tdb_off_t) +tolower_sp: uint32_t (uint32_t) +tolower_w: uint16_t (uint16_t) +toupper_sp: uint32_t (uint32_t) +toupper_w: uint16_t (uint16_t) +type_configs: {{set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}, {set = false, syslog = false, fd = -1, level = log_none, display_options = 0}} +ucs2_to_charset: size_t (charset_t, const uint16_t *, char *, size_t) +ucs2_to_charset_allocate: size_t (charset_t, char **, const uint16_t *) +unbecome_root: void (void) +unix_rename: int (int, const char *, int, const char *) +unix_strlower: size_t (const char *, size_t, char *, size_t) +unix_strupper: size_t (const char *, size_t, char *, size_t) +unload_volumes: void (AFPObj *) +utf8_charlen: size_t (char *) +utf8_decompose: size_t (char *, size_t, char *, size_t) +utf8_precompose: size_t (char *, size_t, char *, size_t) +utf8_strlen_validate: size_t (char *) +utf8_strlower: size_t (const char *, size_t, char *, size_t) +utf8_strupper: size_t (const char *, size_t, char *, size_t) +utf8_to_charset_allocate: size_t (charset_t, char **, const char *) +uuid_bin2string: const char *(const unsigned char *) +uuidcache_dump: void (void) +uuid_string2bin: void (const char *, unsigned char *) +uuidtype: {"", "USER", "GROUP", "LOCAL"} +volume_free: void (struct vol *) +volume_unlink: void (struct vol *) +writet: ssize_t (int, void *, const size_t, int, int)