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