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