1/*
2 * $Id: afs.c,v 1.18 2009-10-15 10:43:13 didg Exp $
3 * Copyright (c) 1990,1993 Regents of The University of Michigan.
4 * All Rights Reserved.  See COPYRIGHT.
5 */
6
7#ifdef HAVE_CONFIG_H
8#include "config.h"
9#endif /* HAVE_CONFIG_H */
10
11#ifdef AFS
12
13#include <string.h>
14#include <sys/types.h>
15#include <atalk/logger.h>
16#include <netatalk/endian.h>
17#include <netinet/in.h>
18#include <afs/venus.h>
19#include <afs/afsint.h>
20#include <atalk/afp.h>
21#ifdef HAVE_UNISTD_H
22#include <unistd.h>
23#endif /* HAVE_UNISTD_H */
24#include <sys/stat.h>
25
26#include "globals.h"
27#include "directory.h"
28#include "volume.h"
29#include "misc.h"
30#include "unix.h"
31
32int afs_getvolspace(struct vol *vol, VolSpace *bfree, VolSpace *btotal, u_int32_t *bsize)
33{
34    struct ViceIoctl	vi;
35    struct VolumeStatus	*vs;
36    char		venuspace[ sizeof( struct VolumeStatus ) + 3 ];
37    int			total, free;
38
39    vi.in_size = 0;
40    vi.out_size = sizeof( venuspace );
41    vi.out = venuspace;
42    if ( pioctl( vol->v_path, VIOCGETVOLSTAT, &vi, 1 ) < 0 ) {
43        return( AFPERR_PARAM );
44    }
45
46    vs = (struct VolumeStatus *)venuspace;
47
48    if ( vs->PartBlocksAvail > 0 ) {
49        if ( vs->MaxQuota != 0 ) {
50#ifdef min
51#undef min
52#endif
53#define min(x,y)	(((x)<(y))?(x):(y))
54            free = min( vs->MaxQuota - vs->BlocksInUse, vs->PartBlocksAvail );
55        } else {
56            free = vs->PartBlocksAvail;
57        }
58    } else {
59        free = 0;
60    }
61
62    if ( vs->MaxQuota != 0 ) {
63        total = free + vs->BlocksInUse;
64    } else {
65        total = vs->PartMaxBlocks;
66    }
67
68    *bsize = 1024;
69    *bfree = (VolSpace) free * 1024;
70    *btotal = (VolSpace) total * 1024;
71
72    return( AFP_OK );
73}
74
75int afp_getdiracl(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
76{
77    struct ViceIoctl	vi;
78    struct vol		*vol;
79    struct dir		*dir;
80    struct path		*path;
81    u_int32_t		did;
82    u_int16_t		vid;
83
84    ibuf += 2;
85    memcpy( &vid, ibuf, sizeof( vid ));
86    ibuf += sizeof( short );
87    if (( vol = getvolbyvid( vid )) == NULL ) {
88        *rbuflen = 0;
89        return( AFPERR_PARAM );
90    }
91
92    memcpy( &did, ibuf, sizeof( did ));
93    ibuf += sizeof( int );
94    if (( dir = dirlookup( vol, did )) == NULL ) {
95        *rbuflen = 0;
96        return afp_errno;
97    }
98
99    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
100        *rbuflen = 0;
101        return get_afp_errno(AFPERR_PARAM);
102    }
103    if ( *path->m_name != '\0' ) {
104        *rbuflen = 0;
105        return (path_isadir( path))? afp_errno: AFPERR_BITMAP;
106    }
107
108    vi.in_size = 0;
109    vi.out_size = *rbuflen;
110    vi.out = rbuf;
111    if ( pioctl( ".", VIOCGETAL, &vi, 1 ) < 0 ) {
112        *rbuflen = 0;
113        return( AFPERR_PARAM );
114    }
115    *rbuflen = strlen( vi.out ) + 1;
116    return( AFP_OK );
117}
118
119/*
120 * Calculate the mode for a directory in AFS.  First, make sure the
121 * directory is in AFS.  Could probably use something less heavy than
122 * VIOCGETAL.  If the directory is on AFS, use access() calls to
123 * estimate permission, a la mdw.
124 */
125#ifdef accessmode
126    #undef accessmode
127#endif
128
129void afsmode(const struct volume *vol, char *path, struct maccess *ma, struct dir *dir, struct stat *st)
130{
131    struct ViceIoctl	vi;
132    char		buf[ 1024 ];
133
134    if (( dir->d_flags & DIRF_FSMASK ) == DIRF_NOFS ) {
135        vi.in_size = 0;
136        vi.out_size = sizeof( buf );
137        vi.out = buf;
138        if ( pioctl( path, VIOCGETAL, &vi, 1 ) < 0 ) {
139            dir->d_flags |= DIRF_UFS;
140        } else {
141            dir->d_flags |= DIRF_AFS;
142        }
143    }
144
145    if (( dir->d_flags & DIRF_FSMASK ) != DIRF_AFS ) {
146        return;
147    }
148
149    accessmode(vol, path, ma, dir, st );
150
151    return;
152}
153
154extern struct dir	*curdir;
155/*
156 * cmd | 0 | vid | did | pathtype | pathname | 0 | acl
157 */
158int afp_setdiracl(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
159{
160    struct ViceIoctl	vi;
161    struct vol		*vol;
162    struct dir		*dir;
163    char		*iend;
164    struct path		*path;
165    u_int32_t		did;
166    u_int16_t		vid;
167
168    *rbuflen = 0;
169    iend = ibuf + ibuflen;
170    ibuf += 2;
171    memcpy( &vid, ibuf, sizeof( vid ));
172    ibuf += sizeof( short );
173    if (( vol = getvolbyvid( vid )) == NULL ) {
174        *rbuflen = 0;
175        return( AFPERR_PARAM );
176    }
177
178    memcpy( &did, ibuf, sizeof( did ));
179    ibuf += sizeof( int );
180    if (( dir = dirlookup( vol, did )) == NULL ) {
181        *rbuflen = 0;
182        return afp_errno;
183    }
184
185    if (( path = cname( vol, dir, &ibuf )) == NULL ) {
186        *rbuflen = 0;
187        return get_afp_errno(AFPERR_PARAM);
188    }
189    if ( *path->m_name != '\0' ) {
190        *rbuflen = 0;
191        return (path_isadir( path))? afp_errno: AFPERR_BITMAP;
192    }
193
194    if ((int)ibuf & 1 ) {
195        ibuf++;
196    }
197
198    vi.in_size = iend - ibuf;
199    vi.in = ibuf;
200    vi.out_size = 0;
201
202    if ( pioctl( ".", VIOCSETAL, &vi, 1 ) < 0 ) {
203        *rbuflen = 0;
204        return( AFPERR_PARAM );
205    }
206    pioctl( ".AppleDouble", VIOCSETAL, &vi, 1 );
207    if ( curdir->d_did  == DIRDID_ROOT ) {
208        pioctl( ".AppleDesktop", VIOCSETAL, &vi, 1 );
209    }
210
211    return( AFP_OK );
212}
213
214
215#ifdef UAM_AFSKRB
216
217#include <krb.h>
218#include <des.h>
219#include <afs/kauth.h>
220#include <afs/kautils.h>
221
222extern C_Block		seskey;
223extern Key_schedule	seskeysched;
224
225int afp_afschangepw(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
226{
227    char	name[ MAXKTCNAMELEN ], instance[ MAXKTCNAMELEN ];
228    char	realm[ MAXKTCREALMLEN ];
229    char	oldpw[ 9 ], newpw[ 9 ];
230    int		len, rc;
231    u_int16_t	clen;
232    struct ktc_encryptionKey	oldkey, newkey;
233    struct ktc_token		adtok;
234    struct ubik_client		*conn;
235
236    *rbuflen = 0;
237    ++ibuf;
238    len = (unsigned char) *ibuf++;
239    ibuf[ len ] = '\0';
240    *name = *instance = *realm = '\0';
241    ka_ParseLoginName( ibuf, name, instance, realm );
242    ucase( realm );
243    if ( *realm == '\0' ) {
244        if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
245            LOG(log_error, logtype_afpd, "krb_get_lrealm failed" );
246            return( AFPERR_BADUAM );
247        }
248    }
249
250    if ( strlen( name ) < 2 || strlen( name ) > 18 ) {
251        return( AFPERR_PARAM );
252    }
253    ibuf += len;
254
255    memcpy( &clen, ibuf, sizeof( clen ));
256    clen = ntohs( clen );
257    if ( clen % 8 != 0 ) {
258        return( AFPERR_PARAM );
259    }
260
261    ibuf += sizeof( short );
262    pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
263                 clen, seskeysched, seskey, DES_DECRYPT );
264
265    len = (unsigned char) *ibuf++;
266    if ( len > 8 ) {
267        return( AFPERR_PARAM );
268    }
269    memset( oldpw, 0, sizeof( oldpw ));
270    memcpy( oldpw, ibuf, len );
271    ibuf += len;
272    oldpw[ len ] = '\0';
273
274    len = (unsigned char) *ibuf++;
275    if ( len > 8 ) {
276        return( AFPERR_PARAM );
277    }
278    memset( newpw, 0, sizeof( newpw ));
279    memcpy( newpw, ibuf, len );
280    ibuf += len;
281    newpw[ len ] = '\0';
282
283    LOG(log_info, logtype_afpd,
284        "changing password for <%s>.<%s>@<%s>", name, instance, realm );
285
286    ka_StringToKey( oldpw, realm, &oldkey );
287    memset( oldpw, 0, sizeof( oldpw ));
288    ka_StringToKey( newpw, realm, &newkey );
289    memset( newpw, 0, sizeof( newpw ));
290
291    rc = ka_GetAdminToken( name, instance, realm, &oldkey, 60, &adtok, 0 );
292    memset( &oldkey, 0, sizeof( oldkey ));
293    switch ( rc ) {
294    case 0:
295        break;
296    case KABADREQUEST:
297        memset( &newkey, 0, sizeof( newkey ));
298        return( AFPERR_NOTAUTH );
299    default:
300        memset( &newkey, 0, sizeof( newkey ));
301        return( AFPERR_BADUAM );
302    }
303    if ( ka_AuthServerConn( realm, KA_MAINTENANCE_SERVICE, &adtok, &conn )
304            != 0 ) {
305        memset( &newkey, 0, sizeof( newkey ));
306        return( AFPERR_BADUAM );
307    }
308
309    rc = ka_ChangePassword( name, instance, conn, 0, &newkey );
310    memset( &newkey, 0, sizeof( newkey ));
311    if ( rc != 0 ) {
312        return( AFPERR_BADUAM );
313    }
314
315    LOG(log_debug, logtype_afpd, "password changed succeeded" );
316    return( AFP_OK );
317}
318
319#endif /* UAM_AFSKRB */
320#endif /* AFS */
321