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/bstrlib.h> 63#include <atalk/bstradd.h> 64#include <atalk/logger.h> 65#include <atalk/errchk.h> 66#include <atalk/unicode.h> 67#include <atalk/globals.h> 68#include <atalk/netatalk_conf.h> 69 70 71#include "ad.h" 72 73int log_verbose; /* Logging flag */ 74 75void _log(enum logtype lt, char *fmt, ...) 76{ 77 int len; 78 static char logbuffer[1024]; 79 va_list args; 80 81 if ( (lt == STD) || (log_verbose == 1)) { 82 va_start(args, fmt); 83 len = vsnprintf(logbuffer, 1023, fmt, args); 84 va_end(args); 85 logbuffer[1023] = 0; 86 87 printf("%s\n", logbuffer); 88 } 89} 90 91/*! 92 * Load volinfo and initialize struct vol 93 * 94 * Only opens "dbd" volumes ! 95 * 96 * @param path (r) path to evaluate 97 * @param vol (rw) structure to initialize 98 * 99 * @returns 0 on success, exits on error 100 */ 101int openvol(AFPObj *obj, const char *path, afpvol_t *vol) 102{ 103 int flags = 0; 104 105 memset(vol, 0, sizeof(afpvol_t)); 106 107 if ((vol->vol = getvolbypath(obj, path)) == NULL) 108 return -1; 109 110 if (STRCMP(vol->vol->v_cnidscheme, != , "dbd")) 111 ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->vol->v_path); 112 113 /* Sanity checks to ensure we can touch this volume */ 114 if (vol->vol->v_adouble != AD_VERSION2 115 && vol->vol->v_adouble != AD_VERSION_EA) 116 ERROR("Unsupported adouble versions: %u", vol->vol->v_adouble); 117 118 if (vol->vol->v_vfs_ea != AFPVOL_EA_SYS) 119 ERROR("Unsupported Extended Attributes option: %u", vol->vol->v_vfs_ea); 120 121 if ((vol->vol->v_flags & AFPVOL_NODEV)) 122 flags |= CNID_FLAG_NODEV; 123 124 if ((vol->vol->v_cdb = cnid_open(vol->vol->v_path, 125 0000, 126 "dbd", 127 flags, 128 vol->vol->v_cnidserver, 129 vol->vol->v_cnidport)) == NULL) 130 ERROR("Cant initialize CNID database connection for %s", vol->vol->v_path); 131 132 cnid_getstamp(vol->vol->v_cdb, 133 vol->db_stamp, 134 sizeof(vol->db_stamp)); 135 136 return 0; 137} 138 139void closevol(afpvol_t *vol) 140{ 141 if (vol->vol) { 142 if (vol->vol->v_cdb) { 143 cnid_close(vol->vol->v_cdb); 144 vol->vol->v_cdb = NULL; 145 } 146 } 147 memset(vol, 0, sizeof(afpvol_t)); 148} 149 150/* 151 Taken form afpd/desktop.c 152*/ 153char *utompath(const struct vol *vol, const char *upath) 154{ 155 static char mpath[ MAXPATHLEN + 2]; /* for convert_charset dest_len parameter +2 */ 156 char *m; 157 const char *u; 158 uint16_t flags = CONV_IGNORE | CONV_UNESCAPEHEX; 159 size_t outlen; 160 161 if (!upath) 162 return NULL; 163 164 m = mpath; 165 u = upath; 166 outlen = strlen(upath); 167 168 if ((vol->v_casefold & AFPVOL_UTOMUPPER)) 169 flags |= CONV_TOUPPER; 170 else if ((vol->v_casefold & AFPVOL_UTOMLOWER)) 171 flags |= CONV_TOLOWER; 172 173 if ((vol->v_flags & AFPVOL_EILSEQ)) { 174 flags |= CONV__EILSEQ; 175 } 176 177 /* convert charsets */ 178 if ((size_t)-1 == ( outlen = convert_charset(vol->v_volcharset, 179 CH_UTF8_MAC, 180 vol->v_maccharset, 181 u, outlen, mpath, MAXPATHLEN, &flags)) ) { 182 SLOG("Conversion from %s to %s for %s failed.", 183 vol->v_volcodepage, vol->v_maccodepage, u); 184 return NULL; 185 } 186 187 return(m); 188} 189 190 191/*! 192 * Convert dot encoding of basename _in place_ 193 * 194 * path arg can be "[/][dir/ | ...]filename". It will be converted in place 195 * possible encoding ".file" as ":2efile" which means the result will be 196 * longer then the original which means provide a big enough buffer. 197 * 198 * @param svol (r) source volume 199 * @param dvol (r) destinatio volume 200 * @param path (rw) path to convert _in place_ 201 * @param buflen (r) size of path buffer (max strlen == buflen -1) 202 * 203 * @returns 0 on sucess, -1 on error 204 */ 205int convert_dots_encoding(const afpvol_t *svol, const afpvol_t *dvol, char *path, size_t buflen) 206{ 207 static charset_t from = (charset_t) -1; 208 static char buf[MAXPATHLEN+2]; 209 char *bname = stripped_slashes_basename(path); 210 int pos = bname - path; 211 uint16_t flags = 0; 212 213 if ( ! svol->vol->v_path) { 214 /* no source volume: escape special chars (eg ':') */ 215 from = dvol->vol->v_volcharset; /* src = dst charset */ 216 if (dvol->vol->v_adouble == AD_VERSION2) 217 flags |= CONV_ESCAPEHEX; 218 } else { 219 from = svol->vol->v_volcharset; 220 } 221 222 int len = convert_charset(from, 223 dvol->vol->v_volcharset, 224 dvol->vol->v_maccharset, 225 bname, strlen(bname), 226 buf, MAXPATHLEN, 227 &flags); 228 if (len == -1) 229 return -1; 230 231 if (strlcpy(bname, buf, MAXPATHLEN - pos) > MAXPATHLEN - pos) 232 return -1; 233 return 0; 234} 235 236/*! 237 * ResolvesCNID of a given paths 238 * 239 * path might be: 240 * (a) relative: 241 * "dir/subdir" with cwd: "/afp_volume/topdir" 242 * (b) absolute: 243 * "/afp_volume/dir/subdir" 244 * 245 * path MUST be pointing inside vol, this is usually the case as vol has been build from 246 * path using loadvolinfo and friends. 247 * 248 * @param vol (r) pointer to afpvol_t 249 * @param path (r) path, see above 250 * @param did (rw) parent CNID of returned CNID 251 * 252 * @returns CNID of path 253 */ 254cnid_t cnid_for_path(const afpvol_t *vol, 255 const char *path, 256 cnid_t *did) 257{ 258 EC_INIT; 259 260 cnid_t cnid; 261 bstring rpath = NULL; 262 bstring statpath = NULL; 263 struct bstrList *l = NULL; 264 struct stat st; 265 266 cnid = htonl(2); 267 268 EC_NULL(rpath = rel_path_in_vol(path, vol->vol->v_path)); 269 EC_NULL(statpath = bfromcstr(vol->vol->v_path)); 270 EC_ZERO(bcatcstr(statpath, "/")); 271 272 l = bsplit(rpath, '/'); 273 for (int i = 0; i < l->qty ; i++) { 274 *did = cnid; 275 276 EC_ZERO(bconcat(statpath, l->entry[i])); 277 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), 278 "lstat(rpath: %s, elem: %s): %s: %s", 279 cfrombstr(rpath), cfrombstr(l->entry[i]), 280 cfrombstr(statpath), strerror(errno)); 281 282 if ((cnid = cnid_add(vol->vol->v_cdb, 283 &st, 284 *did, 285 cfrombstr(l->entry[i]), 286 blength(l->entry[i]), 287 0)) == CNID_INVALID) { 288 EC_FAIL; 289 } 290 EC_ZERO(bcatcstr(statpath, "/")); 291 } 292 293EC_CLEANUP: 294 bdestroy(rpath); 295 bstrListDestroy(l); 296 bdestroy(statpath); 297 if (ret != 0) 298 return CNID_INVALID; 299 300 return cnid; 301} 302 303/*! 304 * Resolves CNID of a given paths parent directory 305 * 306 * path might be: 307 * (a) relative: 308 * "dir/subdir" with cwd: "/afp_volume/topdir" 309 * (b) absolute: 310 * "/afp_volume/dir/subdir" 311 * 312 * path MUST be pointing inside vol, this is usually the case as vol has been build from 313 * path using loadvolinfo and friends. 314 * 315 * @param vol (r) pointer to afpvol_t 316 * @param path (r) path, see above 317 * @param did (rw) parent CNID of returned CNID 318 * 319 * @returns CNID of path 320 */ 321cnid_t cnid_for_paths_parent(const afpvol_t *vol, 322 const char *path, 323 cnid_t *did) 324{ 325 EC_INIT; 326 327 cnid_t cnid; 328 bstring rpath = NULL; 329 bstring statpath = NULL; 330 struct bstrList *l = NULL; 331 struct stat st; 332 333 *did = htonl(1); 334 cnid = htonl(2); 335 336 EC_NULL(rpath = rel_path_in_vol(path, vol->vol->v_path)); 337 EC_NULL(statpath = bfromcstr(vol->vol->v_path)); 338 339 l = bsplit(rpath, '/'); 340 if (l->qty == 1) 341 /* only one path element, means parent dir cnid is volume root = 2 */ 342 goto EC_CLEANUP; 343 for (int i = 0; i < (l->qty - 1); i++) { 344 *did = cnid; 345 EC_ZERO(bconcat(statpath, l->entry[i])); 346 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st), 347 "lstat(rpath: %s, elem: %s): %s: %s", 348 cfrombstr(rpath), cfrombstr(l->entry[i]), 349 cfrombstr(statpath), strerror(errno)); 350 351 if ((cnid = cnid_add(vol->vol->v_cdb, 352 &st, 353 *did, 354 cfrombstr(l->entry[i]), 355 blength(l->entry[i]), 356 0)) == CNID_INVALID) { 357 EC_FAIL; 358 } 359 EC_ZERO(bcatcstr(statpath, "/")); 360 } 361 362EC_CLEANUP: 363 bdestroy(rpath); 364 bstrListDestroy(l); 365 bdestroy(statpath); 366 if (ret != 0) 367 return CNID_INVALID; 368 369 return cnid; 370} 371 372