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