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 #ifdef HAVE_FREEBSD_SUNACL
55 #include <sunacl.h>
56 #endif
57
58 #ifdef HAVE_POSIX_ACLS
59 #include <sys/types.h>
60 #include <sys/acl.h>
61 #endif /* HAVE_POSIX_ACLS */
62
63 #include <atalk/util.h>
64 #include <atalk/cnid.h>
65 #include <atalk/bstrlib.h>
66 #include <atalk/bstradd.h>
67 #include <atalk/logger.h>
68 #include <atalk/errchk.h>
69 #include <atalk/unicode.h>
70 #include <atalk/globals.h>
71 #include <atalk/netatalk_conf.h>
72
73
74 #include "ad.h"
75
76 int log_verbose; /* Logging flag */
77
_log(enum logtype lt,char * fmt,...)78 void _log(enum logtype lt, char *fmt, ...)
79 {
80 int len;
81 static char logbuffer[1024];
82 va_list args;
83
84 if ( (lt == STD) || (log_verbose == 1)) {
85 va_start(args, fmt);
86 len = vsnprintf(logbuffer, 1023, fmt, args);
87 va_end(args);
88 logbuffer[1023] = 0;
89
90 printf("%s\n", logbuffer);
91 }
92 }
93
94 /*!
95 * Load volinfo and initialize struct vol
96 *
97 * Only opens "dbd" volumes !
98 *
99 * @param path (r) path to evaluate
100 * @param vol (rw) structure to initialize
101 *
102 * @returns 0 on success, exits on error
103 */
openvol(AFPObj * obj,const char * path,afpvol_t * vol)104 int openvol(AFPObj *obj, const char *path, afpvol_t *vol)
105 {
106 int flags = 0;
107
108 memset(vol, 0, sizeof(afpvol_t));
109
110 if ((vol->vol = getvolbypath(obj, path)) == NULL)
111 return -1;
112
113 if (STRCMP(vol->vol->v_cnidscheme, != , "dbd"))
114 ERROR("\"%s\" isn't a \"dbd\" CNID volume!", vol->vol->v_path);
115
116 /* Sanity checks to ensure we can touch this volume */
117 if (vol->vol->v_adouble != AD_VERSION2
118 && vol->vol->v_adouble != AD_VERSION_EA)
119 ERROR("Unsupported adouble versions: %u", vol->vol->v_adouble);
120
121 if (vol->vol->v_vfs_ea != AFPVOL_EA_SYS)
122 ERROR("Unsupported Extended Attributes option: %u", vol->vol->v_vfs_ea);
123
124 if ((vol->vol->v_flags & AFPVOL_NODEV))
125 flags |= CNID_FLAG_NODEV;
126
127 if ((vol->vol->v_cdb = cnid_open(vol->vol,
128 "dbd",
129 flags)) == 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
closevol(afpvol_t * vol)139 void 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 */
utompath(const struct vol * vol,const char * upath)153 char *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 */
convert_dots_encoding(const afpvol_t * svol,const afpvol_t * dvol,char * path,size_t buflen)205 int 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 * Resolves CNID of a given paths parent directory
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 */
cnid_for_paths_parent(const afpvol_t * vol,const char * path,cnid_t * did)254 cnid_t cnid_for_paths_parent(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 *did = htonl(1);
267 cnid = htonl(2);
268
269 EC_NULL(rpath = rel_path_in_vol(path, vol->vol->v_path));
270 EC_NULL(statpath = bfromcstr(vol->vol->v_path));
271
272 l = bsplit(rpath, '/');
273 if (l->qty == 1)
274 /* only one path element, means parent dir cnid is volume root = 2 */
275 goto EC_CLEANUP;
276 for (int i = 0; i < (l->qty - 1); i++) {
277 *did = cnid;
278 EC_ZERO(bconcat(statpath, l->entry[i]));
279 EC_ZERO_LOGSTR(lstat(cfrombstr(statpath), &st),
280 "lstat(rpath: %s, elem: %s): %s: %s",
281 cfrombstr(rpath), cfrombstr(l->entry[i]),
282 cfrombstr(statpath), strerror(errno));
283
284 if ((cnid = cnid_add(vol->vol->v_cdb,
285 &st,
286 *did,
287 cfrombstr(l->entry[i]),
288 blength(l->entry[i]),
289 0)) == CNID_INVALID) {
290 EC_FAIL;
291 }
292 EC_ZERO(bcatcstr(statpath, "/"));
293 }
294
295 EC_CLEANUP:
296 bdestroy(rpath);
297 bstrListDestroy(l);
298 bdestroy(statpath);
299 if (ret != 0)
300 return CNID_INVALID;
301
302 return cnid;
303 }
304
305