summaryrefslogtreecommitdiff
path: root/usr/src/lib/libsmbfs/smb/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libsmbfs/smb/file.c')
-rw-r--r--usr/src/lib/libsmbfs/smb/file.c265
1 files changed, 255 insertions, 10 deletions
diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c
index dd738e8d97..e7a02e77df 100644
--- a/usr/src/lib/libsmbfs/smb/file.c
+++ b/usr/src/lib/libsmbfs/smb/file.c
@@ -32,7 +32,10 @@
* $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
#include <sys/param.h>
#include <sys/ioctl.h>
@@ -48,15 +51,230 @@
#include <pwd.h>
#include <grp.h>
#include <unistd.h>
+#include <libintl.h>
#include <sys/types.h>
-extern uid_t real_uid, eff_uid;
+#include <sys/file.h>
#include <netsmb/smb_lib.h>
#include <cflib.h>
+#include "charsets.h"
+#include "private.h"
+
int
-smb_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count, char *dst)
+smb_fh_close(struct smb_ctx *ctx, smbfh fh)
+{
+ struct smb_rq *rqp;
+ struct mbdata *mbp;
+ int serr;
+
+ serr = smb_rq_init(ctx, SMB_COM_CLOSE, 0, &rqp);
+ if (serr != 0)
+ return (serr);
+ mbp = smb_rq_getrequest(rqp);
+ mb_put_uint16le(mbp, fh);
+ mb_put_uint32le(mbp, 0); /* time stamp */
+ smb_rq_wend(rqp);
+ serr = smb_rq_simple(rqp);
+ if (serr != 0) {
+ smb_rq_done(rqp);
+ return (serr);
+ }
+ mbp = smb_rq_getreply(rqp);
+ smb_rq_done(rqp);
+
+ return (serr);
+}
+
+int
+smb_fh_ntcreate(
+ struct smb_ctx *ctx, char *path,
+ int flags, int req_acc, int efattr,
+ int share_acc, int open_disp,
+ int create_opts, int impersonation,
+ smbfh *fhp, uint32_t *action_taken)
+{
+ struct smb_rq *rqp;
+ struct mbdata *mbp;
+ uint8_t wc;
+ size_t pathlen, pathsize;
+ int error, flags2;
+ uint16_t *upath = NULL;
+
+ flags2 = smb_ctx_flags2(ctx);
+ if (flags2 == -1)
+ return (EIO);
+
+ error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, 42, &rqp);
+ if (error != 0)
+ return (error);
+
+ if (flags2 & SMB_FLAGS2_UNICODE) {
+ upath = convert_utf8_to_leunicode(path);
+ if (upath == NULL) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: failed converting to UCS-2"), 0, path);
+ error = EINVAL;
+ goto out;
+ }
+ pathlen = unicode_strlen(upath);
+ pathsize = (pathlen + 1) * 2;
+ } else {
+ pathlen = strlen(path);
+ pathsize = pathlen + 1;
+ }
+
+ mbp = smb_rq_getrequest(rqp);
+ mb_put_uint8(mbp, 0xff); /* secondary command */
+ mb_put_uint8(mbp, 0); /* MBZ */
+ mb_put_uint16le(mbp, 0); /* offset to next command (none) */
+ mb_put_uint8(mbp, 0); /* MBZ */
+ mb_put_uint16le(mbp, pathsize); /* path size (bytes) */
+ mb_put_uint32le(mbp, 0); /* create flags (oplock) */
+ mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */
+ mb_put_uint32le(mbp, req_acc);
+ mb_put_uint64le(mbp, 0); /* initial alloc. size */
+ mb_put_uint32le(mbp, efattr); /* ext. file attributes */
+ mb_put_uint32le(mbp, share_acc); /* share access mode */
+ mb_put_uint32le(mbp, open_disp); /* open disposition */
+ mb_put_uint32le(mbp, create_opts); /* create_options */
+ mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */
+ mb_put_uint8(mbp, 0); /* security flags (?) */
+ smb_rq_wend(rqp);
+
+ /* XXX: Need a "put string" function. */
+ if (flags2 & SMB_FLAGS2_UNICODE) {
+ mb_put_uint8(mbp, 0); /* pad byte - align(2) for Unicode */
+ mb_put_mem(mbp, (char *)upath, pathsize);
+ } else
+ mb_put_mem(mbp, path, pathsize);
+
+ error = smb_rq_simple(rqp);
+ if (error)
+ goto out;
+
+ mbp = smb_rq_getreply(rqp);
+ /*
+ * spec says 26 for word count, but 34 words are defined
+ * and observed from win2000
+ */
+ wc = rqp->rq_wcount;
+ if (wc < 26) {
+ smb_error(dgettext(TEXT_DOMAIN,
+ "%s: open failed, bad word count"), 0, path);
+ error = EBADRPC;
+ goto out;
+ }
+ mb_get_uint8(mbp, NULL); /* secondary cmd */
+ mb_get_uint8(mbp, NULL); /* mbz */
+ mb_get_uint16le(mbp, NULL); /* andxoffset */
+ mb_get_uint8(mbp, NULL); /* oplock lvl granted */
+ mb_get_uint16le(mbp, fhp); /* FID */
+ mb_get_uint32le(mbp, action_taken);
+#if 0 /* skip decoding the rest */
+ mb_get_uint64le(mbp, NULL); /* creation time */
+ mb_get_uint64le(mbp, NULL); /* access time */
+ mb_get_uint64le(mbp, NULL); /* write time */
+ mb_get_uint64le(mbp, NULL); /* change time */
+ mb_get_uint32le(mbp, NULL); /* attributes */
+ mb_get_uint64le(mbp, NULL); /* allocation size */
+ mb_get_uint64le(mbp, NULL); /* EOF */
+ mb_get_uint16le(mbp, NULL); /* file type */
+ mb_get_uint16le(mbp, NULL); /* device state */
+ mb_get_uint8(mbp, NULL); /* directory (boolean) */
+#endif /* skip decoding */
+
+out:
+ if (upath)
+ free(upath);
+ smb_rq_done(rqp);
+
+ return (0);
+}
+
+/*
+ * Conveinence wrapper for smb_fh_ntcreate
+ * Converts Unix-style open call to NTCreate.
+ */
+int
+smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, smbfh *fhp)
+{
+ int error, mode, open_disp, req_acc, share_acc;
+ char *p, *ntpath = NULL;
+
+ /*
+ * Map O_RDONLY, O_WRONLY, O_RDWR
+ * to FREAD, FWRITE
+ */
+ mode = (oflag & 3) + 1;
+
+ /*
+ * Compute requested access, share access.
+ */
+ req_acc = (
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ STD_RIGHT_SYNCHRONIZE_ACCESS);
+ share_acc = NTCREATEX_SHARE_ACCESS_NONE;
+ if (mode & FREAD) {
+ req_acc |= (
+ SA_RIGHT_FILE_READ_DATA |
+ SA_RIGHT_FILE_READ_EA |
+ SA_RIGHT_FILE_READ_ATTRIBUTES);
+ share_acc |= NTCREATEX_SHARE_ACCESS_READ;
+ }
+ if (mode & FWRITE) {
+ req_acc |= (
+ SA_RIGHT_FILE_WRITE_DATA |
+ SA_RIGHT_FILE_APPEND_DATA |
+ SA_RIGHT_FILE_WRITE_EA |
+ SA_RIGHT_FILE_WRITE_ATTRIBUTES);
+ share_acc |= NTCREATEX_SHARE_ACCESS_WRITE;
+ }
+
+ /*
+ * Compute open disposition
+ */
+ if (oflag & FCREAT) {
+ /* Creat if necessary. */
+ if (oflag & FEXCL) {
+ /* exclusive */
+ open_disp = NTCREATEX_DISP_CREATE;
+ } else if (oflag & FTRUNC)
+ open_disp = NTCREATEX_DISP_OVERWRITE_IF;
+ else
+ open_disp = NTCREATEX_DISP_OPEN_IF;
+ } else {
+ /* Not creating. */
+ if (oflag & FTRUNC)
+ open_disp = NTCREATEX_DISP_OVERWRITE;
+ else
+ open_disp = NTCREATEX_DISP_OPEN;
+ }
+
+ /*
+ * Convert Unix path to NT (backslashes)
+ */
+ ntpath = strdup(path);
+ if (ntpath == NULL)
+ return (ENOMEM);
+ for (p = ntpath; *p; p++)
+ if (*p == '/')
+ *p = '\\';
+
+ error = smb_fh_ntcreate(ctx, ntpath, 0, /* flags */
+ req_acc, SMB_EFA_NORMAL, share_acc, open_disp,
+ NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
+ NTCREATEX_IMPERSONATION_IMPERSONATION,
+ fhp, NULL);
+ free(ntpath);
+
+ return (error);
+}
+
+int
+smb_fh_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+ char *dst)
{
struct smbioc_rw rwrq;
@@ -65,17 +283,14 @@ smb_read(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count, char *dst)
rwrq.ioc_base = dst;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- seteuid(eff_uid);
if (ioctl(ctx->ct_fd, SMBIOC_READ, &rwrq) == -1) {
- seteuid(real_uid); /* and back to real user */
return (-1);
}
- seteuid(real_uid); /* and back to real user */
return (rwrq.ioc_cnt);
}
int
-smb_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
+smb_fh_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
const char *src)
{
struct smbioc_rw rwrq;
@@ -85,11 +300,41 @@ smb_write(struct smb_ctx *ctx, smbfh fh, off_t offset, size_t count,
rwrq.ioc_base = (char *)src;
rwrq.ioc_cnt = count;
rwrq.ioc_offset = offset;
- seteuid(eff_uid);
if (ioctl(ctx->ct_fd, SMBIOC_WRITE, &rwrq) == -1) {
- seteuid(real_uid); /* and back to real user */
return (-1);
}
- seteuid(real_uid); /* and back to real user */
return (rwrq.ioc_cnt);
}
+
+/*
+ * Do a TRANSACT_NAMED_PIPE, which is basically just a
+ * pipe write and pipe read, all in one round trip.
+ *
+ * tdlen, tdata describe the data to send.
+ * rdlen, rdata on input describe the receive buffer,
+ * and on output *rdlen is the received length.
+ */
+int
+smb_fh_xactnp(struct smb_ctx *ctx, smbfh fh,
+ int tdlen, const char *tdata, /* transmit */
+ int *rdlen, char *rdata, /* receive */
+ int *more)
+{
+ int err, rparamcnt;
+ uint16_t setup[2];
+
+ setup[0] = TRANS_TRANSACT_NAMED_PIPE;
+ setup[1] = fh;
+ rparamcnt = 0;
+
+ err = smb_t2_request(ctx, 2, setup, "\\PIPE\\",
+ 0, NULL, /* TX paramcnt, params */
+ tdlen, (void *)tdata,
+ &rparamcnt, NULL, /* no RX params */
+ rdlen, rdata, more);
+
+ if (err)
+ *rdlen = 0;
+
+ return (err);
+}