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