]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/unix.c
Warning fixes.
[netatalk.git] / etc / afpd / unix.c
1 /*
2  * $Id: unix.c,v 1.20 2001-08-15 01:37:34 srittau Exp $
3  *
4  * Copyright (c) 1990,1993 Regents of The University of Michigan.
5  * All Rights Reserved.  See COPYRIGHT.
6  */
7
8 #ifdef HAVE_CONFIG_H
9 #include "config.h"
10 #endif /* HAVE_CONFIG_H */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/stat.h>
19 #include <sys/syslog.h>
20 #include <netatalk/endian.h>
21 #include <dirent.h>
22 #include <limits.h>
23 #include <atalk/afp.h>
24 #include <string.h>
25 #include <fcntl.h>
26 #include "auth.h"
27 #include "directory.h"
28 #include "volume.h"
29 #include "unix.h"
30
31 /*
32  * Get the free space on a partition.
33  */
34 int ustatfs_getvolspace( vol, bfree, btotal, bsize )
35     const struct vol    *vol;
36     VolSpace    *bfree, *btotal;
37     u_int32_t   *bsize;
38 {
39   VolSpace maxVolSpace = (~(VolSpace)0);
40   
41 #ifdef ultrix
42     struct fs_data      sfs;
43 #else /*ultrix*/
44     struct statfs       sfs;
45 #endif /*ultrix*/
46
47    
48     if ( statfs( vol->v_path, &sfs ) < 0 ) {
49          syslog(LOG_ERR, "ustatfs_getvolspace unable to stat %s", vol->v_path);
50          return( AFPERR_PARAM );
51     }
52
53 #ifdef ultrix
54     *bfree = (VolSpace) sfs.fd_req.bfreen;
55     *bsize = 1024;
56 #else /* !ultrix */
57     *bfree = (VolSpace) sfs.f_bavail;
58     *bsize = sfs.f_frsize;
59 #endif /* ultrix */
60
61     if ( *bfree > maxVolSpace / *bsize ) {
62         *bfree = maxVolSpace;
63     } else {
64         *bfree *= *bsize;
65     }
66
67 #ifdef ultrix
68     *btotal = (VolSpace) 
69       ( sfs.fd_req.btot - ( sfs.fd_req.bfree - sfs.fd_req.bfreen ));
70 #else /* !ultrix */
71     *btotal = (VolSpace) 
72       ( sfs.f_blocks - ( sfs.f_bfree - sfs.f_bavail ));
73 #endif /* ultrix */
74
75     // see similar block above comments
76     if ( *btotal > maxVolSpace / *bsize ) {
77         *btotal = maxVolSpace;
78     } else {
79         *btotal *= *bsize;
80     }
81
82     return( AFP_OK );
83 }
84
85 static __inline__ int utombits( bits )
86     mode_t      bits;
87 {
88     int         mbits;
89
90     mbits = 0;
91
92     mbits |= ( bits & ( S_IREAD >> 6 )) ? (AR_UREAD | AR_USEARCH) : 0;
93     mbits |= ( bits & ( S_IWRITE >> 6 )) ? AR_UWRITE : 0;
94 /* Do we really need this?
95     mbits |= ( bits & ( S_IEXEC >> 6) ) ? AR_USEARCH : 0; */
96
97     return( mbits );
98 }
99
100 void utommode( stat, ma )
101     struct stat         *stat;
102     struct maccess      *ma;
103 {
104     mode_t              mode;
105
106     mode = stat->st_mode;
107
108     ma->ma_world = utombits( mode );
109     mode = mode >> 3;
110
111     ma->ma_group = utombits( mode );
112     mode = mode >> 3;
113
114     ma->ma_owner = utombits( mode );
115
116     if ( (uuid == stat->st_uid) || (uuid == 0)) {
117         ma->ma_user = ma->ma_owner | AR_UOWN;
118     } else if ( gmem( stat->st_gid )) {
119         ma->ma_user = ma->ma_group;
120     } else {
121         ma->ma_user = ma->ma_world;
122     }
123
124     /*
125      * There are certain things the mac won't try if you don't have
126      * the "owner" bit set, even tho you can do these things on unix wiht
127      * only write permission.  What were the things?
128      */
129     if ( ma->ma_user & AR_UWRITE ) {
130         ma->ma_user |= AR_UOWN;
131     }
132 }
133
134
135 /*
136  * Calculate the mode for a directory using Posix access() calls to
137  * estimate permission, a la mdw.
138  */
139 void accessmode( path, ma, dir )
140     char                *path;
141     struct maccess      *ma;
142     struct dir          *dir;
143 {
144     if ( access( path, R_OK|W_OK|X_OK ) == 0 ) {
145         ma->ma_user = AR_UREAD|AR_UWRITE|AR_USEARCH|AR_UOWN;
146         ma->ma_owner = AR_UREAD|AR_UWRITE|AR_USEARCH;
147     } else if ( access( path, R_OK|X_OK ) == 0 ) {
148         ma->ma_user = AR_UREAD|AR_USEARCH;
149         ma->ma_owner = AR_UREAD|AR_USEARCH;
150     } else {
151         ma->ma_user = ma->ma_owner = 0;
152         if ( access( path, R_OK ) == 0 ) {
153             ma->ma_user |= AR_UREAD;
154             ma->ma_owner |= AR_UREAD;
155         }
156         if ( access( path, X_OK ) == 0 ) {
157             ma->ma_user |= AR_USEARCH;
158             ma->ma_owner |= AR_USEARCH;
159         }
160         if ( access( path, W_OK ) == 0 ) {
161             ma->ma_user |= AR_UWRITE|AR_UOWN;
162             ma->ma_owner |= AR_UWRITE;
163         }
164     }
165 }
166
167 int gmem( gid )
168     const gid_t gid;
169 {
170     int         i;
171
172     for ( i = 0; i < ngroups; i++ ) {
173         if ( groups[ i ] == gid ) {
174             return( 1 );
175         }
176     }
177     return( 0 );
178 }
179
180 static __inline__ mode_t mtoubits( bits )
181     u_char      bits;
182 {
183     mode_t      mode;
184
185     mode = 0;
186
187     mode |= ( bits & AR_UREAD ) ? ( (S_IREAD | S_IEXEC) >> 6 ) : 0;
188     mode |= ( bits & AR_UWRITE ) ? ( (S_IWRITE | S_IEXEC) >> 6 ) : 0;
189 /* I don't think there's a way to set the SEARCH bit by itself on a Mac
190     mode |= ( bits & AR_USEARCH ) ? ( S_IEXEC >> 6 ) : 0; */
191
192     return( mode );
193 }
194
195 mode_t mtoumode( ma )
196     struct maccess      *ma;
197 {
198     mode_t              mode;
199
200     mode = 0;
201     mode |= mtoubits( ma->ma_owner );
202     mode = mode << 3;
203
204     mode |= mtoubits( ma->ma_group );
205     mode = mode << 3;
206
207     mode |= mtoubits( ma->ma_world );
208
209     return( mode );
210 }
211
212 inline int stickydirmode(name, mode, dropbox)
213     char * name;
214     const mode_t mode;
215     const int dropbox;
216 {
217   int retval;
218 #ifdef DROPKLUDGE
219   int uid;
220 #endif /* DROPKLUDGE */
221   
222 /* Turn on the sticky bit if this is a drop box, also turn off the setgid bit */
223    retval=0;
224 #ifdef DROPKLUDGE
225    if (dropbox) {
226     if (mode & S_IWOTH) { 
227       if (mode & S_IROTH); 
228       else { /* if S_IWOTH and not S_IROTH */
229         uid=geteuid();
230         if ( seteuid(0) < 0) {
231            syslog( LOG_ERR, "stickydirmode: unable to seteuid root: %m");
232         }
233         if ( retval=chmod( name, ( DIRBITS | mode | S_ISVTX) ) < 0) {
234            syslog( LOG_ERR, "stickydirmode: chmod \"%s\": %m", name );
235            return(AFPERR_ACCESS);
236         } else {
237 #ifdef DEBUG
238            syslog( LOG_INFO, "stickydirmode: (debug) chmod \"%s\": %m", name );
239 #endif /* DEBUG */
240            seteuid(uid);
241         } /* end getting retval */
242       } /* end if not & S_IROTH */
243    } else { /* end if S_IWOTH and not S_IROTH */
244 #endif /* DROPKLUDGE */
245        if ( (retval=chmod( name, DIRBITS | mode )) < 0 )  {
246           syslog( LOG_ERR, "stickydirmode: chmod \"%s\": %s",
247                   name, strerror(errno) );
248        }
249 #ifdef DROPKLUDGE
250      } /* end if not mode */
251    } /* end checking for "dropbox" */
252 #endif /* DROPKLUDGE */
253    return retval;
254 }
255
256 int setdeskmode( mode )
257     const mode_t        mode;
258 {
259     char                wd[ MAXPATHLEN + 1];
260     struct stat         st;
261     char                modbuf[ 12 + 1], *m;
262     struct dirent       *deskp, *subp;
263     DIR                 *desk, *sub;
264
265     if ( getcwd( wd , MAXPATHLEN) == NULL ) {
266         return( -1 );
267     }
268     if ( chdir( ".AppleDesktop" ) < 0 ) {
269         return( -1 );
270     }
271     if (( desk = opendir( "." )) == NULL ) {
272         if ( chdir( wd ) < 0 ) {
273             syslog( LOG_ERR, "setdeskmode: chdir %s: %s", wd, strerror(errno) );
274         }
275         return( -1 );
276     }
277     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
278         if ( strcmp( deskp->d_name, "." ) == 0 ||
279                 strcmp( deskp->d_name, ".." ) == 0 || strlen( deskp->d_name ) > 2 ) {
280             continue;
281         }
282         strcpy( modbuf, deskp->d_name );
283         strcat( modbuf, "/" );
284         m = strchr( modbuf, '\0' );
285         if (( sub = opendir( deskp->d_name )) == NULL ) {
286             continue;
287         }
288         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
289             if ( strcmp( subp->d_name, "." ) == 0 ||
290                     strcmp( subp->d_name, ".." ) == 0 ) {
291                 continue;
292             }
293             *m = '\0';
294             strcat( modbuf, subp->d_name );
295             /* XXX: need to preserve special modes */
296             if (stat(modbuf, &st) < 0) {
297                 syslog( LOG_ERR, "setdeskmode: stat %s: %s",
298                         modbuf, strerror(errno) );
299                 continue;
300             }       
301
302             if (S_ISDIR(st.st_mode)) {
303               if ( chmod( modbuf,  DIRBITS | mode ) < 0 ) {
304                 syslog( LOG_ERR, "setdeskmode: chmod %s: %s",
305                         modbuf, strerror(errno) );
306               }
307             } else if ( chmod( modbuf,  mode ) < 0 ) {
308                 syslog( LOG_ERR, "setdeskmode: chmod %s: %s",
309                         modbuf, strerror(errno) );
310             }
311
312         }
313         closedir( sub );
314         /* XXX: need to preserve special modes */
315         if ( chmod( deskp->d_name,  DIRBITS | mode ) < 0 ) {
316             syslog( LOG_ERR, "setdeskmode: chmod %s: %s",
317                     deskp->d_name, strerror(errno) );
318         }
319     }
320     closedir( desk );
321     if ( chdir( wd ) < 0 ) {
322         syslog( LOG_ERR, "setdeskmode: chdir %s: %s", wd, strerror(errno) );
323         return -1;
324     }
325     /* XXX: need to preserve special modes */
326     if ( chmod( ".AppleDesktop",  DIRBITS | mode ) < 0 ) {
327         syslog( LOG_ERR, "setdeskmode: chmod .AppleDesktop: %s", strerror(errno) );
328     }
329     return( 0 );
330 }
331
332 int setdirmode( mode, noadouble, dropbox )
333     const mode_t mode;
334     const int noadouble;
335     const int dropbox;
336 {
337     char                buf[ MAXPATHLEN + 1];
338     struct stat         st;
339     char                *m;
340     struct dirent       *dirp;
341     DIR                 *dir;
342
343     if (( dir = opendir( "." )) == NULL ) {
344         syslog( LOG_ERR, "setdirmode: opendir .: %s", strerror(errno) );
345         return( -1 );
346     }
347
348     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
349         if ( *dirp->d_name == '.' ) {
350             continue;
351         }
352         if ( stat( dirp->d_name, &st ) < 0 ) {
353             syslog( LOG_ERR, "setdirmode: stat %s: %s",
354                     dirp->d_name, strerror(errno) );
355             continue;
356         }
357
358         if (S_ISREG(st.st_mode)) {
359             /* XXX: need to preserve special modes */
360             if (S_ISDIR(st.st_mode)) {
361               if (stickydirmode(dirp->d_name, DIRBITS | mode, dropbox) < 0)
362                 return (-1);
363             } else if (stickydirmode(dirp->d_name, mode, dropbox) < 0)
364                 return (-1);
365         }
366     }
367     closedir( dir );
368     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
369         if (noadouble)
370           goto setdirmode_noadouble;
371         syslog( LOG_ERR, "setdirmode: opendir .AppleDouble: %s", strerror(errno) );
372         return( -1 );
373     }
374     strcpy( buf, ".AppleDouble" );
375     strcat( buf, "/" );
376     m = strchr( buf, '\0' );
377     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
378         if ( strcmp( dirp->d_name, "." ) == 0 ||
379                 strcmp( dirp->d_name, ".." ) == 0 ) {
380             continue;
381         }
382         *m = '\0';
383         strcat( buf, dirp->d_name );
384
385         if ( stat( buf, &st ) < 0 ) {
386             syslog( LOG_ERR, "setdirmode: stat %s: %s", buf, strerror(errno) );
387             continue;
388         }
389
390         if (S_ISDIR(st.st_mode)) {
391            stickydirmode( buf, DIRBITS | mode, dropbox );
392         } else 
393            stickydirmode( buf, mode, dropbox );
394     } /* end for */
395     closedir( dir );
396
397     /* XXX: use special bits to tag directory permissions */
398       
399     /* XXX: need to preserve special modes */
400     if ( stickydirmode(".AppleDouble", DIRBITS | mode, dropbox) < 0 )
401         return( -1 );
402
403 setdirmode_noadouble:
404     /* XXX: need to preserve special modes */
405     if ( stickydirmode(".", DIRBITS | mode, dropbox) < 0 )
406         return( -1 );
407     return( 0 );
408 }
409
410 int setdeskowner( uid, gid )
411     const uid_t uid;
412     const gid_t gid;
413 {
414     char                wd[ MAXPATHLEN + 1];
415     char                modbuf[12 + 1], *m;
416     struct dirent       *deskp, *subp;
417     DIR                 *desk, *sub;
418
419     if ( getcwd( wd, MAXPATHLEN ) == NULL ) {
420         return( -1 );
421     }
422     if ( chdir( ".AppleDesktop" ) < 0 ) {
423         return( -1 );
424     }
425     if (( desk = opendir( "." )) == NULL ) {
426         if ( chdir( wd ) < 0 ) {
427             syslog( LOG_ERR, "setdeskowner: chdir %s: %s", wd, strerror(errno) );
428         }
429         return( -1 );
430     }
431     for ( deskp = readdir( desk ); deskp != NULL; deskp = readdir( desk )) {
432         if ( strcmp( deskp->d_name, "." ) == 0 ||
433              strcmp( deskp->d_name, ".." ) == 0 || 
434              strlen( deskp->d_name ) > 2 ) {
435             continue;
436         }
437         strcpy( modbuf, deskp->d_name );
438         strcat( modbuf, "/" );
439         m = strchr( modbuf, '\0' );
440         if (( sub = opendir( deskp->d_name )) == NULL ) {
441             continue;
442         }
443         for ( subp = readdir( sub ); subp != NULL; subp = readdir( sub )) {
444             if ( strcmp( subp->d_name, "." ) == 0 ||
445                  strcmp( subp->d_name, ".." ) == 0 ) {
446                 continue;
447             }
448             *m = '\0';
449             strcat( modbuf, subp->d_name );
450             /* XXX: add special any uid, ignore group bits */
451             if ( chown( modbuf, uid, gid ) < 0 ) {
452                 syslog( LOG_ERR, "setdeskown: chown %s: %s",
453                         modbuf, strerror(errno) );
454             }
455         }
456         closedir( sub );
457         /* XXX: add special any uid, ignore group bits */
458         if ( chown( deskp->d_name, uid, gid ) < 0 ) {
459             syslog( LOG_ERR, "setdeskowner: chown %s: %s",
460                     deskp->d_name, strerror(errno) );
461         }
462     }
463     closedir( desk );
464     if ( chdir( wd ) < 0 ) {
465         syslog( LOG_ERR, "setdeskowner: chdir %s: %s", wd, strerror(errno) );
466         return -1;
467     }
468     if ( chown( ".AppleDesktop", uid, gid ) < 0 ) {
469         syslog( LOG_ERR, "setdeskowner: chown .AppleDesktop: %s",
470                 strerror(errno) );
471     }
472     return( 0 );
473 }
474
475
476 /* uid/gid == 0 need to be handled as special cases. they really mean
477  * that user/group should inherit from other, but that doesn't fit
478  * into the unix permission scheme. we can get around this by
479  * co-opting some bits. */
480 int setdirowner( uid, gid, noadouble )
481     const uid_t uid;
482     const gid_t gid;
483     const int   noadouble;
484 {
485     char                buf[ MAXPATHLEN + 1];
486     struct stat         st;
487     char                *m;
488     struct dirent       *dirp;
489     DIR                 *dir;
490
491     if (( dir = opendir( "." )) == NULL ) {
492         return( -1 );
493     }
494     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
495         if ( *dirp->d_name == '.' ) {
496             continue;
497         };
498         if ( stat( dirp->d_name, &st ) < 0 ) {
499             syslog( LOG_ERR, "setdirowner: stat %s: %s",
500                     dirp->d_name, strerror(errno) );
501             continue;
502         }
503         if (( st.st_mode & S_IFMT ) == S_IFREG ) {
504             if ( chown( dirp->d_name, uid, gid ) < 0 ) {
505                 syslog( LOG_DEBUG, "setdirowner: chown %s: %s",
506                         dirp->d_name, strerror(errno) );
507                 /* return ( -1 ); Sometimes this is okay */
508             }
509         }
510     }
511     closedir( dir );
512     if (( dir = opendir( ".AppleDouble" )) == NULL ) {
513       if (noadouble)
514         goto setdirowner_noadouble;
515       return( -1 );
516     }
517     strcpy( buf, ".AppleDouble" );
518     strcat( buf, "/" );
519     m = strchr( buf, '\0' );
520     for ( dirp = readdir( dir ); dirp != NULL; dirp = readdir( dir )) {
521         if ( strcmp( dirp->d_name, "." ) == 0 ||
522                 strcmp( dirp->d_name, ".." ) == 0 ) {
523             continue;
524         }
525         *m = '\0';
526         strcat( buf, dirp->d_name );
527         if ( chown( buf, uid, gid ) < 0 ) {
528             syslog( LOG_DEBUG, "setdirowner: chown %d/%d %s: %s",
529                     uid, gid, buf, strerror(errno) );
530             /* return ( -1 ); Sometimes this is okay */
531         }
532     }
533     closedir( dir );
534
535     /*
536      * We cheat: we know that chown doesn't do anything.
537      */
538     if ( stat( ".AppleDouble", &st ) < 0 ) {
539         syslog( LOG_ERR, "setdirowner: stat .AppleDouble: %s", strerror(errno) );
540         return( -1 );
541     }
542     if ( gid && gid != st.st_gid && chown( ".AppleDouble", uid, gid ) < 0 ) {
543         syslog( LOG_DEBUG, "setdirowner: chown %d/%d .AppleDouble: %s",
544                 uid, gid, strerror(errno) );
545         /* return ( -1 ); Sometimes this is okay */
546     }
547
548 setdirowner_noadouble:
549     if ( stat( ".", &st ) < 0 ) {
550         return( -1 );
551     }
552     if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 ) {
553         syslog( LOG_DEBUG, "setdirowner: chown %d/%d .: %s",
554                 uid, gid, strerror(errno) );
555     }
556
557     return( 0 );
558 }