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