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