From f0c9b5ff7f303bea73622a97a5d66407c2fbec97 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Sat, 26 Jun 2010 11:39:12 +0200 Subject: [PATCH] autogenerate UUIDs for TM volumes and store em in afp_voluuid.conf --- bin/misc/uuidtest.c | 2 +- configure.in | 8 +++ etc/afpd/Makefile.am | 1 + etc/afpd/acls.c | 2 +- etc/afpd/acls.h | 4 +- etc/afpd/afp_options.c | 1 + etc/afpd/auth.c | 2 +- etc/afpd/globals.h | 1 + etc/afpd/volume.c | 135 ++++++++++++++++++++++++++++++++----- etc/afpd/volume.h | 1 + include/atalk/uuid.h | 2 +- libatalk/acl/cache.c | 2 +- libatalk/adouble/ad_open.c | 6 +- 13 files changed, 140 insertions(+), 27 deletions(-) diff --git a/bin/misc/uuidtest.c b/bin/misc/uuidtest.c index 826d3d91..524e25b7 100644 --- a/bin/misc/uuidtest.c +++ b/bin/misc/uuidtest.c @@ -68,7 +68,7 @@ int main( int argc, char **argv) { int ret, i, c; int verbose = 0; - uuid_t uuid; + atalk_uuid_t uuid; uuidtype_t type; char *uuidstring = NULL; char *name = NULL; diff --git a/configure.in b/configure.in index 4222a222..a8fbc9c3 100644 --- a/configure.in +++ b/configure.in @@ -1283,6 +1283,14 @@ fi dnl --------------------- Netatalk Webmin NETATALK_WEBMIN +dnl --------------------- Check for libuuid which is required for TimeMachine +AC_SEARCH_LIBS([uuid_generate], + [uuid], , + AC_MSG_ERROR([missing library libuuid required for TimeMachine])) +AC_CHECK_HEADER([uuid/uuid.h], + AC_DEFINE([HAVE_UUID], 1, [have libuuid]), + AC_MSG_ERROR([missing header from libuuid required for TimeMachine])) + dnl --------------------- last minute substitutions AC_SUBST(LIBS) diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index f539d899..d08b8702 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -25,6 +25,7 @@ afpd_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sys \ -D_PATH_AFPDSIGCONF=\"$(pkgconfdir)/afp_signature.conf\" \ -D_PATH_AFPDUAMPATH=\"$(UAMS_PATH)/\" \ -D_PATH_ACL_LDAPCONF=\"$(pkgconfdir)/afp_ldap.conf\" \ + -D_PATH_AFPDUUIDCONF=\"$(pkgconfdir)/afp_voluuid.conf\" \ -DAPPLCNAME \ -DSERVERTEXT=\"$(SERVERTEXT)/\" diff --git a/etc/afpd/acls.c b/etc/afpd/acls.c index 2f5b49b8..1ab8b7e3 100644 --- a/etc/afpd/acls.c +++ b/etc/afpd/acls.c @@ -1233,7 +1233,7 @@ int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size void acltoownermode(char *path, struct stat *st, uid_t uid, struct maccess *ma) { struct passwd *pw; - uuid_t uuid; + atalk_uuid_t uuid; int r_ok, w_ok, x_ok; if ( ! (AFPobj->options.flags & OPTION_UUID) || ! (AFPobj->options.flags & OPTION_ACL2OS9MODE)) diff --git a/etc/afpd/acls.h b/etc/afpd/acls.h index 4965c56b..fb0792c3 100644 --- a/etc/afpd/acls.h +++ b/etc/afpd/acls.h @@ -19,7 +19,7 @@ #include #endif -#include /* for uuid_t */ +#include /* for atalk_uuid_t */ /* * This is what Apple says about ACL flags in sys/kauth.h: @@ -93,7 +93,7 @@ enum { /* Access Control List Entry (ACE) */ typedef struct { - uuid_t darwin_ace_uuid; + atalk_uuid_t darwin_ace_uuid; uint32_t darwin_ace_flags; uint32_t darwin_ace_rights; } darwin_ace_t; diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index 92b74542..8c329972 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -165,6 +165,7 @@ void afp_options_init(struct afp_options *options) options->systemvol.name = _PATH_AFPDSYSVOL; options->configfile = _PATH_AFPDCONF; options->sigconffile = _PATH_AFPDSIGCONF; + options->uuidconf = _PATH_AFPDUUIDCONF; options->uampath = _PATH_AFPDUAMPATH; options->uamlist = "uams_dhx.so,uams_dhx2.so"; options->guest = "nobody"; diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index 13fade67..8dc59ec2 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -1002,7 +1002,7 @@ int afp_getuserinfo(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, #ifdef HAVE_ACLS if (bitmap & USERIBIT_UUID) { int ret; - uuid_t uuid; + atalk_uuid_t uuid; char *uuidstring; if ( ! (obj->options.flags & OPTION_UUID)) diff --git a/etc/afpd/globals.h b/etc/afpd/globals.h index b604cf22..5fbb048b 100644 --- a/etc/afpd/globals.h +++ b/etc/afpd/globals.h @@ -64,6 +64,7 @@ struct afp_options { char *uampath, *fqdn; char *pidfile; char *sigconffile; + char *uuidconf; struct afp_volume_name defaultvol, systemvol, uservol; int closevol; diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index c2c18f2f..cfa2ea0a 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -35,6 +35,9 @@ char *strchr (), *strrchr (); #include #include #include + +#include + #include #include #include @@ -119,9 +122,8 @@ static void free_extmap(void); #define VOLOPT_EA_VFS 27 /* Extended Attributes vfs indirection */ #define VOLOPT_CNIDSERVER 28 /* CNID Server ip address*/ #define VOLOPT_CNIDPORT 30 /* CNID server tcp port */ -#define VOLOPT_UUID 31 /* CNID server tcp port */ -#define VOLOPT_MAX 32 /* <== IMPORTANT !!!!!! */ +#define VOLOPT_MAX 31 /* <== IMPORTANT !!!!!! */ #define VOLOPT_NUM (VOLOPT_MAX + 1) #define VOLPASSLEN 8 @@ -569,9 +571,6 @@ static void volset(struct vol_option *options, struct vol_option *save, } else if (optionok(tmp, "volsizelimit:", val)) { options[VOLOPT_LIMITSIZE].i_value = (uint32_t)strtoul(val + 1, NULL, 10); - } else if (optionok(tmp, "uuid:", val)) { - setoption(options, save, VOLOPT_UUID, val); - } else { /* ignore unknown options */ LOG(log_debug, logtype_afpd, "ignoring unknown volume option: %s", tmp); @@ -793,9 +792,6 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, if (options[VOLOPT_LIMITSIZE].i_value) volume->v_limitsize = options[VOLOPT_LIMITSIZE].i_value; - if (options[VOLOPT_UUID].c_value) - volume->v_uuid = strdup(options[VOLOPT_UUID].c_value); - /* Mac to Unix conversion flags*/ volume->v_mtou_flags = 0; if (!(volume->v_flags & AFPVOL_NOHEX)) @@ -857,6 +853,20 @@ static int creatvol(AFPObj *obj, struct passwd *pwd, check_ea_sys_support(volume); initvol_vfs(volume); + /* get/store uuid from file */ + if (volume->v_flags & AFPVOL_TM) { + char *uuid = get_uuid(obj, volume->v_localname); + if (!uuid) { + LOG(log_error, logtype_afpd, "Volume '%s': couldn't get UUID, disabling TM support", + volume->v_localname); + volume->v_flags &= ~AFPVOL_TM; + } else { + volume->v_uuid = uuid; + LOG(log_debug, logtype_afpd, "Volume '%s': UUID '%s'", + volume->v_localname, volume->v_uuid); + } + } + volume->v_next = Volumes; Volumes = volume; return 0; @@ -1317,6 +1327,8 @@ static void volume_free(struct vol *vol) free(vol->v_forceuid); free(vol->v_forcegid); #endif /* FORCE_UIDGID */ + if (vol->v_uuid) + free(vol->v_uuid); } /* ------------------------------- */ @@ -1747,7 +1759,7 @@ void load_volumes(AFPObj *obj) if ( obj->options.flags & OPTION_USERVOLFIRST ) { readvolfile(obj, &obj->options.systemvol, NULL, 0, pwent ); } - + if ( obj->options.closevol ) { struct vol *vol; @@ -1889,7 +1901,7 @@ static int volume_openDB(struct vol *volume) LOG(log_info, logtype_afpd, "CNID server: %s:%s", volume->v_cnidserver ? volume->v_cnidserver : Cnid_srv, volume->v_cnidport ? volume->v_cnidport : Cnid_port); - + #if 0 /* Found this in branch dir-rewrite, maybe we want to use it sometimes */ @@ -1942,11 +1954,11 @@ static int volume_openDB(struct vol *volume) return (!volume->v_cdb)?-1:0; } -/* - Check if the underlying filesystem supports EAs for ea:sys volumes. - If not, switch to ea:ad. - As we can't check (requires write access) on ro-volumes, we switch ea:auto - volumes that are options:ro to ea:none. +/* + Check if the underlying filesystem supports EAs for ea:sys volumes. + If not, switch to ea:ad. + As we can't check (requires write access) on ro-volumes, we switch ea:auto + volumes that are options:ro to ea:none. */ static void check_ea_sys_support(struct vol *vol) { @@ -2111,7 +2123,7 @@ int afp_openvol(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t if ((tmp = strdup(volume->v_path)) == NULL) { free(volume->v_path); return AFPERR_MISC; - } + } free(volume->v_path); volume->v_path = tmp; #endif @@ -2578,7 +2590,7 @@ static int create_special_folder (const struct vol *vol, const struct _special_f free(q); return (-1); } - + ad_setname(&ad, folder->name); ad_getattr(&ad, &attr); @@ -2623,3 +2635,92 @@ void unload_volumes_and_extmap(void) free_extmap(); free_volumes(); } + +/* + * Get a volumes UUID from the config file. + * If there is none, it is generated and stored there. + * + * Returns pointer to allocated storage on success, NULL on error. + */ +char *get_uuid(const AFPObj *obj, const char *volname) +{ + struct stat st; + + char *usersign; + int fd, i; + struct stat tmpstat; + char *volname_conf; + int header = 0; + char buf[1024], uuid[UUID_PRINTABLE_STRING_LENGTH], *p; + FILE *fp, *randomp; + size_t len; + + if ((fp = fopen(obj->options.uuidconf, "r")) != NULL) { /* read open? */ + /* scan in the conf file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + p = buf; + while (p && isblank(*p)) + p++; + if (!p || (*p == '#') || (*p == '\n')) + continue; /* invalid line */ + if (*p == '"') { + p++; + if ((volname_conf = strtok( p, "\"" )) == NULL) + continue; /* syntax error */ + } else { + if ((volname_conf = strtok( p, " \t" )) == NULL) + continue; /* syntax error: invalid name */ + } + p = strchr(p, '\0'); + p++; + if (*p == '\0') + continue; /* syntax error */ + + if (strcmp(volname, volname_conf) != 0) + continue; /* another volume name */ + + while (p && isblank(*p)) + p++; + + if (sscanf(p, "%36s", uuid) == 1 ) { + LOG(log_debug, logtype_afpd, "get_uuid('%s'): UUID: '%s'", volname, uuid); + fclose(fp); + return strdup(uuid); + } + } + } + + if (fp) + fclose(fp); + + /* not found or no file, reopen in append mode */ + if ((fp = fopen(obj->options.uuidconf, "a+")) == NULL) { + LOG(log_error, logtype_afpd, "Cannot create or append to %s (%s).", + obj->options.uuidconf, strerror(errno)); + return NULL; + } + fseek(fp, 0L, SEEK_END); + if(ftell(fp) == 0) { /* size = 0 */ + fprintf(fp, "# DON'T TOUCH NOR COPY THOUGHTLESSLY!\n"); + fprintf(fp, "# This file is auto-generated by afpd.\n"); + fprintf(fp, "# \n"); + fprintf(fp, "# This file stores UUIDs for all volumes, either auto-generated ones\n"); + fprintf(fp, "# or the value from AppleVolumes.default:uuid\n"); + fprintf(fp, "# \n"); + fprintf(fp, "# If both values differ, the one from AppleVolumes.default is used.\n\n"); + } else { + fseek(fp, -1L, SEEK_END); + if(fgetc(fp) != '\n') fputc('\n', fp); /* last char is \n? */ + } + + /* generate uuid and write to file */ + uuid_t id; + uuid_generate(id); + uuid_unparse(id, uuid); + LOG(log_debug, logtype_afpd, "get_uuid('%s'): generated UUID '%s'", volname, uuid); + + fprintf(fp, "\"%s\"\t%36s\n", volname, uuid); + fclose(fp); + + return strdup(uuid); +} diff --git a/etc/afpd/volume.h b/etc/afpd/volume.h index 58dae44d..7402a9a4 100644 --- a/etc/afpd/volume.h +++ b/etc/afpd/volume.h @@ -35,6 +35,7 @@ extern int readvolfile(AFPObj *obj, struct passwd *pwent); extern const struct vol *getvolumes(void); extern void unload_volumes_and_extmap(void); +extern char *get_uuid(const AFPObj *obj, const char *volname); /* FP functions */ int afp_openvol (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen); diff --git a/include/atalk/uuid.h b/include/atalk/uuid.h index 30c14ebf..2c2d502f 100644 --- a/include/atalk/uuid.h +++ b/include/atalk/uuid.h @@ -20,7 +20,7 @@ #define UUID_STRINGSIZE 36 typedef char *uuidp_t; -typedef char uuid_t[UUID_BINSIZE]; +typedef char atalk_uuid_t[UUID_BINSIZE]; typedef enum {UUID_USER = 1, UUID_GROUP} uuidtype_t; extern char *uuidtype[]; diff --git a/libatalk/acl/cache.c b/libatalk/acl/cache.c index 3b3a888f..538ff33d 100644 --- a/libatalk/acl/cache.c +++ b/libatalk/acl/cache.c @@ -103,7 +103,7 @@ static unsigned char hashstring(unsigned char *str) { return index; } -/* hash uuid_t into unsigned char */ +/* hash atalk_uuid_t into unsigned char */ static unsigned char hashuuid(uuidp_t uuid) { unsigned char index = 83; int i; diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index 90d3e362..cf957c6c 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1080,8 +1080,8 @@ ad_mkdir( const char *path, int mode) int st_invalid; struct stat stbuf; - LOG(log_debug, logtype_default, "ad_mkdir: creating ad-directory '%s/%s' with mode %04o", - getcwdpath(), path, mode); + LOG(log_debug, logtype_default, "ad_mkdir: creating ad-directory '%s' with mode %04o", + path, mode); st_invalid = ad_mode_st(path, &mode, &stbuf); ret = mkdir( path, mode ); @@ -1383,7 +1383,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble * here. * if ((oflags & O_CREAT) ==> (oflags & O_RDWR) */ - LOG(log_debug, logtype_default, "ad_open: creating new adouble file: %s/%s", getcwdpath(), ad_p); + LOG(log_debug, logtype_default, "ad_open: creating new adouble file: %s", ad_p); admode = mode; errno = 0; st_invalid = ad_mode_st(ad_p, &admode, &st_dir); -- 2.39.2