/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include <sys/types.h>
#include <sys/errno.h>
#import <sys/stat.h>
#import <syslog.h>
#import <unistd.h>
#import <stdlib.h>
#import <string.h>
#import "automount.h"
#import "NFSHeaders.h"
#import "Controller.h"
#import "AMMap.h"
#import "log.h"
#import "AMVnode.h"
#import "AMString.h"
/* Some essential cheats: */
struct svcudp_data {
u_int su_iosz; /* byte size of send.recv buffer */
u_long su_xid; /* transaction id */
XDR su_xdrs; /* XDR handle */
char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
char * su_cache; /* cached data, NULL if no cache */
};
#define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))
u_long rpc_xid; /* copy of su_xid, derived from rm_xid */
#ifndef __APPLE__
#define nfsproc_create_2_svc nfsproc_create_2
#define nfsproc_getattr_2_svc nfsproc_getattr_2
#define nfsproc_link_2_svc nfsproc_link_2
#define nfsproc_lookup_2_svc nfsproc_lookup_2
#define nfsproc_mkdir_2_svc nfsproc_mkdir_2
#define nfsproc_null_2_svc nfsproc_null_2
#define nfsproc_read_2_svc nfsproc_read_2
#define nfsproc_readdir_2_svc nfsproc_readdir_2
#define nfsproc_readlink_2_svc nfsproc_readlink_2
#define nfsproc_remove_2_svc nfsproc_remove_2
#define nfsproc_rename_2_svc nfsproc_rename_2
#define nfsproc_rmdir_2_svc nfsproc_rmdir_2
#define nfsproc_root_2_svc nfsproc_root_2
#define nfsproc_setattr_2_svc nfsproc_setattr_2
#define nfsproc_statfs_2_svc nfsproc_statfs_2
#define nfsproc_symlink_2_svc nfsproc_symlink_2
#define nfsproc_write_2_svc nfsproc_write_2
#define nfsproc_writecache_2_svc nfsproc_writecache_2
#endif
int _rpcpmstart; /* Started by a port monitor ? */
int _rpcfdtype; /* Whether Stream or Datagram ? */
int _rpcsvcdirty; /* Still serving ? */
extern void send_pid_to_parent(void);
extern int doing_timeout;
extern int debug;
extern int debug_proc;
Vnode *new_mount_dir;
#import <stdio.h>
struct debug_file_handle
{
unsigned int i[8];
};
char *
fhtoc(nfs_fh *fh)
{
static char str[32];
struct debug_file_handle *dfh;
dfh = (struct debug_file_handle *)fh;
sprintf(str, " return str;
}
/*
* add up sizeof (valid + fileid + name + cookie) - strlen(name)
*/
#define ENTRYSIZE (3 * BYTES_PER_XDR_UNIT + NFS_COOKIESIZE)
/*
* sizeof(status + eof)
*/
#define JUNKSIZE (2 * BYTES_PER_XDR_UNIT)
attrstat *
nfsproc_getattr_2_svc(nfs_fh *fh, struct svc_req *req)
{
static attrstat astat;
struct file_handle *ifh;
Vnode *n;
ifh = (struct file_handle *)fh;
sys_msg(debug_proc, LOG_DEBUG, "-> getattr");
sys_msg(debug_proc, LOG_DEBUG, " fh =
n = [controller vnodeWithID:ifh->node_id];
if (n == nil)
{
sys_msg(debug, LOG_ERR, "getattr for non-existent file handle fhtoc(fh));
astat.status = NFSERR_NOENT;
}
else
{
/* Allow a getattr to succeed even if a previous mount attempt was canceled: */
astat.status = [n nfsStatus];
if (astat.status == ECANCELED) astat.status = NFS_OK;
}
if (astat.status != NFS_OK)
{
sys_msg(debug_proc, LOG_DEBUG, "<- getattr (error return(&astat);
}
sys_msg(debug_proc, LOG_DEBUG, " name = astat.attrstat_u.attributes = [n attributes];
if ((astat.attrstat_u.attributes.mode & S_IFMT) == S_IFLNK) {
sys_msg(debug_proc, LOG_DEBUG, " (Link flags: (astat.attrstat_u.attributes.mode & S_ISVTX) ? "trigger" : "not trigger",
(astat.attrstat_u.attributes.mode & S_ISUID) ? "mounted" : "not mounted",
(astat.attrstat_u.attributes.mode & S_ISGID) ? "needs auth." : "no auth. needed");
}
sys_msg(debug_proc, LOG_DEBUG, "<- getattr");
return(&astat);
}
/* Does something */
diropres *
nfsproc_lookup_2_svc(diropargs *args, struct svc_req *req)
{
static diropres res;
struct file_handle *ifh;
Vnode *n;
String *s;
ifh = (struct file_handle *)&(args->dir);
sys_msg(debug_proc, LOG_DEBUG, "-> lookup");
sys_msg(debug_proc, LOG_DEBUG, " dir fh = sys_msg(debug_proc, LOG_DEBUG, " file =
n = [controller vnodeWithID:ifh->node_id];
if (n == nil)
{
sys_msg(debug, LOG_ERR, "lookup for non-existent file handle fhtoc(&(args->dir)));
res.status = NFSERR_NOENT;
}
else res.status = [n nfsStatus];
if (res.status != NFS_OK)
{
sys_msg(debug_proc, LOG_DEBUG, "<- lookup (error return(&res);
}
s = [String uniqueString:args->name];
n = [n lookup:s];
[s release];
if (n == nil) res.status = NFSERR_NOENT;
else
{
/* Allow a lookup to succeed even if a previous mount attempt was canceled: */
res.status = [n nfsStatus];
if (res.status == ECANCELED) res.status = NFS_OK;
}
if (res.status != NFS_OK)
{
sys_msg(debug_proc, LOG_DEBUG, "<- lookup (res= return(&res);
}
[n getFileHandle:(nfs_fh *)&res.diropres_u.diropres.file];
sys_msg(debug_proc, LOG_DEBUG, " return fh = fhtoc(&res.diropres_u.diropres.file));
res.diropres_u.diropres.attributes = [n attributes];
if ((res.diropres_u.diropres.attributes.mode & S_IFMT) == S_IFLNK) {
sys_msg(debug_proc, LOG_DEBUG, " (Link flags: (res.diropres_u.diropres.attributes.mode & S_ISVTX) ? "trigger" : "not trigger",
(res.diropres_u.diropres.attributes.mode & S_ISUID) ? "mounted" : "not mounted",
(res.diropres_u.diropres.attributes.mode & S_ISGID) ? "needs auth." : "no auth. needed");
}
sys_msg(debug_proc, LOG_DEBUG, "<- lookup");
return(&res);
}
readlinkres *
nfsproc_readlink_2_svc(nfs_fh *fh, struct svc_req *req)
{
static readlinkres res;
struct file_handle *ifh;
Vnode *n;
unsigned int status;
struct authunix_parms *aup;
int uid;
uid = -2;
if (req->rq_cred.oa_flavor == AUTH_UNIX)
{
aup = (struct authunix_parms *)req->rq_clntcred;
uid = aup->aup_uid;
sys_msg(debug_proc, LOG_DEBUG, "\t uid }
else
{
sys_msg(debug_proc, LOG_DEBUG, "\t uid unknown requested a new link check");
}
ifh = (struct file_handle *)fh;
sys_msg(debug_proc, LOG_DEBUG, "-> readlink");
sys_msg(debug_proc, LOG_DEBUG, " fh = rpc_xid = su_data(req->rq_xprt)->su_xid;
sys_msg(debug_proc, LOG_DEBUG, " xid = 0x
if (doing_timeout) return NULL;
n = [controller vnodeWithID:ifh->node_id];
if (n == nil)
{
sys_msg(debug, LOG_ERR, "readlink for non-existent file handle fhtoc(fh));
res.status = NFSERR_NOENT;
}
else if ([n type] != NFLNK) res.status = NFSERR_ISDIR;
else res.status = [n nfsStatus];
if (res.status != NFS_OK)
{
return(&res);
sys_msg(debug_proc, LOG_DEBUG, "<- readlink (1)");
}
status = 0;
#warning test here for a bad afp mount ... (i.e. disconnected)
if ([n type] == NFLNK)
{
sys_msg(debug_proc, LOG_DEBUG, " NFLNK");
}
if (([n type] == NFLNK) && (![n mounted]))
{
sys_msg(debug_proc, LOG_DEBUG, " not mounted");
#warning deriving internal copy of private and transport-specific xid...
status = [[n map] mount:n withUid:uid];
if (gBlockedMountDependency) {
sys_msg(debug_proc, LOG_DEBUG, " mount is in progress; transaction id = 0x if (gBlockingMountTransactionID == rpc_xid) {
/* This is a retransmission of the original readlink request
that triggered the mount in the first place; best to wait
until the mount's complete. */
sys_msg(debug_proc, LOG_DEBUG, "<- [readlink abandoned]");
gBlockedMountDependency = NO; /* This is a one-shot deal */
return NULL; /* Try again later... */
};
/* This is a mount in progress from another call - don't wait up and don't hold up THIS call! */
gBlockedMountDependency = NO;
};
if (gForkedMountInProgress) {
sys_msg(debug_proc, LOG_DEBUG, "<- [readlink abandoned]");
gForkedMountInProgress = NO;
return NULL;
};
if (status != 0)
{
res.status = (status == ECANCELED) ? ECANCELED : NFSERR_NOENT;
sys_msg(debug_proc, LOG_DEBUG, "<- readlink (2)");
return(&res);
}
}
sys_msg(debug_proc, LOG_DEBUG, " name = res.readlinkres_u.data = [[n link] value];
sys_msg(debug_proc, LOG_DEBUG, " link = sys_msg(debug_proc, LOG_DEBUG, "<- readlink");
return(&res);
}
/* Does something */
readdirres *
nfsproc_readdir_2_svc(readdirargs *args, struct svc_req *req)
{
static readdirres res;
Vnode *n, *v;
struct entry *e, *nexte;
struct entry **entp;
unsigned int cookie, count, entrycount, i, nlist;
struct file_handle *ifh;
Array *list;
String *s;
ifh = (struct file_handle *)&(args->dir);
cookie = *(unsigned int*)args->cookie;
sys_msg(debug_proc, LOG_DEBUG, "-> readdir");
sys_msg(debug_proc, LOG_DEBUG, " dir fh = sys_msg(debug_proc, LOG_DEBUG, " cookie = sys_msg(debug_proc, LOG_DEBUG, " count =
/*
* Free up old stuff
*/
e = res.readdirres_u.reply.entries;
while (e != NULL)
{
nexte = e->nextentry;
free(e);
e = nexte;
}
res.readdirres_u.reply.entries = NULL;
n = [controller vnodeWithID:ifh->node_id];
if (n == nil)
{
sys_msg(debug, LOG_ERR, "readdir for non-existent file handle fhtoc(&(args->dir)));
res.status = NFSERR_NOENT;
}
else if ([n type] != NFDIR) res.status = NFSERR_NOTDIR;
else res.status = [n nfsStatus];
if (res.status != NFS_OK)
{
sys_msg(debug_proc, LOG_DEBUG, "<- readdir (1)");
return(&res);
}
sys_msg(debug_proc, LOG_DEBUG, " name =
list = [n dirlist];
nlist = [list count];
count = JUNKSIZE;
entrycount = 0;
entp = &res.readdirres_u.reply.entries;
for (i = cookie; i < nlist; i++)
{
v = [list objectAtIndex:i];
if (i == 0) s = dot;
else if (i == 1) s = dotdot;
else s = [v name];
count += ENTRYSIZE;
count += [s length];
if (count > args->count)
{
sys_msg(debug_proc, LOG_DEBUG, " BREAK");
break;
}
sys_msg(debug_proc, LOG_DEBUG, " cookie, [v nodeID], [s value]);
*entp = (struct entry *) malloc(sizeof(struct entry));
bzero(*entp, sizeof(struct entry));
(*entp)->fileid = [v nodeID];
(*entp)->name = [s value];
*(unsigned int*)((*entp)->cookie) = ++cookie;
(*entp)->nextentry = NULL;
entp = &(*entp)->nextentry;
}
if (i < nlist) res.readdirres_u.reply.eof = FALSE;
else res.readdirres_u.reply.eof = TRUE;
sys_msg(debug_proc, LOG_DEBUG, " eof = res.readdirres_u.reply.eof ? "TRUE" : "FALSE");
[list release];
sys_msg(debug_proc, LOG_DEBUG, "<- readdir");
return(&res);
}
statfsres *
nfsproc_statfs_2_svc(nfs_fh *fh, struct svc_req *req)
{
static statfsres res;
sys_msg(debug_proc, LOG_DEBUG, "-> statfs");
res.status = NFS_OK;
res.statfsres_u.reply.tsize = 512;
res.statfsres_u.reply.bsize = 512;
res.statfsres_u.reply.blocks = 0;
res.statfsres_u.reply.bfree = 0;
res.statfsres_u.reply.bavail = 0;
sys_msg(debug_proc, LOG_DEBUG, "<- statfs");
return(&res);
}
/*
* These routines do nothing - they should never even be called!
*/
void *
nfsproc_null_2_svc(void *x, struct svc_req *req)
{
sys_msg(debug_proc, LOG_DEBUG, "-- null");
return((void *)NULL);
}
attrstat *
nfsproc_setattr_2_svc(sattrargs *args, struct svc_req *req)
{
static attrstat astat;
sys_msg(debug_proc, LOG_DEBUG, "-- setattr");
astat.status = NFSERR_ROFS;
return(&astat);
}
void *
nfsproc_root_2_svc(void *x, struct svc_req *req)
{
sys_msg(debug_proc, LOG_DEBUG, "-- root");
return(NULL);
}
readres *
nfsproc_read_2_svc(readargs *args, struct svc_req *req)
{
static readres res;
sys_msg(debug_proc, LOG_DEBUG, "-- read");
res.status = NFSERR_ISDIR; /* XXX: should return better error */
return(&res);
}
void *
nfsproc_writecache_2_svc(void *x, struct svc_req *req)
{
sys_msg(debug_proc, LOG_DEBUG, "-- writecache");
return(NULL);
}
attrstat *
nfsproc_write_2_svc(writeargs *args, struct svc_req *req)
{
static attrstat res;
sys_msg(debug_proc, LOG_DEBUG, "-- write");
res.status = NFSERR_ROFS; /* XXX: should return better error */
return(&res);
}
diropres *
nfsproc_create_2_svc(createargs *args, struct svc_req *req)
{
static diropres res;
sys_msg(debug_proc, LOG_DEBUG, "-- create");
res.status = NFSERR_ROFS;
return(&res);
}
nfsstat *
nfsproc_remove_2_svc(diropargs *args, struct svc_req *req)
{
static nfsstat status;
struct file_handle *ifh;
Vnode *n;
String *s;
uid_t uid = -2; /* default = nobody */
if (req->rq_cred.oa_flavor == AUTH_UNIX)
{
struct authunix_parms *aup;
aup = (struct authunix_parms *)req->rq_clntcred;
uid = aup->aup_uid;
}
ifh = (struct file_handle *) &(args->dir);
sys_msg(debug_proc, LOG_DEBUG, "-> remove");
sys_msg(debug_proc, LOG_DEBUG, " dir fh = sys_msg(debug_proc, LOG_DEBUG, " file = sys_msg(debug_proc, LOG_DEBUG, " requesting uid =
if (uid != 0) {
sys_msg(debug, LOG_ERR, "remove request from unauthorized uid status = NFSERR_ACCES;
return(&status);
}
n = [controller vnodeWithID:ifh->node_id];
if (n == nil)
{
sys_msg(debug, LOG_ERR, "remove for non-existent dir handle fhtoc(&(args->dir)));
status = NFSERR_NOENT;
}
else status = [n nfsStatus];
if (status != NFS_OK)
{
sys_msg(debug_proc, LOG_DEBUG, "<- remove (error return(&status);
}
s = [String uniqueString:args->name];
status = [n remove:s];
[s release];
if (status != NFS_OK)
sys_msg(debug_proc, LOG_DEBUG, "<- remove (res= else
sys_msg(debug_proc, LOG_DEBUG, "<- remove");
return(&status);
}
nfsstat *
nfsproc_rename_2_svc(renameargs *args, struct svc_req *req)
{
static nfsstat status;
sys_msg(debug_proc, LOG_DEBUG, "-- rename");
status = NFSERR_ROFS;
return(&status);
}
nfsstat *
nfsproc_link_2_svc(linkargs *args, struct svc_req *req)
{
static nfsstat status;
sys_msg(debug_proc, LOG_DEBUG, "-- link");
status = NFSERR_ROFS;
return(&status);
}
nfsstat *
nfsproc_symlink_2_svc(symlinkargs *args, struct svc_req *req)
{
static nfsstat status;
struct file_handle *ifh;
Vnode *n;
struct authunix_parms *aup;
uid_t uid = -2; /* default = nobody */
if (req->rq_cred.oa_flavor == AUTH_UNIX)
{
aup = (struct authunix_parms *)req->rq_clntcred;
uid = aup->aup_uid;
}
sys_msg(debug_proc, LOG_DEBUG, "-> symlink");
sys_msg(debug_proc, LOG_DEBUG, " from.dir fh = sys_msg(debug_proc, LOG_DEBUG, " from.name = sys_msg(debug_proc, LOG_DEBUG, " to = sys_msg(debug_proc, LOG_DEBUG, " attributes:");
sys_msg(debug_proc, LOG_DEBUG, " mode = 0 sys_msg(debug_proc, LOG_DEBUG, " uid = 0 sys_msg(debug_proc, LOG_DEBUG, " gid = 0 sys_msg(debug_proc, LOG_DEBUG, " size = 0x sys_msg(debug_proc, LOG_DEBUG, " atime = [0x sys_msg(debug_proc, LOG_DEBUG, " mtime = [0x sys_msg(debug_proc, LOG_DEBUG, " requesting uid =
if (uid != 0) {
sys_msg(debug, LOG_ERR, "symlink request from unauthorized uid");
status = NFSERR_ACCES;
return(&status);
};
ifh = (struct file_handle *)&(args->from.dir);
n = [controller vnodeWithID:ifh->node_id];
if (n == nil)
{
sys_msg(debug, LOG_ERR, "lookup for non-existent file handle fhtoc(&(args->from.dir)));
status = NFSERR_NOENT;
}
else status = [n nfsStatus];
if (status != NFS_OK)
{
sys_msg(debug_proc, LOG_DEBUG, "<- symlink (error return(&status);
}
status = [n symlinkWithName:args->from.name to:args->to attributes:(struct nfsv2_sattr *)&args->attributes];
if (status) {
sys_msg(debug_proc, LOG_DEBUG, "<- symlink");
} else {
sys_msg(debug_proc, LOG_DEBUG, "<- symlink (status = };
return(&status);
}
diropres *
nfsproc_mkdir_2_svc(createargs *args, struct svc_req *req)
{
static diropres res;
sys_msg(debug_proc, LOG_DEBUG, "-- mkdir");
res.status = NFSERR_ROFS;
return(&res);
}
nfsstat *
nfsproc_rmdir_2_svc(diropargs *args, struct svc_req *req)
{
static nfsstat status;
sys_msg(debug_proc, LOG_DEBUG, "-- rmdir");
status = NFSERR_ROFS;
return(&status);
}