1/* 2 * Copyright (c) 2009 Frank Lahm <franklahm@gmail.com> 3 * Copyright (c) 1991, 1993, 1994 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#ifdef HAVE_CONFIG_H 32#include "config.h" 33#endif /* HAVE_CONFIG_H */ 34 35#include <sys/types.h> 36#include <sys/param.h> 37#include <sys/stat.h> 38#include <sys/mman.h> 39 40#include <errno.h> 41#include <fcntl.h> 42#include <limits.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <sysexits.h> 46#include <unistd.h> 47#include <stdarg.h> 48#include <string.h> 49#include <libgen.h> 50 51#ifdef HAVE_SOLARIS_ACLS 52#include <sys/acl.h> 53#endif /* HAVE_SOLARIS_ACLS */ 54 55#ifdef HAVE_POSIX_ACLS 56#include <sys/types.h> 57#include <sys/acl.h> 58#endif /* HAVE_POSIX_ACLS */ 59 60#include <atalk/util.h> 61#include <atalk/cnid.h> 62#include <atalk/volinfo.h> 63#include <atalk/bstrlib.h> 64#include <atalk/bstradd.h> 65#include <atalk/logger.h> 66#include <atalk/errchk.h> 67#include <atalk/unicode.h> 68 69#include "ad.h" 70 71int log_verbose; /* Logging flag */ 72 73void _log(enum logtype lt, char *fmt, ...) 74{ 75 int len; 76 static char logbuffer[1024]; 77 va_list args; 78 79 if ( (lt == STD) || (log_verbose == 1)) { 80 va_start(args, fmt); 81 len = vsnprintf(logbuffer, 1023, fmt, args); 82 va_end(args); 83 logbuffer[1023] = 0; 84 85 printf("%s\n", logbuffer); 86 } 87} 88 89/*! 90 * Load volinfo and initialize struct vol 91 * 92 * Only opens "dbd" volumes ! 93 * 94 * @param path (r) path to evaluate 95 * @param vol (rw) structure to initialize 96 * 97 * @returns 0 on success, exits on error 98 */ 99int openvol(const char *path, afpvol_t *vol) 100{ 101 int flags = 0; 102 103 memset(vol, 0, sizeof(afpvol_t)); 104 105 /* try to find a .AppleDesktop/.volinfo */ 106 if (loadvolinfo((char *)path, &vol->volinfo) != 0) 107 return -1; 108 109 if (STRCMP(vol->volinfo.v_cnidscheme, != , "dbd")) 110 ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->volinfo.v_path); 111 112 if (vol_load_charsets(&vol->volinfo) == -1) 113 ERROR("Error loading charsets!"); 114 115 /* Sanity checks to ensure we can touch this volume */ 116 if (vol->volinfo.v_adouble != AD_VERSION2) 117 ERROR("Unsupported adouble versions: %u", vol->volinfo.v_adouble); 118 119 if (vol->volinfo.v_vfs_ea != AFPVOL_EA_SYS) 120 ERROR("Unsupported Extended Attributes option: %u", vol->volinfo.v_vfs_ea); 121 122 /* initialize sufficient struct vol for VFS initialisation */ 123 vol->volume.v_adouble = AD_VERSION2; 124 vol->volume.v_vfs_ea = AFPVOL_EA_SYS; 125 initvol_vfs(&vol->volume); 126 127 if ((vol->volinfo.v_flags & AFPVOL_NODEV)) 128 flags |= CNID_FLAG_NODEV; 129 130 if ((vol->volume.v_cdb = cnid_open(vol->volinfo.v_path, 131 0000, 132 "dbd", 133 flags, 134 vol->volinfo.v_dbd_host, 135 vol->volinfo.v_dbd_port)) == NULL) 136 ERROR("Cant initialize CNID database connection for %s", vol->volinfo.v_path); 137 138 cnid_getstamp(vol->volume.v_cdb, 139 vol->db_stamp, 140 sizeof(vol->db_stamp)); 141 142 return 0; 143} 144 145void closevol(afpvol_t *vol) 146{ 147 if (vol->volume.v_cdb) 148 cnid_close(vol->volume.v_cdb); 149 150 memset(vol, 0, sizeof(afpvol_t)); 151} 152 153/* 154 Taken form afpd/desktop.c 155*/ 156char *utompath(const struct volinfo *volinfo, const char *upath) 157{ 158 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ 159 char *m; 160 const char *u; 161 uint16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX; 162 size_t outlen; 163 164 if (!upath) 165 return NULL; 166 167 m = mpath; 168 u = upath; 169 outlen = strlen(upath); 170 171 if ((volinfo->v_casefold & AFPVOL_UTOMUPPER)) 172 flags |= CONV_TOUPPER; 173 else if ((volinfo->v_casefold & AFPVOL_UTOMLOWER)) 174 flags |= CONV_TOLOWER; 175 176 if ((volinfo->v_flags & AFPVOL_EILSEQ)) { 177 flags |= CONV__EILSEQ; 178 } 179 180 /* convert charsets */ 181 if ((size_t)-1 == ( outlen = convert_charset(volinfo->v_volcharset, 182 CH_UTF8_MAC, 183 volinfo->v_maccharset, 184 u, outlen, mpath, MAXPATHLEN, &flags)) ) { 185 SLOG("Conversion from %s to %s for %s failed.", 186 volinfo->v_volcodepage, volinfo->v_maccodepage, u); 187 return NULL; 188 } 189 190 return(m); 191} 192 193 194/*! 195 * Convert dot encoding of basename _in place_ 196 * 197 * path arg can be "[/][dir/ | ...]filename". It will be converted in place 198 * possible encoding ".file" as ":2efile" which means the result will be 199 * longer then the original which means provide a big enough buffer. 200 * 201 * @param svol (r) source volume 202 * @param dvol (r) destinatio volume 203 * @param path (rw) path to convert _in place_ 204 * @param buflen (r) size of path buffer (max strlen == buflen -1) 205 * 206 * @returns 0 on sucess, -1 on error 207 */ 208int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path, size_t buflen) 209{ 210 static charset_t from = (charset_t) -1; 211 static char buf[MAXPATHLEN+2]; 212 char *bname = stripped_slashes_basename(path); 213 int pos = bname - path; 214 uint16_t flags = 0; 215 216 if ( ! svol->volinfo.v_path) { 217 /* no source volume: escape special chars (eg ':') */ 218 from = dvol->volinfo.v_volcharset; /* src = dst charset */ 219 flags |= CONV_ESCAPEHEX; 220 } else { 221 from = svol->volinfo.v_volcharset; 222 } 223 224 if ( (svol->volinfo.v_path) 225 && ! (svol->volinfo.v_flags & AFPVOL_USEDOTS) 226 && (dvol->volinfo.v_flags & AFPVOL_USEDOTS)) { 227 /* source is without dots, destination is with */ 228 flags |= CONV_UNESCAPEHEX; 229 } else if (! (dvol->volinfo.v_flags & AFPVOL_USEDOTS)) { 230 flags |= CONV_ESCAPEDOTS; 231 } 232 233 int len = convert_charset(from, 234 dvol->volinfo.v_volcharset, 235 dvol->volinfo.v_maccharset, 236 bname, strlen(bname), 237 buf, MAXPATHLEN, 238 &flags); 239 if (len == -1) 240 return -1; 241 242 if (strlcpy(bname, buf, MAXPATHLEN - pos) > MAXPATHLEN - pos) 243 return -1; 244 return 0; 245} 246 247/*! 248 * ResolvesCNID of a given paths 249 * 250 * path might be: 251 * (a) relative: 252 * "dir/subdir" with cwd: "/afp_volume/topdir" 253 * (b) absolute: 254 * "/afp_volume/dir/subdir" 255 * 256 * path MUST be pointing inside vol, this is usually the case as vol has been build from 257 * path using loadvolinfo and friends. 258 * 259 * @param vol (r) pointer to afpvol_t 260 * @param path (r) path, see above 261 * @param did (rw) parent CNID of returned CNID 262 * 263 * @returns CNID of path 264 */ 265cnid_t cnid_for_path(const afpvol_t *vol, 266 const char *path, 267 cnid_t *did) 268{ 269 EC_INIT; 270 271 cnid_t cnid; 272 bstring rpath = NULL; 273 bstring statpath = NULL; 274 struct bstrList *l = NULL; 275 struct stat st; 276 277 cnid = htonl(2); 278 279 EC_NULL(rpath = rel_path_in_vol(path, vol->volinfo.v_path)); 280 EC_NULL(statpath = bfromcstr(vol->volinfo.v_path)); 281 EC_ZERO(bcatcstr(statpath, "/")); 282 283 l = bsplit(rpath, '/'); 284 for (int i = 0; i < l->qty ; i++) { 285 *did = cnid; 286 287 EC_ZERO(bconcat(statpath, l->entry[i])); 288 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), 289 "lstat(rpath: %s, elem: %s): %s: %s", 290 cfrombstr(rpath), cfrombstr(l->entry[i]), 291 cfrombstr(statpath), strerror(errno)); 292 293 if ((cnid = cnid_add(vol->volume.v_cdb, 294 &st, 295 *did, 296 cfrombstr(l->entry[i]), 297 blength(l->entry[i]), 298 0)) == CNID_INVALID) { 299 EC_FAIL; 300 } 301 EC_ZERO(bcatcstr(statpath, "/")); 302 } 303 304EC_CLEANUP: 305 bdestroy(rpath); 306 bstrListDestroy(l); 307 bdestroy(statpath); 308 if (ret != 0) 309 return CNID_INVALID; 310 311 return cnid; 312} 313 314/*! 315 * Resolves CNID of a given paths parent directory 316 * 317 * path might be: 318 * (a) relative: 319 * "dir/subdir" with cwd: "/afp_volume/topdir" 320 * (b) absolute: 321 * "/afp_volume/dir/subdir" 322 * 323 * path MUST be pointing inside vol, this is usually the case as vol has been build from 324 * path using loadvolinfo and friends. 325 * 326 * @param vol (r) pointer to afpvol_t 327 * @param path (r) path, see above 328 * @param did (rw) parent CNID of returned CNID 329 * 330 * @returns CNID of path 331 */ 332cnid_t cnid_for_paths_parent(const afpvol_t *vol, 333 const char *path, 334 cnid_t *did) 335{ 336 EC_INIT; 337 338 cnid_t cnid; 339 bstring rpath = NULL; 340 bstring statpath = NULL; 341 struct bstrList *l = NULL; 342 struct stat st; 343 344 *did = htonl(1); 345 cnid = htonl(2); 346 347 EC_NULL(rpath = rel_path_in_vol(path, vol->volinfo.v_path)); 348 EC_NULL(statpath = bfromcstr(vol->volinfo.v_path)); 349 350 l = bsplit(rpath, '/'); 351 if (l->qty == 1) 352 /* only one path element, means parent dir cnid is volume root = 2 */ 353 goto EC_CLEANUP; 354 for (int i = 0; i < (l->qty - 1); i++) { 355 *did = cnid; 356 EC_ZERO(bconcat(statpath, l->entry[i])); 357 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), 358 "lstat(rpath: %s, elem: %s): %s: %s", 359 cfrombstr(rpath), cfrombstr(l->entry[i]), 360 cfrombstr(statpath), strerror(errno)); 361 362 if ((cnid = cnid_add(vol->volume.v_cdb, 363 &st, 364 *did, 365 cfrombstr(l->entry[i]), 366 blength(l->entry[i]), 367 0)) == CNID_INVALID) { 368 EC_FAIL; 369 } 370 EC_ZERO(bcatcstr(statpath, "/")); 371 } 372 373EC_CLEANUP: 374 bdestroy(rpath); 375 bstrListDestroy(l); 376 bdestroy(statpath); 377 if (ret != 0) 378 return CNID_INVALID; 379 380 return cnid; 381} 382 383