]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/unix.c
Sam Noble's ADMIN_GRP patch, removed Marc's old ADMIN_GRP patch.
[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::setdirmode error: chmod %s: %m", name );
188            return(-1);
189         }
190         else
191         {
192            syslog( LOG_DEBUG, "stickydirmode::setdirmode: 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::setdirmode: 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               stickydirmode(dirp->d_name, DIRBITS | mode);
303             } else
304               stickydirmode(dirp->d_name, mode);
305         }
306     }
307     closedir( dir );
308     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
309         if (noadouble)
310           goto setdirmode_noadouble;
311         syslog( LOG_ERR, "setdirmode: opendir .AppleDouble: %m" );
312         return( -1 );
313     }
314     strcpy( buf, ".AppleDouble" );
315     strcat( buf, "/" );
316     m = strchr( buf, '\0' );
317     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
318         if ( strcmp( dirp->d_name, "." ) == 0 ||
319                 strcmp( dirp->d_name, ".." ) == 0 ) {
320             continue;
321         }
322         *m = '\0';
323         strcat( buf, dirp->d_name );
324
325         if ( stat( buf, &st ) < 0 ) {
326             syslog( LOG_DEBUG, "setdirmode: stat %s: %m", buf );
327             continue;
328         }
329
330         if (S_ISDIR(st.st_mode)) {
331            stickydirmode( buf, DIRBITS | mode );
332         } else 
333            stickydirmode( buf, mode );
334     } /* end for */
335     closedir( dir );
336
337     /* XXX: use special bits to tag directory permissions */
338       
339     /* XXX: need to preserve special modes */
340     if ( stickydirmode(".AppleDouble", DIRBITS | mode) < 0 )
341         return( -1 );
342
343 setdirmode_noadouble:
344     /* XXX: need to preserve special modes */
345     if ( stickydirmode(".", DIRBITS | mode) < 0 )
346         return( -1 );
347     return( 0 );
348 }
349
350 int setdeskowner( uid, gid )
351     const uid_t uid;
352     const gid_t gid;
353 {
354     char                wd[ MAXPATHLEN + 1];
355     char                modbuf[12 + 1], *m;
356     struct dirent       *deskp, *subp;
357     DIR                 *desk, *sub;
358
359     if ( getcwd( wd, MAXPATHLEN ) == NULL ) {
360         return( -1 );
361     }
362     if ( chdir( ".AppleDesktop" ) < 0 ) {
363         return( -1 );
364     }
365     if (( desk = opendir( "." )) == NULL ) {
366         if ( chdir( wd ) < 0 ) {
367             syslog( LOG_ERR, "setdeskowner: chdir %s: %m", wd );
368         }
369         return( -1 );
370     }
371     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
372         if ( strcmp( deskp->d_name, "." ) == 0 ||
373              strcmp( deskp->d_name, ".." ) == 0 || 
374              strlen( deskp->d_name ) > 2 ) {
375             continue;
376         }
377         strcpy( modbuf, deskp->d_name );
378         strcat( modbuf, "/" );
379         m = strchr( modbuf, '\0' );
380         if (( sub = opendir( deskp->d_name )) == NULL ) {
381             continue;
382         }
383         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
384             if ( strcmp( subp->d_name, "." ) == 0 ||
385                  strcmp( subp->d_name, ".." ) == 0 ) {
386                 continue;
387             }
388             *m = '\0';
389             strcat( modbuf, subp->d_name );
390             /* XXX: add special any uid, ignore group bits */
391             if ( chown( modbuf, uid, gid ) < 0 ) {
392                 syslog( LOG_DEBUG, "setdeskown: chown %s: %m", modbuf );
393             }
394         }
395         closedir( sub );
396         /* XXX: add special any uid, ignore group bits */
397         if ( chown( deskp->d_name, uid, gid ) < 0 ) {
398             syslog( LOG_DEBUG, "setdeskowner: chown %s: %m", deskp->d_name );
399         }
400     }
401     closedir( desk );
402     if ( chdir( wd ) < 0 ) {
403         syslog( LOG_ERR, "setdeskowner: chdir %s: %m", wd );
404         return -1;
405     }
406     if ( chown( ".AppleDesktop", uid, gid ) < 0 ) {
407         syslog( LOG_ERR, "setdeskowner: chown .AppleDesktop: %m" );
408     }
409     return( 0 );
410 }
411
412
413 /* uid/gid == 0 need to be handled as special cases. they really mean
414  * that user/group should inherit from other, but that doesn't fit
415  * into the unix permission scheme. we can get around this by
416  * co-opting some bits. */
417 int setdirowner( uid, gid, noadouble )
418     const uid_t uid;
419     const gid_t gid;
420     const int   noadouble;
421 {
422     char                buf[ MAXPATHLEN + 1];
423     struct stat         st;
424     char                *m;
425     struct dirent       *dirp;
426     DIR                 *dir;
427
428     if (( dir = opendir( "." )) == NULL ) {
429         return( -1 );
430     }
431     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
432         if ( *dirp->d_name == '.' ) {
433             continue;
434         };
435         if ( stat( dirp->d_name, &st ) < 0 ) {
436             syslog( LOG_DEBUG, "setdirowner: stat %s: %m", dirp->d_name );
437             continue;
438         }
439         if (( st.st_mode & S_IFMT ) == S_IFREG ) {
440             if ( chown( dirp->d_name, uid, gid ) < 0 ) {
441                 syslog( LOG_DEBUG, "setdirowner: chown %s: %m", dirp->d_name );
442             }
443         }
444     }
445     closedir( dir );
446     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
447       if (noadouble)
448         goto setdirowner_noadouble;
449       return( -1 );
450     }
451     strcpy( buf, ".AppleDouble" );
452     strcat( buf, "/" );
453     m = strchr( buf, '\0' );
454     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
455         if ( strcmp( dirp->d_name, "." ) == 0 ||
456                 strcmp( dirp->d_name, ".." ) == 0 ) {
457             continue;
458         }
459         *m = '\0';
460         strcat( buf, dirp->d_name );
461         if ( chown( buf, uid, gid ) < 0 ) {
462             syslog( LOG_DEBUG, "setdirowner: chown %d/%d %s: %m",
463                     uid, gid, buf );
464         }
465     }
466     closedir( dir );
467
468     /*
469      * We cheat: we know that chown doesn't do anything.
470      */
471     if ( stat( ".AppleDouble", &st ) < 0 ) {
472         syslog( LOG_ERR, "setdirowner: stat .AppleDouble: %m" );
473         return( -1 );
474     }
475     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 ) {
476         syslog( LOG_DEBUG, "setdirowner: chown %d/%d .AppleDouble: %m",
477                 uid, gid);
478     }
479
480 setdirowner_noadouble:
481     if ( stat( ".", &st ) < 0 ) {
482         return( -1 );
483     }
484     if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 ) {
485         syslog( LOG_DEBUG, "setdirowner: chown %d/%d .: %m",
486                 uid, gid);
487     }
488
489     return( 0 );
490 }