]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/unix.c
General fixes for logging, error reporting, this, that, and the other thing.
[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         if ( seteuid(0) < 0)
196            syslog( LOG_ERR, "stickydirmode: unable to seteuid root: %m");
197         if ( retval=chmod( name, (DIRBITS | mode | S_ISVTX)) < 0)
198         {
199            syslog( LOG_ERR, "stickydirmode: chmod %s: %m", name );
200            return(AFPERR_ACCESS);
201         }
202         else
203         {
204 #ifdef DEBUG
205            syslog( LOG_INFO, "stickydirmode: chmod \"%s\": %m", name );
206 #endif
207            seteuid(uid);
208         }
209       }
210    else 
211 #endif DROPKLUDGE
212        if ( retval=chmod( name, DIRBITS | mode ) < 0 ) 
213           syslog( LOG_ERR, "stickydirmode: chmod \"%s\": %m", name );
214    return retval;
215 }
216
217 int setdeskmode( mode )
218     const mode_t        mode;
219 {
220     char                wd[ MAXPATHLEN + 1];
221     struct stat         st;
222     char                modbuf[ 12 + 1], *m;
223     struct dirent       *deskp, *subp;
224     DIR                 *desk, *sub;
225
226     if ( getcwd( wd , MAXPATHLEN) == NULL ) {
227         return( -1 );
228     }
229     if ( chdir( ".AppleDesktop" ) < 0 ) {
230         return( -1 );
231     }
232     if (( desk = opendir( "." )) == NULL ) {
233         if ( chdir( wd ) < 0 ) {
234             syslog( LOG_ERR, "setdeskmode: chdir %s: %m", wd );
235         }
236         return( -1 );
237     }
238     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
239         if ( strcmp( deskp->d_name, "." ) == 0 ||
240                 strcmp( deskp->d_name, ".." ) == 0 || strlen( deskp->d_name ) > 2 ) {
241             continue;
242         }
243         strcpy( modbuf, deskp->d_name );
244         strcat( modbuf, "/" );
245         m = strchr( modbuf, '\0' );
246         if (( sub = opendir( deskp->d_name )) == NULL ) {
247             continue;
248         }
249         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
250             if ( strcmp( subp->d_name, "." ) == 0 ||
251                     strcmp( subp->d_name, ".." ) == 0 ) {
252                 continue;
253             }
254             *m = '\0';
255             strcat( modbuf, subp->d_name );
256             /* XXX: need to preserve special modes */
257             if (stat(modbuf, &st) < 0) {
258                 syslog( LOG_ERR, "setdeskmode: stat %s: %m", modbuf );
259                 continue;
260             }       
261
262             if (S_ISDIR(st.st_mode)) {
263               if ( chmod( modbuf,  DIRBITS | mode ) < 0 ) {
264                 syslog( LOG_ERR, "setdeskmode: chmod %s: %m", modbuf );
265               }
266             } else if ( chmod( modbuf,  mode ) < 0 ) {
267                 syslog( LOG_ERR, "setdeskmode: chmod %s: %m", modbuf );
268             }
269
270         }
271         closedir( sub );
272         /* XXX: need to preserve special modes */
273         if ( chmod( deskp->d_name,  DIRBITS | mode ) < 0 ) {
274             syslog( LOG_ERR, "setdeskmode: chmod %s: %m", deskp->d_name );
275         }
276     }
277     closedir( desk );
278     if ( chdir( wd ) < 0 ) {
279         syslog( LOG_ERR, "setdeskmode: chdir %s: %m", wd );
280         return -1;
281     }
282     /* XXX: need to preserve special modes */
283     if ( chmod( ".AppleDesktop",  DIRBITS | mode ) < 0 ) {
284         syslog( LOG_ERR, "setdeskmode: chmod .AppleDesktop: %m" );
285     }
286     return( 0 );
287 }
288
289 int setdirmode( mode, noadouble )
290     const mode_t mode;
291     const int noadouble;
292 {
293     char                buf[ MAXPATHLEN + 1];
294     struct stat         st;
295     char                *m;
296     struct dirent       *dirp;
297     DIR                 *dir;
298
299     if (( dir = opendir( "." )) == NULL ) {
300         syslog( LOG_ERR, "setdirmode: opendir .: %m" );
301         return( -1 );
302     }
303
304     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
305         if ( *dirp->d_name == '.' ) {
306             continue;
307         }
308         if ( stat( dirp->d_name, &st ) < 0 ) {
309             syslog( LOG_ERR, "setdirmode: stat %s: %m", dirp->d_name );
310             continue;
311         }
312
313         if (S_ISREG(st.st_mode)) {
314             /* XXX: need to preserve special modes */
315             if (S_ISDIR(st.st_mode)) {
316               if (stickydirmode(dirp->d_name, DIRBITS | mode) < 0)
317                 return (-1);
318             } else if (stickydirmode(dirp->d_name, mode) < 0)
319                 return (-1);
320         }
321     }
322     closedir( dir );
323     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
324         if (noadouble)
325           goto setdirmode_noadouble;
326         syslog( LOG_ERR, "setdirmode: opendir .AppleDouble: %m" );
327         return( -1 );
328     }
329     strcpy( buf, ".AppleDouble" );
330     strcat( buf, "/" );
331     m = strchr( buf, '\0' );
332     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
333         if ( strcmp( dirp->d_name, "." ) == 0 ||
334                 strcmp( dirp->d_name, ".." ) == 0 ) {
335             continue;
336         }
337         *m = '\0';
338         strcat( buf, dirp->d_name );
339
340         if ( stat( buf, &st ) < 0 ) {
341             syslog( LOG_ERR, "setdirmode: stat %s: %m", buf );
342             continue;
343         }
344
345         if (S_ISDIR(st.st_mode)) {
346            stickydirmode( buf, DIRBITS | mode );
347         } else 
348            stickydirmode( buf, mode );
349     } /* end for */
350     closedir( dir );
351
352     /* XXX: use special bits to tag directory permissions */
353       
354     /* XXX: need to preserve special modes */
355     if ( stickydirmode(".AppleDouble", DIRBITS | mode) < 0 )
356         return( -1 );
357
358 setdirmode_noadouble:
359     /* XXX: need to preserve special modes */
360     if ( stickydirmode(".", DIRBITS | mode) < 0 )
361         return( -1 );
362     return( 0 );
363 }
364
365 int setdeskowner( uid, gid )
366     const uid_t uid;
367     const gid_t gid;
368 {
369     char                wd[ MAXPATHLEN + 1];
370     char                modbuf[12 + 1], *m;
371     struct dirent       *deskp, *subp;
372     DIR                 *desk, *sub;
373
374     if ( getcwd( wd, MAXPATHLEN ) == NULL ) {
375         return( -1 );
376     }
377     if ( chdir( ".AppleDesktop" ) < 0 ) {
378         return( -1 );
379     }
380     if (( desk = opendir( "." )) == NULL ) {
381         if ( chdir( wd ) < 0 ) {
382             syslog( LOG_ERR, "setdeskowner: chdir %s: %m", wd );
383         }
384         return( -1 );
385     }
386     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
387         if ( strcmp( deskp->d_name, "." ) == 0 ||
388              strcmp( deskp->d_name, ".." ) == 0 || 
389              strlen( deskp->d_name ) > 2 ) {
390             continue;
391         }
392         strcpy( modbuf, deskp->d_name );
393         strcat( modbuf, "/" );
394         m = strchr( modbuf, '\0' );
395         if (( sub = opendir( deskp->d_name )) == NULL ) {
396             continue;
397         }
398         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
399             if ( strcmp( subp->d_name, "." ) == 0 ||
400                  strcmp( subp->d_name, ".." ) == 0 ) {
401                 continue;
402             }
403             *m = '\0';
404             strcat( modbuf, subp->d_name );
405             /* XXX: add special any uid, ignore group bits */
406             if ( chown( modbuf, uid, gid ) < 0 ) {
407                 syslog( LOG_ERR, "setdeskown: chown %s: %m", modbuf );
408             }
409         }
410         closedir( sub );
411         /* XXX: add special any uid, ignore group bits */
412         if ( chown( deskp->d_name, uid, gid ) < 0 ) {
413             syslog( LOG_ERR, "setdeskowner: chown %s: %m", deskp->d_name );
414         }
415     }
416     closedir( desk );
417     if ( chdir( wd ) < 0 ) {
418         syslog( LOG_ERR, "setdeskowner: chdir %s: %m", wd );
419         return -1;
420     }
421     if ( chown( ".AppleDesktop", uid, gid ) < 0 ) {
422         syslog( LOG_ERR, "setdeskowner: chown .AppleDesktop: %m" );
423     }
424     return( 0 );
425 }
426
427
428 /* uid/gid == 0 need to be handled as special cases. they really mean
429  * that user/group should inherit from other, but that doesn't fit
430  * into the unix permission scheme. we can get around this by
431  * co-opting some bits. */
432 int setdirowner( uid, gid, noadouble )
433     const uid_t uid;
434     const gid_t gid;
435     const int   noadouble;
436 {
437     char                buf[ MAXPATHLEN + 1];
438     struct stat         st;
439     char                *m;
440     struct dirent       *dirp;
441     DIR                 *dir;
442
443     if (( dir = opendir( "." )) == NULL ) {
444         return( -1 );
445     }
446     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
447         if ( *dirp->d_name == '.' ) {
448             continue;
449         };
450         if ( stat( dirp->d_name, &st ) < 0 ) {
451             syslog( LOG_ERR, "setdirowner: stat %s: %m", dirp->d_name );
452             continue;
453         }
454         if (( st.st_mode & S_IFMT ) == S_IFREG ) {
455             if ( chown( dirp->d_name, uid, gid ) < 0 ) {
456                 syslog( LOG_ERR, "setdirowner: chown %s: %m", dirp->d_name );
457             }
458         }
459     }
460     closedir( dir );
461     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
462       if (noadouble)
463         goto setdirowner_noadouble;
464       return( -1 );
465     }
466     strcpy( buf, ".AppleDouble" );
467     strcat( buf, "/" );
468     m = strchr( buf, '\0' );
469     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
470         if ( strcmp( dirp->d_name, "." ) == 0 ||
471                 strcmp( dirp->d_name, ".." ) == 0 ) {
472             continue;
473         }
474         *m = '\0';
475         strcat( buf, dirp->d_name );
476         if ( chown( buf, uid, gid ) < 0 ) {
477             syslog( LOG_ERR, "setdirowner: chown %d/%d %s: %m",
478                     uid, gid, buf );
479         }
480     }
481     closedir( dir );
482
483     /*
484      * We cheat: we know that chown doesn't do anything.
485      */
486     if ( stat( ".AppleDouble", &st ) < 0 ) {
487         syslog( LOG_ERR, "setdirowner: stat .AppleDouble: %m" );
488         return( -1 );
489     }
490     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 ) {
491         syslog( LOG_ERR, "setdirowner: chown %d/%d .AppleDouble: %m",
492                 uid, gid);
493     }
494
495 setdirowner_noadouble:
496     if ( stat( ".", &st ) < 0 ) {
497         return( -1 );
498     }
499     if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 ) {
500         syslog( LOG_ERR, "setdirowner: chown %d/%d .: %m",
501                 uid, gid);
502     }
503
504     return( 0 );
505 }