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