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