]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/unix.c
Dropbox kludge -- fixed file overwrites, I don't plan any more dev. on this.
[netatalk.git] / etc / afpd / unix.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 <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/param.h>
15 #include <sys/stat.h>
16 #include <sys/syslog.h>
17 #include <netatalk/endian.h>
18 #include <dirent.h>
19 #include <limits.h>
20 #include <atalk/afp.h>
21 #include <string.h>
22 #include <fcntl.h>
23 #include "auth.h"
24 #include "directory.h"
25 #include "volume.h"
26 #include "unix.h"
27
28 /*
29  * Get the free space on a partition.
30  */
31 int ustatfs_getvolspace( vol, bfree, btotal, bsize )
32     const struct vol    *vol;
33     VolSpace    *bfree, *btotal;
34     u_int32_t   *bsize;
35 {
36 #ifdef ultrix
37     struct fs_data      sfs;
38 #else /*ultrix*/
39     struct statfs       sfs;
40 #endif /*ultrix*/
41
42     if ( statfs( vol->v_path, &sfs ) < 0 ) {
43         return( AFPERR_PARAM );
44     }
45
46 #ifdef ultrix
47     *bfree = (VolSpace) sfs.fd_req.bfreen * 1024;
48     *bsize = 1024;
49 #else
50     *bfree = (VolSpace) sfs.f_bavail * sfs.f_frsize;
51     *bsize = sfs.f_frsize;
52 #endif ultrix
53
54     if ( *bfree > 0x7fffffff / *bsize ) {
55         *bfree = 0x7fffffff;
56     } else {
57         *bfree *= *bsize;
58     }
59
60 #ifdef ultrix
61     *btotal = (VolSpace) 
62       ( sfs.fd_req.btot - ( sfs.fd_req.bfree - sfs.fd_req.bfreen )) * 1024;
63 #else ultrix
64     *btotal = (VolSpace) 
65       ( sfs.f_blocks - ( sfs.f_bfree - sfs.f_bavail )) * sfs.f_frsize;
66 #endif ultrix
67     if ( *bfree > 0x7fffffff / *bsize ) {
68         *bfree = 0x7fffffff;
69     } else {
70         *bfree *= *bsize;
71     }
72     return( AFP_OK );
73 }
74
75 static __inline__ int utombits( bits )
76     mode_t      bits;
77 {
78     int         mbits;
79
80     mbits = 0;
81
82     mbits |= ( bits & ( S_IREAD >> 6 )) ? (AR_UREAD | AR_USEARCH) : 0;
83     mbits |= ( bits & ( S_IWRITE >> 6 )) ? AR_UWRITE : 0;
84 /* Do we really need this?
85     mbits |= ( bits & ( S_IEXEC >> 6) ) ? AR_USEARCH : 0; */
86
87     return( mbits );
88 }
89
90 void utommode( stat, ma )
91     struct stat         *stat;
92     struct maccess      *ma;
93 {
94     mode_t              mode;
95
96     mode = stat->st_mode;
97
98     ma->ma_world = utombits( mode );
99     mode = mode >> 3;
100
101     ma->ma_group = utombits( mode );
102     mode = mode >> 3;
103
104     ma->ma_owner = utombits( mode );
105
106 #ifdef ADMIN_GRP
107     if ( uuid == 0 )
108         ma->ma_user = AR_UWRITE | AR_UREAD | AR_USEARCH | AR_UOWN;
109     else
110 #endif
111
112     if ( uuid == stat->st_uid ) {
113         ma->ma_user = ma->ma_owner | AR_UOWN;
114     } else if ( gmem( stat->st_gid )) {
115         ma->ma_user = ma->ma_group;
116     } else {
117         ma->ma_user = ma->ma_world;
118     }
119
120     /*
121      * There are certain things the mac won't try if you don't have
122      * the "owner" bit set, even tho you can do these things on unix wiht
123      * only write permission.  What were the things?
124      */
125     if ( ma->ma_user & AR_UWRITE ) {
126         ma->ma_user |= AR_UOWN;
127     }
128 }
129
130
131 int gmem( gid )
132     const gid_t gid;
133 {
134     int         i;
135
136     for ( i = 0; i < ngroups; i++ ) {
137         if ( groups[ i ] == gid ) {
138             return( 1 );
139         }
140     }
141     return( 0 );
142 }
143
144 static __inline__ mode_t mtoubits( bits )
145     u_char      bits;
146 {
147     mode_t      mode;
148
149     mode = 0;
150
151     mode |= ( bits & AR_UREAD ) ? ( (S_IREAD | S_IEXEC) >> 6 ) : 0;
152     mode |= ( bits & AR_UWRITE ) ? ( (S_IWRITE | S_IEXEC) >> 6 ) : 0;
153 /* I don't think there's a way to set the SEARCH bit by itself on a Mac
154     mode |= ( bits & AR_USEARCH ) ? ( S_IEXEC >> 6 ) : 0; */
155
156     return( mode );
157 }
158
159 mode_t mtoumode( ma )
160     struct maccess      *ma;
161 {
162     mode_t              mode;
163
164     mode = 0;
165     mode |= mtoubits( ma->ma_owner );
166     mode = mode << 3;
167
168     mode |= mtoubits( ma->ma_group );
169     mode = mode << 3;
170
171     mode |= mtoubits( ma->ma_world );
172
173     return( mode );
174 }
175
176 inline int stickydirmode(name, mode)
177 char * name;
178 const mode_t mode;
179 {
180   int uid, retval;
181
182 /* Turn on the sticky bit if this is a drop box */
183    retval=0;
184 #ifdef DROPKLUDGE
185    if (mode & S_IWOTH) 
186       if (mode & S_IROTH); 
187       else /* if S_IWOTH and not S_IROTH */
188       {
189         uid=geteuid();
190         seteuid(0);
191         if ( retval=chmod( name, (DIRBITS | mode | S_ISVTX)) < 0)
192         {
193            syslog( LOG_ERR, "stickydirmode::setdirmode error: chmod %s: %m", name );
194            return(-1);
195         }
196         else
197         {
198            syslog( LOG_DEBUG, "stickydirmode::setdirmode: chmod %s: %m", name );
199            seteuid(uid);
200         }
201       }
202    else 
203 #endif DROPKLUDGE
204        if ( retval=chmod( name, DIRBITS | mode ) < 0 ) 
205           syslog( LOG_DEBUG, "stickydirmode::setdirmode: chmod %s: %m", name );
206    return retval;
207 }
208
209 int setdeskmode( mode )
210     const mode_t        mode;
211 {
212     char                wd[ MAXPATHLEN + 1];
213     struct stat         st;
214     char                modbuf[ 12 + 1], *m;
215     struct dirent       *deskp, *subp;
216     DIR                 *desk, *sub;
217
218     if ( getcwd( wd , MAXPATHLEN) == NULL ) {
219         return( -1 );
220     }
221     if ( chdir( ".AppleDesktop" ) < 0 ) {
222         return( -1 );
223     }
224     if (( desk = opendir( "." )) == NULL ) {
225         if ( chdir( wd ) < 0 ) {
226             syslog( LOG_ERR, "setdeskmode: chdir %s: %m", wd );
227         }
228         return( -1 );
229     }
230     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
231         if ( strcmp( deskp->d_name, "." ) == 0 ||
232                 strcmp( deskp->d_name, ".." ) == 0 || strlen( deskp->d_name ) > 2 ) {
233             continue;
234         }
235         strcpy( modbuf, deskp->d_name );
236         strcat( modbuf, "/" );
237         m = strchr( modbuf, '\0' );
238         if (( sub = opendir( deskp->d_name )) == NULL ) {
239             continue;
240         }
241         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
242             if ( strcmp( subp->d_name, "." ) == 0 ||
243                     strcmp( subp->d_name, ".." ) == 0 ) {
244                 continue;
245             }
246             *m = '\0';
247             strcat( modbuf, subp->d_name );
248             /* XXX: need to preserve special modes */
249             if (stat(modbuf, &st) < 0) {
250                 syslog( LOG_DEBUG, "setdeskmode: stat %s: %m", modbuf );
251                 continue;
252             }       
253
254             if (S_ISDIR(st.st_mode)) {
255               if ( chmod( modbuf,  DIRBITS | mode ) < 0 ) {
256                 syslog( LOG_DEBUG, "setdeskmode: chmod %s: %m", modbuf );
257               }
258             } else if ( chmod( modbuf,  mode ) < 0 ) {
259                 syslog( LOG_DEBUG, "setdeskmode: chmod %s: %m", modbuf );
260             }
261
262         }
263         closedir( sub );
264         /* XXX: need to preserve special modes */
265         if ( chmod( deskp->d_name,  DIRBITS | mode ) < 0 ) {
266             syslog( LOG_DEBUG, "setdeskmode: chmod %s: %m", deskp->d_name );
267         }
268     }
269     closedir( desk );
270     if ( chdir( wd ) < 0 ) {
271         syslog( LOG_ERR, "setdeskmode: chdir %s: %m", wd );
272         return -1;
273     }
274     /* XXX: need to preserve special modes */
275     if ( chmod( ".AppleDesktop",  DIRBITS | mode ) < 0 ) {
276         syslog( LOG_DEBUG, "setdeskmode: chmod .AppleDesktop: %m" );
277     }
278     return( 0 );
279 }
280
281 int setdirmode( mode, noadouble )
282     const mode_t mode;
283     const int noadouble;
284 {
285     char                buf[ MAXPATHLEN + 1];
286     struct stat         st;
287     char                *m;
288     struct dirent       *dirp;
289     DIR                 *dir;
290
291     if (( dir = opendir( "." )) == NULL ) {
292         syslog( LOG_ERR, "setdirmode: opendir .: %m" );
293         return( -1 );
294     }
295
296     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
297         if ( *dirp->d_name == '.' ) {
298             continue;
299         }
300         if ( stat( dirp->d_name, &st ) < 0 ) {
301             syslog( LOG_DEBUG, "setdirmode: stat %s: %m", dirp->d_name );
302             continue;
303         }
304
305         if (S_ISREG(st.st_mode)) {
306             /* XXX: need to preserve special modes */
307             if (S_ISDIR(st.st_mode)) {
308               stickydirmode(dirp->d_name, DIRBITS | mode);
309             } else
310               stickydirmode(dirp->d_name, mode);
311         }
312     }
313     closedir( dir );
314     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
315         if (noadouble)
316           goto setdirmode_noadouble;
317         syslog( LOG_ERR, "setdirmode: opendir .AppleDouble: %m" );
318         return( -1 );
319     }
320     strcpy( buf, ".AppleDouble" );
321     strcat( buf, "/" );
322     m = strchr( buf, '\0' );
323     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
324         if ( strcmp( dirp->d_name, "." ) == 0 ||
325                 strcmp( dirp->d_name, ".." ) == 0 ) {
326             continue;
327         }
328         *m = '\0';
329         strcat( buf, dirp->d_name );
330
331         if ( stat( buf, &st ) < 0 ) {
332             syslog( LOG_DEBUG, "setdirmode: stat %s: %m", buf );
333             continue;
334         }
335
336         if (S_ISDIR(st.st_mode)) {
337            stickydirmode( buf, DIRBITS | mode );
338         } else 
339            stickydirmode( buf, mode );
340     } /* end for */
341     closedir( dir );
342
343     /* XXX: use special bits to tag directory permissions */
344       
345     /* XXX: need to preserve special modes */
346     if ( stickydirmode(".AppleDouble", DIRBITS | mode) < 0 )
347         return( -1 );
348
349 setdirmode_noadouble:
350     /* XXX: need to preserve special modes */
351     if ( stickydirmode(".", DIRBITS | mode) < 0 )
352         return( -1 );
353     return( 0 );
354 }
355
356 int setdeskowner( uid, gid )
357     const uid_t uid;
358     const gid_t gid;
359 {
360     char                wd[ MAXPATHLEN + 1];
361     char                modbuf[12 + 1], *m;
362     struct dirent       *deskp, *subp;
363     DIR                 *desk, *sub;
364
365     if ( getcwd( wd, MAXPATHLEN ) == NULL ) {
366         return( -1 );
367     }
368     if ( chdir( ".AppleDesktop" ) < 0 ) {
369         return( -1 );
370     }
371     if (( desk = opendir( "." )) == NULL ) {
372         if ( chdir( wd ) < 0 ) {
373             syslog( LOG_ERR, "setdeskowner: chdir %s: %m", wd );
374         }
375         return( -1 );
376     }
377     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
378         if ( strcmp( deskp->d_name, "." ) == 0 ||
379              strcmp( deskp->d_name, ".." ) == 0 || 
380              strlen( deskp->d_name ) > 2 ) {
381             continue;
382         }
383         strcpy( modbuf, deskp->d_name );
384         strcat( modbuf, "/" );
385         m = strchr( modbuf, '\0' );
386         if (( sub = opendir( deskp->d_name )) == NULL ) {
387             continue;
388         }
389         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
390             if ( strcmp( subp->d_name, "." ) == 0 ||
391                  strcmp( subp->d_name, ".." ) == 0 ) {
392                 continue;
393             }
394             *m = '\0';
395             strcat( modbuf, subp->d_name );
396             /* XXX: add special any uid, ignore group bits */
397             if ( chown( modbuf, uid, gid ) < 0 ) {
398                 syslog( LOG_DEBUG, "setdeskown: chown %s: %m", modbuf );
399             }
400         }
401         closedir( sub );
402         /* XXX: add special any uid, ignore group bits */
403         if ( chown( deskp->d_name, uid, gid ) < 0 ) {
404             syslog( LOG_DEBUG, "setdeskowner: chown %s: %m", deskp->d_name );
405         }
406     }
407     closedir( desk );
408     if ( chdir( wd ) < 0 ) {
409         syslog( LOG_ERR, "setdeskowner: chdir %s: %m", wd );
410         return -1;
411     }
412     if ( chown( ".AppleDesktop", uid, gid ) < 0 ) {
413         syslog( LOG_ERR, "setdeskowner: chown .AppleDesktop: %m" );
414     }
415     return( 0 );
416 }
417
418
419 /* uid/gid == 0 need to be handled as special cases. they really mean
420  * that user/group should inherit from other, but that doesn't fit
421  * into the unix permission scheme. we can get around this by
422  * co-opting some bits. */
423 int setdirowner( uid, gid, noadouble )
424     const uid_t uid;
425     const gid_t gid;
426     const int   noadouble;
427 {
428     char                buf[ MAXPATHLEN + 1];
429     struct stat         st;
430     char                *m;
431     struct dirent       *dirp;
432     DIR                 *dir;
433
434     if (( dir = opendir( "." )) == NULL ) {
435         return( -1 );
436     }
437     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
438         if ( *dirp->d_name == '.' ) {
439             continue;
440         };
441         if ( stat( dirp->d_name, &st ) < 0 ) {
442             syslog( LOG_DEBUG, "setdirowner: stat %s: %m", dirp->d_name );
443             continue;
444         }
445         if (( st.st_mode & S_IFMT ) == S_IFREG ) {
446             if ( chown( dirp->d_name, uid, gid ) < 0 ) {
447                 syslog( LOG_DEBUG, "setdirowner: chown %s: %m", dirp->d_name );
448             }
449         }
450     }
451     closedir( dir );
452     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
453       if (noadouble)
454         goto setdirowner_noadouble;
455       return( -1 );
456     }
457     strcpy( buf, ".AppleDouble" );
458     strcat( buf, "/" );
459     m = strchr( buf, '\0' );
460     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
461         if ( strcmp( dirp->d_name, "." ) == 0 ||
462                 strcmp( dirp->d_name, ".." ) == 0 ) {
463             continue;
464         }
465         *m = '\0';
466         strcat( buf, dirp->d_name );
467         if ( chown( buf, uid, gid ) < 0 ) {
468             syslog( LOG_DEBUG, "setdirowner: chown %d/%d %s: %m",
469                     uid, gid, buf );
470         }
471     }
472     closedir( dir );
473
474     /*
475      * We cheat: we know that chown doesn't do anything.
476      */
477     if ( stat( ".AppleDouble", &st ) < 0 ) {
478         syslog( LOG_ERR, "setdirowner: stat .AppleDouble: %m" );
479         return( -1 );
480     }
481     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 ) {
482         syslog( LOG_DEBUG, "setdirowner: chown %d/%d .AppleDouble: %m",
483                 uid, gid);
484     }
485
486 setdirowner_noadouble:
487     if ( stat( ".", &st ) < 0 ) {
488         return( -1 );
489     }
490     if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 ) {
491         syslog( LOG_DEBUG, "setdirowner: chown %d/%d .: %m",
492                 uid, gid);
493     }
494
495     return( 0 );
496 }