]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/filedir.c
added dropbox as a volume option when DROPKLUDGE is compiled in
[netatalk.git] / etc / afpd / filedir.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif
9
10 #include <errno.h>
11 #include <sys/syslog.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/param.h>
15 #include <netatalk/endian.h>
16 #include <atalk/adouble.h>
17 #include <atalk/afp.h>
18 #include <atalk/util.h>
19 #include <atalk/cnid.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <fcntl.h>
23 #include <dirent.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 #include "directory.h"
28 #include "desktop.h"
29 #include "volume.h"
30 #include "fork.h"
31 #include "file.h"
32 #include "globals.h"
33 #include "filedir.h"
34
35 int matchfile2dirperms(upath, vol, did)
36                               /* Since it's kinda' big; I decided against an
37                               inline function */
38     char        *upath;
39     struct vol  *vol;
40     int         did;
41   /* The below code changes the way file ownership is determined in the name of
42   fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
43   more information */
44 {
45     struct stat st, sb;
46     struct dir  *dir;
47     char        adpath[50];
48     int         uid;
49
50 #ifdef DEBUG
51     syslog (LOG_INFO, "begin matchfile2dirperms:");
52 #endif DEBUG
53
54     if (stat(upath, &st ) < 0)
55       syslog(LOG_ERR, "Could not stat %s: %m", upath);
56     strcpy (adpath, "./.AppleDouble/");
57     strcat (adpath, upath);
58     if (( dir = dirsearch( vol, did )) == NULL ) {
59       syslog (LOG_ERR, "matchfile2dirperms: Unable to get directory info.");
60       return( AFPERR_NOOBJ );
61     }
62     else if (stat(".", &sb) < 0) {
63         syslog (LOG_ERR, 
64            "matchfile2dirperms: Error checking directory \"%s\": %m", 
65            dir->d_name);
66         return(AFPERR_NOOBJ );
67       }
68     else {
69         uid=geteuid();
70         if ( uid != sb.st_uid )
71         {
72           seteuid(0);
73           if (lchown(upath, sb.st_uid, sb.st_gid) < 0)
74           {
75             syslog (LOG_ERR, 
76               "matchfile2dirperms: Error changing owner/gid of %s: %m", upath);
77             return (AFPERR_ACCESS);
78           }
79           if (chmod(upath,(st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
80           {
81             syslog (LOG_ERR, 
82               "matchfile2dirperms:  Error adding file read permissions: %m");
83             return (AFPERR_ACCESS);
84           }
85 #ifdef DEBUG
86           else 
87             syslog (LOG_INFO, 
88               "matchfile2dirperms:  Added S_IRGRP and S_IROTH: %m");
89 #endif DEBUG
90           if (lchown(adpath, sb.st_uid, sb.st_gid) < 0)
91           {
92             syslog (LOG_ERR, 
93               "matchfile2dirperms: Error changing AppleDouble owner/gid %s: %m",
94               adpath);
95             return (AFPERR_ACCESS);
96           }
97           if (chmod(adpath, (st.st_mode&0x0FFFF)| S_IRGRP| S_IROTH) < 0)
98           {
99             syslog (LOG_ERR, 
100               "matchfile2dirperms:  Error adding AD file read permissions: %m");
101             return (AFPERR_ACCESS);
102           }
103 #ifdef DEBUG
104           else 
105             syslog (LOG_INFO, 
106               "matchfile2dirperms:  Added S_IRGRP and S_IROTH to AD: %m");
107 #endif DEBUG
108         }
109 #ifdef DEBUG
110         else
111           syslog (LOG_INFO, 
112             "matchfile2dirperms: No ownership change necessary.");
113 #endif DEBUG
114     } /* end else if stat success */
115     seteuid(uid); /* Restore process ownership to normal */
116 #ifdef DEBUG
117     syslog (LOG_INFO, "end matchfile2dirperms:");
118 #endif DEBUG
119
120     return (AFP_OK);
121
122 }
123     
124
125 int afp_getfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
126     AFPObj      *obj;
127     char        *ibuf, *rbuf;
128     int         ibuflen, *rbuflen;
129 {
130     struct stat         st;
131     struct vol          *vol;
132     struct dir          *dir;
133     u_int32_t           did;
134     int                 buflen, ret;
135     char                *path;
136     u_int16_t           fbitmap, dbitmap, vid;
137
138 #ifdef DEBUG
139     syslog(LOG_INFO, "begin afp_getfildirparams:");
140 #endif DEBUG
141
142     *rbuflen = 0;
143     ibuf += 2;
144
145     memcpy( &vid, ibuf, sizeof( vid ));
146     ibuf += sizeof( vid );
147     if (( vol = getvolbyvid( vid )) == NULL ) {
148         return( AFPERR_PARAM );
149     }
150
151     memcpy( &did, ibuf, sizeof( did ));
152     ibuf += sizeof( did );
153
154     if (( dir = dirsearch( vol, did )) == NULL ) {
155         return( AFPERR_NOOBJ );
156     }
157
158     memcpy( &fbitmap, ibuf, sizeof( fbitmap ));
159     fbitmap = ntohs( fbitmap );
160     ibuf += sizeof( fbitmap );
161     memcpy( &dbitmap, ibuf, sizeof( dbitmap ));
162     dbitmap = ntohs( dbitmap );
163     ibuf += sizeof( dbitmap );
164
165     if (( path = cname( vol, dir, &ibuf )) == NULL) {
166         return( AFPERR_NOOBJ );
167     }
168
169     if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
170         return( AFPERR_NOOBJ );
171     }
172
173     buflen = 0;
174     if (S_ISDIR(st.st_mode)) {
175         if (dbitmap && ( ret = getdirparams(vol, dbitmap, ".", curdir,
176                 &st, rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
177             return( ret );
178         }
179         /* this is a directory */
180         *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISDIR; 
181     } else {
182         if (fbitmap && ( ret = getfilparams(vol, fbitmap, path, curdir, &st,
183                 rbuf + 3 * sizeof( u_int16_t ), &buflen )) != AFP_OK ) {
184             return( ret );
185         }
186         /* this is a file */
187         *(rbuf + 2 * sizeof( u_int16_t )) = FILDIRBIT_ISFILE;
188     }
189     *rbuflen = buflen + 3 * sizeof( u_int16_t );
190     fbitmap = htons( fbitmap );
191     memcpy( rbuf, &fbitmap, sizeof( fbitmap ));
192     rbuf += sizeof( fbitmap );
193     dbitmap = htons( dbitmap );
194     memcpy( rbuf, &dbitmap, sizeof( dbitmap ));
195     rbuf += sizeof( dbitmap ) + sizeof( u_char );
196     *rbuf = 0;
197
198 #ifdef DEBUG
199     syslog(LOG_INFO, "end afp_getfildirparams:");
200 #endif DEBUG
201
202     return( AFP_OK );
203 }
204
205 int afp_setfildirparams(obj, ibuf, ibuflen, rbuf, rbuflen )
206     AFPObj      *obj;
207     char        *ibuf, *rbuf;
208     int         ibuflen, *rbuflen;
209 {
210     struct stat st;
211     struct vol  *vol;
212     struct dir  *dir;
213     char        *path;
214     u_int16_t   vid, bitmap;
215     int         did, rc;
216
217 #ifdef DEBUG
218     syslog(LOG_INFO, "begin afp_setfildirparams:");
219 #endif DEBUG
220
221     *rbuflen = 0;
222     ibuf += 2;
223     memcpy( &vid, ibuf, sizeof(vid));
224     ibuf += sizeof( vid );
225
226     if (( vol = getvolbyvid( vid )) == NULL ) {
227         return( AFPERR_PARAM );
228     }
229
230     if (vol->v_flags & AFPVOL_RO)
231         return AFPERR_VLOCK;
232
233     memcpy( &did, ibuf, sizeof( did));
234     ibuf += sizeof( did);
235
236     if (( dir = dirsearch( vol, did )) == NULL ) {
237         return( AFPERR_NOOBJ );
238     }
239
240     memcpy( &bitmap, ibuf, sizeof( bitmap ));
241     bitmap = ntohs( bitmap );
242     ibuf += sizeof( bitmap );
243
244     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
245         return( AFPERR_NOOBJ );
246     }
247
248     if ( stat( mtoupath(vol, path ), &st ) < 0 ) {
249         return( AFPERR_NOOBJ );
250     }
251
252     /*
253      * If ibuf is odd, make it even.
254      */
255     if ((u_long)ibuf & 1 ) {
256         ibuf++;
257     }
258
259     if (S_ISDIR(st.st_mode)) {
260         rc = setdirparams(vol, path, bitmap, ibuf );
261     } else {
262         rc = setfilparams(vol, path, bitmap, ibuf );
263     }
264     if ( rc == AFP_OK ) {
265         setvoltime(obj, vol );
266     }
267
268 #ifdef DEBUG
269     syslog(LOG_INFO, "end afp_setfildirparams:");
270 #endif DEBUG
271
272     return( rc );
273 }
274
275 int afp_rename(obj, ibuf, ibuflen, rbuf, rbuflen )
276     AFPObj      *obj;
277     char        *ibuf, *rbuf;
278     int         ibuflen, *rbuflen;
279 {
280     struct adouble      ad;
281     struct stat         st;
282     struct vol          *vol;
283     struct dir          *dir, *odir = NULL;
284     char                *path, *buf, *upath, *newpath;
285     char                *newadpath;
286     u_int32_t           did;
287     int                 plen;
288     u_int16_t           vid;
289 #if AD_VERSION > AD_VERSION1
290     cnid_t              id;
291 #endif
292
293 #ifdef DEBUG
294     syslog(LOG_INFO, "begin afp_rename:");
295 #endif DEBUG
296
297     *rbuflen = 0;
298     ibuf += 2;
299
300     memcpy( &vid, ibuf, sizeof( vid ));
301     ibuf += sizeof( vid );
302     if (( vol = getvolbyvid( vid )) == NULL ) {
303         return( AFPERR_PARAM );
304     }
305
306     if (vol->v_flags & AFPVOL_RO)
307         return AFPERR_VLOCK;
308
309     memcpy( &did, ibuf, sizeof( did ));
310     ibuf += sizeof( did );
311     if (( dir = dirsearch( vol, did )) == NULL ) {
312         return( AFPERR_NOOBJ );
313     }
314
315     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
316         return( AFPERR_NOOBJ );
317     }
318
319     /* another place where we know about the path type */
320     if ( *ibuf++ != 2 ) {
321         return( AFPERR_PARAM );
322     }
323     plen = (unsigned char) *ibuf++;
324     *( ibuf + plen ) = '\0';
325
326     if ( *path == '\0' ) {
327         if ( curdir->d_parent == NULL ) { /* root directory */
328             return( AFPERR_NORENAME );
329         }
330         odir = curdir;
331         path = curdir->d_name;
332         if ( movecwd( vol, curdir->d_parent ) < 0 ) {
333             return( AFPERR_NOOBJ );
334         }
335     }
336
337 #ifdef notdef
338     if ( strcasecmp( path, ibuf ) == 0 ) {
339         return( AFP_OK );
340     }
341 #endif notdef
342
343     /* if a curdir/newname ofork exists, return busy */
344     if (of_findname(vol, curdir, ibuf))
345         return AFPERR_BUSY;
346
347     /* source == destination. just say okay. */
348     if (strcmp(path, ibuf) == 0)
349         return AFP_OK;
350
351     /* check for illegal characters */
352     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
353         strpbrk(ibuf, MSWINDOWS_BADCHARS))
354         return AFPERR_PARAM;
355
356     newpath = obj->oldtmp;
357     strcpy( newpath, mtoupath(vol, ibuf ));
358
359     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(newpath, '/'))
360       return AFPERR_PARAM;
361
362     if (!validupath(vol, newpath))
363       return AFPERR_EXIST;
364
365     /* the strdiacasecmp deals with case-insensitive, case preserving
366        filesystems */
367     if (stat( newpath, &st ) == 0 && strdiacasecmp(path, ibuf))
368         return( AFPERR_EXIST );
369
370     upath = mtoupath(vol, path);
371
372 #if AD_VERSION > AD_VERSION1
373     id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
374 #endif
375
376     if ( rename( upath, newpath ) < 0 ) {
377         switch ( errno ) {
378         case ENOENT :
379             return( AFPERR_NOOBJ );
380         case EACCES :
381             return( AFPERR_ACCESS );
382         default :
383             return( AFPERR_PARAM );
384         }
385     }
386
387 #if AD_VERSION > AD_VERSION1
388     if (stat(newpath, &st) < 0) /* this shouldn't fail */
389       return AFPERR_MISC;
390     cnid_update(vol->v_db, id, &st, curdir->d_did, newpath, strlen(newpath));
391 #endif
392
393     if ( !odir ) {
394         newadpath = obj->newtmp;
395         strcpy( newadpath, ad_path( newpath, 0 ));
396         if ( rename( ad_path( upath, 0 ), newadpath ) < 0 ) {
397             if ( errno == ENOENT ) {    /* no adouble header file */
398                 if (( unlink( newadpath ) < 0 ) && ( errno != ENOENT )) {
399                     return( AFPERR_PARAM );
400                 }
401                 goto out;
402             }
403             return( AFPERR_PARAM );
404         }
405
406         memset(&ad, 0, sizeof(ad));
407         if ( ad_open( newpath, ADFLAGS_HF, O_RDWR|O_CREAT, 0666,
408                       &ad) < 0 ) {
409             return( AFPERR_PARAM );
410         }
411     } else {
412         int isad = 1;
413
414         memset(&ad, 0, sizeof(ad));
415         if ( ad_open( newpath, vol_noadouble(vol)|ADFLAGS_HF|ADFLAGS_DIR, 
416                       O_RDWR|O_CREAT, 0666, &ad) < 0 ) {
417             if (!((errno == ENOENT) && vol_noadouble(vol)))
418               return( AFPERR_PARAM );
419             isad = 0;
420         }
421         if ((buf = realloc( odir->d_name, plen + 1 )) == NULL ) {
422             syslog( LOG_ERR, "afp_rename: realloc: %m" );
423             if (isad) {
424               ad_flush(&ad, ADFLAGS_HF); /* in case of create */
425               ad_close(&ad, ADFLAGS_HF);
426             }
427             return AFPERR_MISC;
428         }
429         odir->d_name = buf;
430         strcpy( odir->d_name, ibuf );
431         if (!isad)
432           goto out;
433     }
434
435     ad_setentrylen( &ad, ADEID_NAME, plen );
436     memcpy( ad_entry( &ad, ADEID_NAME ), ibuf, plen );
437     ad_flush( &ad, ADFLAGS_HF );
438     ad_close( &ad, ADFLAGS_HF );
439
440 out:
441     setvoltime(obj, vol );
442
443     /* if it's still open, rename the ofork as well. */
444     if (of_rename(vol, curdir, path, curdir, ibuf) < 0)
445         return AFPERR_MISC;
446
447 #ifdef DEBUG
448     syslog(LOG_INFO, "end afp_rename:");
449 #endif DEBUG
450
451     return( AFP_OK );
452 }
453
454
455 int afp_delete(obj, ibuf, ibuflen, rbuf, rbuflen )
456     AFPObj      *obj;
457     char        *ibuf, *rbuf;
458     int         ibuflen, *rbuflen;
459 {
460     struct vol          *vol;
461     struct dir          *dir;
462     char                *path, *upath;
463     int                 did, rc;
464     u_int16_t           vid;
465
466 #ifdef DEBUG
467     syslog(LOG_INFO, "begin afp_delete:");
468 #endif DEBUG
469
470     *rbuflen = 0;
471     ibuf += 2;
472
473     memcpy( &vid, ibuf, sizeof( vid ));
474     ibuf += sizeof( vid );
475     if (( vol = getvolbyvid( vid )) == NULL ) {
476         return( AFPERR_PARAM );
477     }
478
479     if (vol->v_flags & AFPVOL_RO)
480         return AFPERR_VLOCK;
481
482     memcpy( &did, ibuf, sizeof( did ));
483     ibuf += sizeof( int );
484     if (( dir = dirsearch( vol, did )) == NULL ) {
485         return( AFPERR_NOOBJ );
486     }
487
488     if (( path = cname( vol, dir, &ibuf )) == NULL ) {
489         return( AFPERR_NOOBJ );
490     }
491
492     if ( *path == '\0' ) {
493         rc = deletecurdir( vol, obj->oldtmp, AFPOBJ_TMPSIZ);
494     } else if (of_findname(vol, curdir, path)) {
495         rc = AFPERR_BUSY;
496     } else if ((rc = deletefile( upath = mtoupath(vol, path ))) == AFP_OK) {
497 #if AD_VERSION > AD_VERSION1 /* get rid of entry */
498         cnid_t id = cnid_get(vol->v_db, curdir->d_did, upath, strlen(upath));
499         cnid_delete(vol->v_db, id);
500 #endif
501     }
502     if ( rc == AFP_OK ) {
503         setvoltime(obj, vol );
504     }
505
506 #ifdef DEBUG
507     syslog(LOG_INFO, "end afp_delete:");
508 #endif DEBUG
509
510     return( rc );
511 }
512
513 char *ctoupath( vol, dir, name )
514     const struct vol    *vol;
515     struct dir  *dir;
516     char        *name;
517 {
518     struct dir  *d;
519     static char path[ MAXPATHLEN + 1];
520     char        *p, *u;
521     int         len;
522
523     p = path + sizeof( path ) - 1;
524     *p = '\0';
525     u = mtoupath(vol, name );
526     len = strlen( u );
527     p -= len;
528     strncpy( p, u, len );
529     for ( d = dir; d->d_parent; d = d->d_parent ) {
530         *--p = '/';
531         u = mtoupath(vol, d->d_name );
532         len = strlen( u );
533         p -= len;
534         strncpy( p, u, len );
535     }
536     *--p = '/';
537     len = strlen( vol->v_path );
538     p -= len;
539     strncpy( p, vol->v_path, len );
540
541     return( p );
542 }
543
544
545 int afp_moveandrename(obj, ibuf, ibuflen, rbuf, rbuflen )
546     AFPObj      *obj;
547     char        *ibuf, *rbuf;
548     int         ibuflen, *rbuflen;
549 {
550     struct vol  *vol;
551     struct dir  *sdir, *ddir, *odir = NULL;
552     struct stat st;
553     char        *oldname, *newname;
554     char        *path, *p, *upath; 
555     int         did, rc;
556     int         plen, retvalue;
557     u_int16_t   vid;
558 #if AD_VERSION > AD_VERSION1
559     cnid_t      id;
560 #endif
561
562 #ifdef DEBUG
563     syslog(LOG_INFO, "begin afp_moveandrename:");
564 #endif DEBUG
565
566     *rbuflen = 0;
567     ibuf += 2;
568
569     memcpy( &vid, ibuf, sizeof( vid ));
570     ibuf += sizeof( vid );
571     if (( vol = getvolbyvid( vid )) == NULL ) {
572         return( AFPERR_PARAM );
573     }
574
575     if (vol->v_flags & AFPVOL_RO)
576         return AFPERR_VLOCK;
577
578     /* source did followed by dest did */
579     memcpy( &did, ibuf, sizeof( did ));
580     ibuf += sizeof( int );
581     if (( sdir = dirsearch( vol, did )) == NULL ) {
582         return( AFPERR_PARAM );
583     }
584
585     memcpy( &did, ibuf, sizeof( did ));
586     ibuf += sizeof( int );
587
588     /* source pathname */
589     if (( path = cname( vol, sdir, &ibuf )) == NULL ) {
590         return( AFPERR_NOOBJ );
591     }
592
593     sdir = curdir;
594     newname = obj->newtmp;
595     oldname = obj->oldtmp;
596     if ( *path != '\0' ) {
597         /* not a directory */
598         strcpy(newname, path);
599         strcpy(oldname, path); /* an extra copy for of_rename */
600 #if AD_VERSION > AD_VERSION1
601         p = mtoupath(vol, path);
602         id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p));
603 #endif
604         p = ctoupath( vol, sdir, newname );
605     } else {
606         odir = curdir;
607         strcpy( newname, odir->d_name );
608         strcpy(oldname, odir->d_name); 
609         p = ctoupath( vol, odir->d_parent, newname );
610 #if AD_VERSION > AD_VERSION1
611         id = curdir->d_did; /* we already have the CNID */
612 #endif
613     }
614     /*
615      * p now points to the full pathname of the source fs object.
616      */
617
618     /* get the destination directory */
619     if (( ddir = dirsearch( vol, did )) == NULL ) {
620         return( AFPERR_PARAM );
621     }
622     if (( path = cname( vol, ddir, &ibuf )) == NULL ) {
623         return( AFPERR_NOOBJ );
624     }
625     if ( *path != '\0' ) {
626         return( AFPERR_BADTYPE );
627     }
628
629     /* one more place where we know about path type */
630     if ( *ibuf++ != 2 ) {
631         return( AFPERR_PARAM );
632     }
633
634     if (( plen = (unsigned char)*ibuf++ ) != 0 ) {
635         strncpy( newname, ibuf, plen );
636         newname[ plen ] = '\0';
637     }
638
639     /* check for illegal characters */
640     if ((vol->v_flags & AFPVOL_MSWINDOWS) && 
641         strpbrk(newname, MSWINDOWS_BADCHARS))
642         return AFPERR_PARAM;
643
644     upath = mtoupath(vol, newname);
645
646     if ((vol->v_flags & AFPVOL_NOHEX) && strchr(upath, '/'))
647       return AFPERR_PARAM;
648
649     if (!validupath(vol, upath))
650       return AFPERR_EXIST;
651
652     /* source == destination. we just silently accept this. */
653     if (curdir == sdir) {
654       if (strcmp(oldname, newname) == 0)
655         return AFP_OK;
656       
657       /* deal with case insensitive, case-preserving filesystems. */
658       if ((stat(upath, &st) == 0) && strdiacasecmp(oldname, newname)) 
659         return AFPERR_EXIST;
660       
661     } else if (stat(upath, &st ) == 0)
662       return( AFPERR_EXIST );
663       
664     if ( !odir ) {
665       if (of_findname(vol, curdir, newname)) {
666         rc = AFPERR_BUSY;
667       } else if ((rc = renamefile( p, upath, newname, 
668                                    vol_noadouble(vol) )) == AFP_OK) {
669         /* if it's still open, rename the ofork as well. */
670         rc = of_rename(vol, sdir, oldname, curdir, newname);
671       }
672     } else {
673         rc = renamedir(p, upath, odir, curdir, newname, vol_noadouble(vol));
674     }
675
676 #ifdef DROPKLUDGE
677     if (vol->v_flags & AFPVOL_DROPBOX) {
678         if (retvalue=matchfile2dirperms (newname, vol, did) != AFP_OK) {
679             return retvalue;
680         }
681     }
682 #endif DROPKLUDGE
683
684     if ( rc == AFP_OK ) {
685 #if AD_VERSION > AD_VERSION1
686         /* renaming may have moved the file/dir across a filesystem */
687         if (stat(upath, &st) < 0) 
688           return AFPERR_MISC;
689         
690         /* fix up the catalog entry */
691         cnid_update(vol->v_db, id, &st, curdir->d_did, upath, strlen(upath));
692 #endif      
693         setvoltime(obj, vol );
694     }
695
696 #ifdef DEBUG
697     syslog(LOG_INFO, "end afp_moveandrename:");
698 #endif DEBUG
699
700     return( rc );
701 }
702