diff options
author | jose borrego <Jose.Borrego@Sun.COM> | 2009-02-01 19:44:54 -0700 |
---|---|---|
committer | jose borrego <Jose.Borrego@Sun.COM> | 2009-02-01 19:44:54 -0700 |
commit | 7f667e74610492ddbce8ce60f52ece95d2401949 (patch) | |
tree | 2e81974f83f306484e9e5617b0996a0c1186d753 /usr/src | |
parent | 947caa0ed80d272c3bda0c220e088b61b027809a (diff) | |
download | illumos-joyent-7f667e74610492ddbce8ce60f52ece95d2401949.tar.gz |
6792084 smb_node_lookup should not take ownership of the hold on vnode passed as a parameter
6792299 winreg EnumKey should enumerate subkeys of any key
6582194 Replace getdents with readdir
6790756 smb_vss_lookup_nodes doesn't release its hold on vnode if smb_node_lookup fails
6791568 Solaris CIFS server only accepts pre-Windows 2000 user logon name
6793375 Unable to map a share with a user on a trusted domain
6796947 invalid assert in smb_vop_getattr
6581736 IPv6 support
6788345 smbadm list output only shows one trusted domain
6796594 Array overrun in libmlrpc
6797782 Need a SAM abstraction layer
6764696 Insufficient access while attempting to modify UserAccountControl attribute of a machine account
6798908 Refresh after enabling network interfaces should trigger DC discovery
6798825 Replace the smb_vop_readdir mechanism with the smb_odir_t object
Diffstat (limited to 'usr/src')
102 files changed, 5318 insertions, 6820 deletions
diff --git a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c index 874c790ed4..19f25ab69a 100644 --- a/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c +++ b/usr/src/cmd/mdb/common/modules/smbsrv/smbsrv.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -882,8 +882,6 @@ smb_dcmd_request(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) sr->uid_user); mdb_printf("File: %u (%p)\n", sr->smb_fid, sr->fid_ofile); - mdb_printf("Dir.: %u (%p)\n", sr->smb_sid, - sr->sid_odir); mdb_printf("PID: %u\n", sr->smb_pid); mdb_printf("MID: %u\n\n", sr->smb_mid); } else { @@ -1169,10 +1167,10 @@ smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) "%<b>%<u>SMB odir information (%p):%</u>%</b>\n\n", addr); mdb_printf("State: %d (%s)\n", od->d_state, state); - mdb_printf("SID: %u\n", od->d_sid); + mdb_printf("SID: %u\n", od->d_odid); mdb_printf("Reference Count: %d\n", od->d_refcnt); mdb_printf("Pattern: %s\n", od->d_pattern); - mdb_printf("SMB Node: %p\n\n", od->d_dir_snode); + mdb_printf("SMB Node: %p\n\n", od->d_dnode); } else { if (DCMD_HDRSPEC(flags)) mdb_printf( @@ -1183,7 +1181,7 @@ smb_dcmd_odir(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) "ODIR", "SID", "VNODE", "PATTERN"); mdb_printf("%?p %-5u %-16s %s\n", - addr, od->d_sid, od->d_dir_snode, od->d_pattern); + addr, od->d_odid, od->d_dnode, od->d_pattern); } } return (DCMD_OK); diff --git a/usr/src/cmd/smbsrv/smbadm/Makefile b/usr/src/cmd/smbsrv/smbadm/Makefile index baffa960d8..e972d0892a 100644 --- a/usr/src/cmd/smbsrv/smbadm/Makefile +++ b/usr/src/cmd/smbsrv/smbadm/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "@(#)Makefile 1.5 08/07/16 SMI" @@ -31,7 +31,7 @@ SRCS= smbadm.c include ../../Makefile.cmd include ../Makefile.smbsrv.defs -LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lsmb -lumem -lnsl +LDLIBS += -L$(ROOT)/usr/lib/smbsrv -lsmb -lumem LDFLAGS += -R/usr/lib/smbsrv all: $(PROG) diff --git a/usr/src/cmd/smbsrv/smbadm/smbadm.c b/usr/src/cmd/smbsrv/smbadm/smbadm.c index f48087202e..9b15b5d1cd 100644 --- a/usr/src/cmd/smbsrv/smbadm/smbadm.c +++ b/usr/src/cmd/smbsrv/smbadm/smbadm.c @@ -781,7 +781,7 @@ smbadm_list(int argc, char **argv) char srvname[MAXHOSTNAMELEN]; char modename[16]; int rc; - uint32_t srvipaddr; + smb_inaddr_t srvipaddr; char ipstr[INET6_ADDRSTRLEN]; rc = smb_config_getstr(SMB_CI_SECURITY, modename, sizeof (modename)); @@ -808,9 +808,9 @@ smbadm_list(int argc, char **argv) if ((smb_get_dcinfo(srvname, MAXHOSTNAMELEN, &srvipaddr) == NT_STATUS_SUCCESS) && (*srvname != '\0') && - (srvipaddr != 0)) { - (void) inet_ntop(AF_INET, (const void *)&srvipaddr, - ipstr, sizeof (ipstr)); + (!smb_inet_iszero(&srvipaddr))) { + (void) smb_inet_ntop(&srvipaddr, ipstr, + SMB_IPSTRLEN(srvipaddr.a_family)); (void) printf(gettext("\t[+%s.%s] [%s]\n"), srvname, fqdn, ipstr); } diff --git a/usr/src/cmd/smbsrv/smbd/server.xml b/usr/src/cmd/smbsrv/smbd/server.xml index f84df842e7..ea64de7ccb 100644 --- a/usr/src/cmd/smbsrv/smbd/server.xml +++ b/usr/src/cmd/smbsrv/smbd/server.xml @@ -21,7 +21,7 @@ information: Portions Copyright [yyyy] [name of copyright owner] CDDL HEADER END -Copyright 2008 Sun Microsystems, Inc. All rights reserved. +Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. NOTE: This service manifest is not editable; its contents will @@ -192,6 +192,8 @@ file. value='0' override='true'/> <propval name='netlogon_seqnum' type='integer' value='0' override='true'/> + <propval name='ipv6_enable' type='boolean' + value='false' override='true'/> </property_group> <!-- 6. Identify faults to be ignored. --> diff --git a/usr/src/cmd/smbsrv/smbd/smbd_logon.c b/usr/src/cmd/smbsrv/smbd/smbd_logon.c index 0b88309dbf..ebe04ba09a 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_logon.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_logon.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/types.h> #include <errno.h> #include <synch.h> @@ -86,6 +84,8 @@ smbd_user_auth_logon(netr_client_t *clnt) adt_event_data_t *event; au_tid_addr_t termid; char sidbuf[SMB_SID_STRSZ]; + char *username; + char *domain; uid_t uid; gid_t gid; char *sid; @@ -96,13 +96,17 @@ smbd_user_auth_logon(netr_client_t *clnt) uid = ADT_NO_ATTRIB; gid = ADT_NO_ATTRIB; sid = NT_NULL_SIDSTR; + username = clnt->real_username; + domain = clnt->real_domain; status = ADT_FAILURE; retval = ADT_FAIL_VALUE_AUTH; } else { - uid = token->tkn_user->i_id; - gid = token->tkn_primary_grp->i_id; - smb_sid_tostr(token->tkn_user->i_sidattr.sid, sidbuf); + uid = token->tkn_user.i_id; + gid = token->tkn_primary_grp.i_id; + smb_sid_tostr(token->tkn_user.i_sid, sidbuf); sid = sidbuf; + username = token->tkn_account_name; + domain = token->tkn_domain_name; status = ADT_SUCCESS; retval = ADT_SUCCESS; } @@ -123,8 +127,14 @@ smbd_user_auth_logon(netr_client_t *clnt) (void) memset(&termid, 0, sizeof (au_tid_addr_t)); termid.at_port = clnt->local_port; - termid.at_type = AU_IPv4; - termid.at_addr[0] = clnt->ipaddr; + + if (clnt->ipaddr.a_family == AF_INET) { + termid.at_addr[0] = clnt->ipaddr.a_ipv4; + termid.at_type = AU_IPv4; + } else { + bcopy(&clnt->ipaddr.a_ip, termid.at_addr, IPV6_ADDR_LEN); + termid.at_type = AU_IPv6; + } adt_set_termid(ah, &termid); if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) { @@ -135,8 +145,8 @@ smbd_user_auth_logon(netr_client_t *clnt) return (NULL); } - event->adt_smbd_session.domain = clnt->domain; - event->adt_smbd_session.username = clnt->username; + event->adt_smbd_session.domain = domain; + event->adt_smbd_session.username = username; event->adt_smbd_session.sid = sid; if (adt_put_event(event, status, retval)) @@ -155,8 +165,8 @@ smbd_user_auth_logon(netr_client_t *clnt) entry->sa_handle = ah; entry->sa_uid = uid; entry->sa_gid = gid; - entry->sa_username = strdup(clnt->username); - entry->sa_domain = strdup(clnt->domain); + entry->sa_username = strdup(username); + entry->sa_domain = strdup(domain); smb_autohome_add(entry->sa_username); smbd_audit_link(entry); diff --git a/usr/src/cmd/smbsrv/smbd/smbd_main.c b/usr/src/cmd/smbsrv/smbd/smbd_main.c index 4a0b2e572d..c53af345a6 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_main.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_main.c @@ -45,8 +45,6 @@ #include <time.h> #include <libscf.h> #include <zone.h> -#include <time.h> -#include <tzfile.h> #include <libgen.h> #include <pwd.h> #include <grp.h> @@ -90,6 +88,8 @@ static pthread_t localtime_thr; static int smbd_refresh_init(void); static void smbd_refresh_fini(void); static void *smbd_refresh_monitor(void *); +static void smbd_refresh_dc(void); + static pthread_t nbt_listener; static pthread_t tcp_listener; static pthread_t refresh_thr; @@ -529,8 +529,6 @@ smbd_refresh_monitor(void *arg) exit(SMF_EXIT_OK); } - syslog(LOG_DEBUG, "refresh"); - /* * We've been woken up by a refresh event so go do * what is necessary. @@ -549,9 +547,9 @@ smbd_refresh_monitor(void *arg) /* re-initialize NIC table */ if (smb_nic_init() != 0) smbd_report("failed to get NIC information"); - smb_netbios_name_reconfig(); smb_browser_reconfig(); + smbd_refresh_dc(); dyndns_update_zones(); if (smbd_set_netlogon_cred()) { @@ -594,6 +592,23 @@ smbd_refresh_monitor(void *arg) return (NULL); } +/* + * Update DC information on a refresh. + */ +static void +smbd_refresh_dc(void) +{ + char fqdomain[MAXHOSTNAMELEN]; + if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN) + return; + + if (smb_getfqdomainname(fqdomain, MAXHOSTNAMELEN)) + return; + + if (smb_locate_dc(fqdomain, "", NULL)) + smbd_report("DC discovery failed"); +} + void smbd_set_secmode(int secmode) { diff --git a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c index 942db7def9..ea4a3d3da0 100644 --- a/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c +++ b/usr/src/cmd/smbsrv/smbd/smbd_share_doorsvc.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -151,7 +151,7 @@ smb_share_dsrv_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, smb_shrlist_t lmshr_list; smb_enumshare_info_t esi; int offset; - ipaddr_t ipaddr; + smb_inaddr_t ipaddr; if ((cookie != SMB_SHARE_DSRV_COOKIE) || (ptr == NULL) || (size < sizeof (uint32_t))) { @@ -205,15 +205,14 @@ smb_share_dsrv_dispatch(void *cookie, char *ptr, size_t size, door_desc_t *dp, case SMB_SHROP_GETINFO: sharename = smb_dr_get_string(dec_ctx); - ipaddr = smb_dr_get_uint32(dec_ctx); + (void) smb_dr_get_buf(dec_ctx, (unsigned char *)&ipaddr, + sizeof (smb_inaddr_t)); if ((dec_status = smb_dr_decode_finish(dec_ctx)) != 0) { smb_dr_free_string(sharename); goto decode_error; } - - rc = smb_shr_get(sharename, &lmshr_info); - smb_shr_hostaccess(&lmshr_info, ipaddr); + smb_shr_hostaccess(&lmshr_info, &ipaddr); smb_dr_put_int32(enc_ctx, SMB_SHARE_DSUCCESS); smb_dr_put_uint32(enc_ctx, rc); smb_dr_put_share(enc_ctx, &lmshr_info); diff --git a/usr/src/common/smbsrv/smb_inet.c b/usr/src/common/smbsrv/smb_inet.c new file mode 100644 index 0000000000..f7af3f54af --- /dev/null +++ b/usr/src/common/smbsrv/smb_inet.c @@ -0,0 +1,79 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file was originally generated using rpcgen. + */ + +#ifndef _KERNEL +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> +#endif /* !_KERNEL */ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <inet/tcp.h> +#include <smbsrv/smb_inet.h> + +const struct in6_addr ipv6addr_any = IN6ADDR_ANY_INIT; + +boolean_t +smb_inet_equal(smb_inaddr_t *ip1, smb_inaddr_t *ip2, uint32_t v4mask) +{ + if ((ip1->a_family == AF_INET) && + (ip2->a_family == AF_INET) && + ((ip1->a_ipv4 & v4mask) == (ip2->a_ipv4 & v4mask))) + return (B_TRUE); + + if ((ip1->a_family == AF_INET6) && + (ip2->a_family == AF_INET6) && + (!memcmp(&ip1->a_ipv6, &ip2->a_ipv6, IPV6_ADDR_LEN))) + return (B_TRUE); + else + return (B_FALSE); +} + +boolean_t +smb_inet_iszero(smb_inaddr_t *ipaddr) +{ + const void *ipsz = (const void *)&ipv6addr_any; + + if ((ipaddr->a_family == AF_INET) && + (ipaddr->a_ipv4 == 0)) + return (B_TRUE); + + if ((ipaddr->a_family == AF_INET6) && + !memcmp(&ipaddr->a_ipv6, ipsz, IPV6_ADDR_LEN)) + return (B_TRUE); + else + return (B_FALSE); +} + +const char * +smb_inet_ntop(smb_inaddr_t *addr, char *buf, int size) +{ + return ((char *)inet_ntop(addr->a_family, (char *)addr, buf, size)); +} diff --git a/usr/src/common/smbsrv/smb_sid.c b/usr/src/common/smbsrv/smb_sid.c index e6726290f1..4671274786 100644 --- a/usr/src/common/smbsrv/smb_sid.c +++ b/usr/src/common/smbsrv/smb_sid.c @@ -19,16 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * NT Security Identifier (SID) library functions. - */ - #ifndef _KERNEL #include <stdio.h> #include <strings.h> @@ -149,23 +143,26 @@ smb_sid_getrid(smb_sid_t *sid, uint32_t *rid) * smb_sid_split * * Take a full sid and split it into a domain sid and a relative id (rid). - * - * IMPORTANT: The original sid is modified in place - use smb_sid_dup before - * calling this function to preserve the original SID. Be careful if you're - * using this function in kernel code, after calling this function 'sid' - * cannot be passed to smb_sid_free() because the size won't match the original - * allocated size. Use smb_sid_ksplit() instead. + * The domain SID is allocated and a pointer to it will be returned. The + * RID value is passed back in 'rid' arg if it's not NULL. The allocated + * memory for the domain SID must be freed by caller. */ -int +smb_sid_t * smb_sid_split(smb_sid_t *sid, uint32_t *rid) { + smb_sid_t *domsid; + if (!smb_sid_isvalid(sid) || (sid->sid_subauthcnt == 0)) - return (-1); + return (NULL); + + if ((domsid = smb_sid_dup(sid)) == NULL) + return (NULL); - --sid->sid_subauthcnt; + --domsid->sid_subauthcnt; if (rid) - *rid = sid->sid_subauth[sid->sid_subauthcnt]; - return (0); + *rid = domsid->sid_subauth[domsid->sid_subauthcnt]; + + return (domsid); } /* @@ -464,3 +461,20 @@ smb_sid_free(smb_sid_t *sid) free(sid); #endif } + +#ifndef _KERNEL +void +smb_ids_free(smb_ids_t *ids) +{ + smb_id_t *id; + int i; + + if ((ids != NULL) && (ids->i_ids != NULL)) { + id = ids->i_ids; + for (i = 0; i < ids->i_cnt; i++, id++) + smb_sid_free(id->i_sid); + + free(ids->i_ids); + } +} +#endif diff --git a/usr/src/common/smbsrv/smb_token_xdr.c b/usr/src/common/smbsrv/smb_token_xdr.c index 6278aba8a4..11cd04156c 100644 --- a/usr/src/common/smbsrv/smb_token_xdr.c +++ b/usr/src/common/smbsrv/smb_token_xdr.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file was originally generated using rpcgen. */ @@ -32,65 +30,15 @@ #ifndef _KERNEL #include <stdlib.h> #endif /* !_KERNEL */ -#include <smbsrv/smb_vops.h> #include <smbsrv/wintypes.h> #include <smbsrv/smb_sid.h> #include <smbsrv/smb_xdr.h> #include <smbsrv/smb_token.h> -static bool_t -xdr_sid_helper(xdrs, sid) - XDR *xdrs; - char **sid; -{ - uint32_t pos, len; - uint8_t dummy, cnt; - bool_t rc; - - switch (xdrs->x_op) { - case XDR_DECODE: - /* - * chicken-and-egg: Can't use smb_sid_len() since it takes - * SID as its parameter while sid is yet to be decoded. - */ - pos = xdr_getpos(xdrs); - - if (!xdr_bool(xdrs, &rc)) - return (FALSE); - - if (!xdr_uint8_t(xdrs, &dummy)) - return (FALSE); - - if (!xdr_uint8_t(xdrs, &cnt)) - return (FALSE); - - rc = xdr_setpos(xdrs, pos); - - if (rc == FALSE) - return (FALSE); - - len = sizeof (smb_sid_t) - sizeof (uint32_t) + - (cnt * sizeof (uint32_t)); +static bool_t xdr_smb_privset_t(XDR *, smb_privset_t *); +static bool_t xdr_smb_sid_t(XDR *, smb_sid_t *); - if (!xdr_pointer(xdrs, sid, len, (xdrproc_t)xdr_smb_sid_t)) - return (FALSE); - break; - - case XDR_ENCODE: - case XDR_FREE: - if (*sid == NULL) - return (FALSE); - - len = smb_sid_len((smb_sid_t *)(uintptr_t)*sid); - if (!xdr_pointer(xdrs, sid, len, (xdrproc_t)xdr_smb_sid_t)) - return (FALSE); - break; - } - - return (TRUE); -} - -bool_t +static bool_t xdr_smb_privset_helper(xdrs, privs) XDR *xdrs; char **privs; @@ -131,68 +79,45 @@ xdr_smb_privset_helper(xdrs, privs) return (TRUE); } -bool_t -xdr_smb_win_grps_helper(xdrs, grps) +static bool_t +xdr_smb_id_t(xdrs, objp) XDR *xdrs; - char **grps; + smb_id_t *objp; { - uint32_t pos, len; - uint16_t cnt; - bool_t rc; + uint8_t len; - if (xdrs->x_op == XDR_DECODE) { - pos = xdr_getpos(xdrs); + if ((xdrs->x_op == XDR_ENCODE) || (xdrs->x_op == XDR_FREE)) + len = smb_sid_len(objp->i_sid); - if (!xdr_bool(xdrs, &rc)) - return (FALSE); - - if (!xdr_uint16_t(xdrs, &cnt)) - return (FALSE); - - rc = xdr_setpos(xdrs, pos); - if (rc == FALSE) - return (FALSE); - } else { - if (*grps == NULL) - return (FALSE); - - cnt = ((smb_win_grps_t *)(uintptr_t)*grps)->wg_count; - } - - len = cnt * sizeof (smb_id_t) + sizeof (smb_win_grps_t); - - if (!xdr_pointer(xdrs, grps, len, (xdrproc_t)xdr_smb_win_grps_t)) + if (!xdr_uint32_t(xdrs, &objp->i_attrs)) return (FALSE); - return (TRUE); -} + if (!xdr_uint8_t(xdrs, &len)) + return (FALSE); -bool_t -xdr_smb_id_t(xdrs, objp) - XDR *xdrs; - smb_id_t *objp; -{ - if (!xdr_smb_sid_attrs_t(xdrs, &objp->i_sidattr)) + if (!xdr_pointer(xdrs, (char **)&objp->i_sid, len, + (xdrproc_t)xdr_smb_sid_t)) return (FALSE); + if (!xdr_uint32_t(xdrs, (uint32_t *)&objp->i_id)) return (FALSE); + return (TRUE); } -bool_t -xdr_smb_win_grps_t(xdrs, objp) +static bool_t +xdr_smb_ids_t(xdrs, objp) XDR *xdrs; - smb_win_grps_t *objp; + smb_ids_t *objp; { - if (!xdr_uint16_t(xdrs, &objp->wg_count)) - return (FALSE); - if (!xdr_vector(xdrs, (char *)objp->wg_groups, objp->wg_count, - sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t)) + if (!xdr_array(xdrs, (char **)&objp->i_ids, (uint32_t *)&objp->i_cnt, + ~0, sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t)) return (FALSE); + return (TRUE); } -bool_t +static bool_t xdr_smb_posix_grps_t(xdrs, objp) XDR *xdrs; smb_posix_grps_t *objp; @@ -205,7 +130,7 @@ xdr_smb_posix_grps_t(xdrs, objp) return (TRUE); } -bool_t +static bool_t xdr_smb_posix_grps_helper(xdrs, identity) XDR *xdrs; char **identity; @@ -239,7 +164,7 @@ xdr_smb_posix_grps_helper(xdrs, identity) return (TRUE); } -bool_t +static bool_t xdr_smb_session_key_t(xdrs, objp) XDR *xdrs; smb_session_key_t *objp; @@ -261,9 +186,13 @@ xdr_netr_client_t(xdrs, objp) return (FALSE); if (!xdr_string(xdrs, &objp->domain, ~0)) return (FALSE); + if (!xdr_string(xdrs, &objp->real_username, ~0)) + return (FALSE); + if (!xdr_string(xdrs, &objp->real_domain, ~0)) + return (FALSE); if (!xdr_string(xdrs, &objp->workstation, ~0)) return (FALSE); - if (!xdr_uint32_t(xdrs, &objp->ipaddr)) + if (!xdr_smb_inaddr_t(xdrs, &objp->ipaddr)) return (FALSE); if (!xdr_array(xdrs, (char **)&objp->challenge_key.challenge_key_val, (uint32_t *)&objp->challenge_key.challenge_key_len, ~0, @@ -283,16 +212,14 @@ xdr_netr_client_t(xdrs, objp) return (FALSE); if (!xdr_int(xdrs, &objp->native_lm)) return (FALSE); - if (!xdr_uint32_t(xdrs, &objp->local_ipaddr)) + if (!xdr_smb_inaddr_t(xdrs, &objp->local_ipaddr)) return (FALSE); if (!xdr_uint16_t(xdrs, &objp->local_port)) return (FALSE); - if (!xdr_uint32_t(xdrs, &objp->flags)) - return (FALSE); return (TRUE); } -bool_t +static bool_t xdr_smb_sid_t(xdrs, objp) XDR *xdrs; smb_sid_t *objp; @@ -310,7 +237,7 @@ xdr_smb_sid_t(xdrs, objp) return (TRUE); } -bool_t +static bool_t xdr_smb_luid_t(xdrs, objp) XDR *xdrs; smb_luid_t *objp; @@ -322,7 +249,7 @@ xdr_smb_luid_t(xdrs, objp) return (TRUE); } -bool_t +static bool_t xdr_smb_luid_attrs_t(xdrs, objp) XDR *xdrs; smb_luid_attrs_t *objp; @@ -334,7 +261,7 @@ xdr_smb_luid_attrs_t(xdrs, objp) return (TRUE); } -bool_t +static bool_t xdr_smb_privset_t(xdrs, objp) XDR *xdrs; smb_privset_t *objp; @@ -351,30 +278,17 @@ xdr_smb_privset_t(xdrs, objp) } bool_t -xdr_smb_sid_attrs_t(xdrs, objp) - XDR *xdrs; - smb_sid_attrs_t *objp; -{ - if (!xdr_uint32_t(xdrs, &objp->attrs)) - return (FALSE); - return (xdr_sid_helper(xdrs, (char **)&objp->sid)); -} - -bool_t xdr_smb_token_t(xdrs, objp) XDR *xdrs; smb_token_t *objp; { - if (!xdr_pointer(xdrs, (char **)&objp->tkn_user, - sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t)) + if (!xdr_smb_id_t(xdrs, &objp->tkn_user)) return (FALSE); - if (!xdr_pointer(xdrs, (char **)&objp->tkn_owner, - sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t)) + if (!xdr_smb_id_t(xdrs, &objp->tkn_owner)) return (FALSE); - if (!xdr_pointer(xdrs, (char **)&objp->tkn_primary_grp, - sizeof (smb_id_t), (xdrproc_t)xdr_smb_id_t)) + if (!xdr_smb_id_t(xdrs, &objp->tkn_primary_grp)) return (FALSE); - if (!xdr_smb_win_grps_helper(xdrs, (char **)&objp->tkn_win_grps)) + if (!xdr_smb_ids_t(xdrs, &objp->tkn_win_grps)) return (FALSE); if (!xdr_smb_privset_helper(xdrs, (char **)&objp->tkn_privileges)) return (FALSE); diff --git a/usr/src/common/smbsrv/smb_xdr_utils.c b/usr/src/common/smbsrv/smb_xdr_utils.c index 4bbd59618c..c3d16a1cc5 100644 --- a/usr/src/common/smbsrv/smb_xdr_utils.c +++ b/usr/src/common/smbsrv/smb_xdr_utils.c @@ -29,7 +29,7 @@ #include <strings.h> #endif /* _KERNEL */ #include <smbsrv/smb_xdr.h> - +#include <sys/socket.h> #ifdef _KERNEL /* * xdr_vector(): @@ -199,6 +199,22 @@ smb_opipe_context_decode(smb_opipe_context_t *ctx, uint8_t *buf, } bool_t +xdr_smb_inaddr_t(XDR *xdrs, smb_inaddr_t *objp) +{ + if (!xdr_int32_t(xdrs, &objp->a_family)) + return (FALSE); + if (objp->a_family == AF_INET) { + if (!xdr_uint32_t(xdrs, (in_addr_t *)&objp->a_ipv4)) + return (FALSE); + } else { + if (!xdr_vector(xdrs, (char *)&objp->a_ipv6, + sizeof (objp->a_ipv6), sizeof (char), (xdrproc_t)xdr_char)) + return (FALSE); + } + return (TRUE); +} + +bool_t smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp) { if (!xdr_uint64_t(xdrs, &objp->oc_session_id)) @@ -217,7 +233,7 @@ smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp) return (FALSE); if (!xdr_string(xdrs, &objp->oc_workstation, ~0)) return (FALSE); - if (!xdr_uint32_t(xdrs, &objp->oc_ipaddr)) + if (!xdr_smb_inaddr_t(xdrs, &objp->oc_ipaddr)) return (FALSE); if (!xdr_int32_t(xdrs, &objp->oc_native_os)) return (FALSE); @@ -228,7 +244,6 @@ smb_opipe_context_xdr(XDR *xdrs, smb_opipe_context_t *objp) return (TRUE); } - bool_t xdr_smb_dr_ulist_t(xdrs, objp) XDR *xdrs; diff --git a/usr/src/lib/libshare/smb/libshare_smb.c b/usr/src/lib/libshare/smb/libshare_smb.c index fd9a951c8f..30e8ae088a 100644 --- a/usr/src/lib/libshare/smb/libshare_smb.c +++ b/usr/src/lib/libshare/smb/libshare_smb.c @@ -882,6 +882,8 @@ struct smb_proto_option_defs { string_length_check_validator, SMB_REFRESH_REFRESH }, { SMB_CI_DYNDNS_ENABLE, 0, 0, true_false_validator, 0 }, { SMB_CI_AUTOHOME_MAP, 0, MAX_VALUE_BUFLEN, path_validator, 0 }, + { SMB_CI_IPV6_ENABLE, 0, 0, true_false_validator, + SMB_REFRESH_REFRESH }, }; #define SMB_OPT_NUM \ diff --git a/usr/src/lib/libshare/smb/smb_share_doorclnt.c b/usr/src/lib/libshare/smb/smb_share_doorclnt.c index 3232ce4868..e7a93507fa 100644 --- a/usr/src/lib/libshare/smb/smb_share_doorclnt.c +++ b/usr/src/lib/libshare/smb/smb_share_doorclnt.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -368,50 +368,6 @@ smb_share_rename(char *from, char *to) } uint32_t -smb_share_get(char *share_name, smb_share_t *si) -{ - door_arg_t *arg; - smb_dr_ctx_t *dec_ctx; - smb_dr_ctx_t *enc_ctx; - uint32_t rc; - - if ((arg = smb_share_door_clnt_enter()) == NULL) - return (NERR_InternalError); - - enc_ctx = smb_dr_encode_start(arg->data_ptr, SMB_SHARE_DSIZE); - smb_dr_put_uint32(enc_ctx, SMB_SHROP_GETINFO); - smb_dr_put_string(enc_ctx, share_name); - - rc = smb_dr_encode_finish(enc_ctx, (unsigned int *)&arg->data_size); - if (rc != 0) { - smb_share_door_clnt_exit(arg, B_FALSE, "encode"); - return (NERR_InternalError); - } - - if (smb_share_door_call(smb_share_dfd, arg) < 0) { - smb_share_door_clnt_exit(arg, B_TRUE, "door call"); - return (NERR_InternalError); - } - - dec_ctx = smb_dr_decode_start(arg->data_ptr, arg->data_size); - if (smb_share_dchk(dec_ctx) != 0) { - (void) smb_dr_decode_finish(dec_ctx); - smb_share_door_clnt_exit(arg, B_FALSE, "decode"); - return (NERR_InternalError); - } - - rc = smb_dr_get_uint32(dec_ctx); - smb_dr_get_share(dec_ctx, si); - if (smb_dr_decode_finish(dec_ctx) != 0) { - smb_share_door_clnt_exit(arg, B_FALSE, "decode"); - return (NERR_InternalError); - } - - smb_share_door_clnt_exit(arg, B_FALSE, NULL); - return (rc); -} - -uint32_t smb_share_create(smb_share_t *si) { door_arg_t *arg; diff --git a/usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c b/usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c index ae10a98848..d1decb44bf 100644 --- a/usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c +++ b/usr/src/lib/smbsrv/libmlrpc/common/ndr_heap.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -68,19 +68,19 @@ ndr_heap_create(void) { ndr_heap_t *heap; char *base; + size_t allocsize = sizeof (ndr_heap_t) + NDR_HEAP_BLKSZ; - if ((base = (char *)malloc(NDR_HEAP_BLKSZ)) == NULL) + if ((heap = malloc(allocsize)) == NULL) return (NULL); - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - heap = (ndr_heap_t *)base; + base = (char *)heap; bzero(heap, sizeof (ndr_heap_t)); heap->iovcnt = NDR_HEAP_MAXIOV; heap->iov = heap->iovec; heap->iov->iov_base = base; heap->iov->iov_len = sizeof (ndr_heap_t); - heap->top = base + NDR_HEAP_BLKSZ; + heap->top = base + allocsize; heap->next = base + sizeof (ndr_heap_t); return (heap); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c index 49c941af66..66fd860dde 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_svc.c @@ -285,15 +285,25 @@ logr_s_EventLogOpen(void *arg, ndr_xa_t *mxa) struct logr_EventLogOpen *param = arg; ndr_hdid_t *id = NULL; ndr_handle_t *hd; + char *log_name = NULL; + + if (param->log_name.length != 0) + log_name = (char *)param->log_name.str; + + if ((log_name == NULL) || strcasecmp(log_name, "System") != 0) { + bzero(¶m->handle, sizeof (logr_handle_t)); + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); + return (NDR_DRC_OK); + } id = logr_hdalloc(mxa); if (id && ((hd = logr_hdlookup(mxa, id)) != NULL)) { hd->nh_data_free = logr_context_data_free; bcopy(id, ¶m->handle, sizeof (logr_handle_t)); - param->status = ERROR_SUCCESS; + param->status = NT_STATUS_SUCCESS; } else { bzero(¶m->handle, sizeof (logr_handle_t)); - param->status = ERROR_ACCESS_DENIED; + param->status = NT_SC_ERROR(NT_STATUS_ACCESS_DENIED); } return (NDR_DRC_OK); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c index 0cb5fb6d71..f89c62d076 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/eventlog_syslog.c @@ -38,38 +38,27 @@ #include <ctype.h> #include "eventlog.h" -#define LOGR_SYSLOG_PARSE_ENTRY_SUCCESS 0 -#define LOGR_SYSLOG_PARSE_ENTRY_ERR -1 -#define LOGR_SYSLOG_PARSE_NOPRI_ERR -2 - -#define LOGR_SYSLOG_PARSE_IDTOKEN_PFX "[ID" - typedef enum { - LOGR_SYSLOG_MONTH = 0, - LOGR_SYSLOG_DAY, - LOGR_SYSLOG_TIME, - LOGR_SYSLOG_MACHINENAME, - LOGR_SYSLOG_SOURCE, - LOGR_SYSLOG_ID, - LOGR_SYSLOG_PRI_FAC, - LOGR_SYSLOG_NARG -} logr_syslog_tokens; - -typedef enum { - LOGR_SYSLOG_FACILITY = 0, - LOGR_SYSLOG_PRIORITY, - LOGR_SYSLOG_PRI_FAC_NARG -} logr_syslog_pri_fac_tokens; + LOGR_MONTH = 0, + LOGR_DAY, + LOGR_TIME, + LOGR_HOST, + LOGR_SOURCE, + LOGR_IDTAG, + LOGR_ID, + LOGR_PRI_FAC, + LOGR_NARG +} logr_syslog_tokens_t; /* * Event code translation struct for use in processing config file */ -typedef struct logr_code_tbl { - char *c_name; - int c_val; -} logr_code_tbl_t; +typedef struct logr_priority { + char *p_name; + int p_value; +} logr_priority_t; -static logr_code_tbl_t logr_syslog_pri_names[] = { +static logr_priority_t logr_pri_names[] = { "panic", LOG_EMERG, "emerg", LOG_EMERG, "alert", LOG_ALERT, @@ -83,233 +72,126 @@ static logr_code_tbl_t logr_syslog_pri_names[] = { "debug", LOG_DEBUG }; -static logr_code_tbl_t logr_syslog_fac_names[] = { - "kern", LOG_KERN, - "user", LOG_USER, - "mail", LOG_MAIL, - "daemon", LOG_DAEMON, - "auth", LOG_AUTH, - "security", LOG_AUTH, - "syslog", LOG_SYSLOG, - "lpr", LOG_LPR, - "news", LOG_NEWS, - "uucp", LOG_UUCP, - "audit", LOG_AUDIT, - "cron", LOG_CRON, - "local0", LOG_LOCAL0, - "local1", LOG_LOCAL1, - "local2", LOG_LOCAL2, - "local3", LOG_LOCAL3, - "local4", LOG_LOCAL4, - "local5", LOG_LOCAL5, - "local6", LOG_LOCAL6, - "local7", LOG_LOCAL7 -}; - typedef struct logr_syslog_node { list_node_t ln_node; char ln_logline[LOGR_MAXENTRYLEN]; } logr_syslog_node_t; /* - * Sets the loghost of an syslog entry. - * Returns 0 on success, -1 on failure. - */ -static int -logr_syslog_set_loghost(char *log_host, logr_entry_t *le) -{ - if (log_host == NULL) - return (-1); - - (void) strlcpy(le->le_hostname, log_host, MAXHOSTNAMELEN); - - return (0); -} - -/* - * Sets the timestamp of an syslog entry. - * Returns 0 on success, -1 on failure. + * Set the syslog timestamp. + * + * This is a private helper for logr_syslog_parse_entry(), which + * must ensure that the appropriate argv entries are non-null. */ -static int -logr_syslog_set_timestamp(char *month, char *day, char *time, logr_entry_t *le) +static void +logr_syslog_set_timestamp(char **argv, logr_entry_t *le) { + char *month = argv[LOGR_MONTH]; + char *day = argv[LOGR_DAY]; + char *time = argv[LOGR_TIME]; struct timeval now; struct tm tm, cur_tm; - char buf[30]; - - if ((month == NULL) || (day == NULL) || (time == NULL)) - return (-1); + char buf[32]; bzero(&tm, sizeof (tm)); - (void) snprintf(buf, 30, "%s %s %s", month, day, time); - if (strptime(buf, "%b" "%d" "%H:%M:%S", &tm) == NULL) - return (-1); - - /* get the current dst, year and apply it. */ - if (gettimeofday(&now, NULL) != 0) - return (-1); + (void) snprintf(buf, 32, "%s %s %s", month, day, time); + if (strptime(buf, "%b" "%d" "%H:%M:%S", &tm) == NULL) { + le->le_timestamp.tv_sec = 0; + return; + } - if (localtime_r(&now.tv_sec, &cur_tm) == NULL) - return (-1); + (void) gettimeofday(&now, NULL); + (void) localtime_r(&now.tv_sec, &cur_tm); tm.tm_isdst = cur_tm.tm_isdst; tm.tm_year = cur_tm.tm_year; if (tm.tm_mon > cur_tm.tm_mon) - tm.tm_year = tm.tm_year - 1; - - if ((le->le_timestamp.tv_sec = mktime(&tm)) == -1) - return (-1); + tm.tm_year--; - return (0); + le->le_timestamp.tv_sec = mktime(&tm); } /* - * Sets the Priority and Facility of an syslog entry. - * Returns 0 on success, -1 on failure. + * Set the syslog priority. + * + * This is a private helper for logr_syslog_parse_entry(), which + * must ensure that the appropriate argv entries are non-null. */ -static int -logr_syslog_set_pri_fac(char *pf_tkn, logr_entry_t *le) +static void +logr_syslog_set_priority(char **argv, logr_entry_t *le) { - int pri_fac[LOGR_SYSLOG_PRI_FAC_NARG]; - int j, sz = 0; + logr_priority_t *entry; + char *token; + int sz = sizeof (logr_pri_names) / sizeof (logr_pri_names[0]); + int i; le->le_pri = LOG_INFO; - if (pf_tkn == NULL) - return (-1); - - /* Defaults */ - pri_fac[LOGR_SYSLOG_FACILITY] = LOG_USER; - pri_fac[LOGR_SYSLOG_PRIORITY] = LOG_INFO; + if ((token = argv[LOGR_PRI_FAC]) == NULL) + return; - sz = sizeof (logr_syslog_fac_names) / sizeof (logr_syslog_fac_names[0]); - for (j = 0; j < sz; j++) { - if (strstr(pf_tkn, logr_syslog_fac_names[j].c_name) != NULL) { - pri_fac[LOGR_SYSLOG_FACILITY] = - logr_syslog_fac_names[j].c_val; - break; - } - } + for (i = 0; i < sz; i++) { + entry = &logr_pri_names[i]; - sz = sizeof (logr_syslog_pri_names) / sizeof (logr_syslog_pri_names[0]); - for (j = 0; j < sz; j++) { - if (strstr(pf_tkn, logr_syslog_pri_names[j].c_name) != NULL) { - pri_fac[LOGR_SYSLOG_PRIORITY] = - logr_syslog_pri_names[j].c_val; + if (strstr(token, entry->p_name) != NULL) { + le->le_pri = entry->p_value; break; } } - - le->le_pri = pri_fac[LOGR_SYSLOG_PRIORITY]; - - return (0); -} - -/* - * Sets the messages of an syslog entry. - */ -static void -logr_syslog_set_message(char *logline, logr_entry_t *le) -{ - char *p; - - if ((p = strchr(logline, '\n')) != NULL) - *p = '\0'; - - (void) strlcpy(le->le_msg, logline, LOGR_MAXENTRYLEN); } /* - * Parses the tokens from an syslog entry. A typical syslog entry is of the - * following standard format, + * Parse a syslog entry into a log_entry_t structure. A typical syslog + * entry has one of the following formats: * - * <month> <day> <time> <loghost> <source>: [ID <ID> <facility.priority>] <msg> - * For Example: - * Oct 29 09:49:20 pbgalaxy1 smbd[104039]: [ID 702911 daemon.info] init done. + * <month> <day> <time> <host> <msg> + * <month> <day> <time> <host> <source>: [ID <ID> <facility.priority>] <msg> * - * This method parses the above syslog entry and populates the log_entry_t - * structure from the parsed tokens. It returns the following return codes. - * - * Returns, - * LOGR_SYSLOG_PARSE_ENTRY_ERR: If the syslog entry is NULL, or there is - * error in parsing the entry or entry is - * not in the standard format. - * LOGR_SYSLOG_PARSE_NOPRI_ERR: If the priority of the message cannot be - * obtained from the parsed tokens. - * LOGR_SYSLOG_PARSE_ENTRY_SUCCESS: If the syslog entry is sucessfully - * parsed. + * For Example: + * Oct 29 09:49:20 galaxy smbd[104039]: [ID 702911 daemon.info] init done */ static int -logr_syslog_parse_tokens(char *logline, logr_entry_t *le) +logr_syslog_parse_entry(char *logline, logr_entry_t *le) { - char *argv[LOGR_SYSLOG_NARG]; + char buf[LOGR_MAXENTRYLEN]; + char *argv[LOGR_NARG]; + char *value; + char *bp; int i; - boolean_t no_pri = B_TRUE; - - for (i = 0; i < LOGR_SYSLOG_NARG; ++i) { - if ((argv[i] = strsep(&logline, " ")) == NULL) - return (LOGR_SYSLOG_PARSE_ENTRY_ERR); - (void) trim_whitespace(logline); - - if ((i == LOGR_SYSLOG_ID) && - (strcmp(argv[i], LOGR_SYSLOG_PARSE_IDTOKEN_PFX) == 0)) { - i--; - no_pri = B_FALSE; + (void) memset(argv, 0, sizeof (char *) * LOGR_NARG); + (void) strlcpy(buf, logline, LOGR_MAXENTRYLEN); + + for (bp = buf, i = 0; i < LOGR_NARG; ++i) { + if (i == LOGR_SOURCE) { + /* + * If the [ID key is not present, everything + * that follows is the message text. + */ + if (strstr(bp, "[ID") == NULL) + break; } - } - - if (logr_syslog_set_timestamp(argv[LOGR_SYSLOG_MONTH], - argv[LOGR_SYSLOG_DAY], argv[LOGR_SYSLOG_TIME], le) < 0) - return (LOGR_SYSLOG_PARSE_ENTRY_ERR); - - if (logr_syslog_set_loghost(argv[LOGR_SYSLOG_MACHINENAME], le) < 0) - return (LOGR_SYSLOG_PARSE_ENTRY_ERR); - - if (no_pri) - return (LOGR_SYSLOG_PARSE_NOPRI_ERR); - if (logr_syslog_set_pri_fac(argv[LOGR_SYSLOG_PRI_FAC], le) < 0) - return (LOGR_SYSLOG_PARSE_NOPRI_ERR); + do { + if ((value = strsep(&bp, " \t")) == NULL) + break; + } while (*value == '\0'); - logr_syslog_set_message(logline, le); - - return (LOGR_SYSLOG_PARSE_ENTRY_SUCCESS); -} - -/* - * log_syslog_parse_entry - * - * Parse the given syslog entry into a log_entry_t structure. - * - * Returns, - * LOGR_SYSLOG_PARSE_ENTRY_SUCCESS: If the parsing is successful. - * An error code less than zero, if parsing fails. - */ -static int -logr_syslog_parse_entry(char *logline, logr_entry_t *le) -{ - char *dup_logline; - int ret = LOGR_SYSLOG_PARSE_ENTRY_SUCCESS; - - if (logline == NULL) - return (LOGR_SYSLOG_PARSE_ENTRY_ERR); - - dup_logline = strdup(logline); - ret = logr_syslog_parse_tokens(dup_logline, le); - free(dup_logline); - - switch (ret) { - case LOGR_SYSLOG_PARSE_NOPRI_ERR: - le->le_pri = LOG_INFO; - logr_syslog_set_message(logline, le); - ret = LOGR_SYSLOG_PARSE_ENTRY_SUCCESS; - break; - default: - break; + if ((argv[i] = value) == NULL) + return (-1); } - return (ret); + /* + * bp should be pointing at the remaining message text. + */ + if ((value = strchr(bp, '\n')) != NULL) + *value = '\0'; + + (void) strlcpy(le->le_msg, bp, LOGR_MAXENTRYLEN); + (void) strlcpy(le->le_hostname, argv[LOGR_HOST], MAXHOSTNAMELEN); + logr_syslog_set_timestamp(argv, le); + logr_syslog_set_priority(argv, le); + return (0); } static void @@ -383,8 +265,7 @@ logr_syslog_load(FILE *fp, logr_info_t *log) while (node) { entry = &log->li_entry[i]; - if (logr_syslog_parse_entry(node->ln_logline, entry) != - LOGR_SYSLOG_PARSE_ENTRY_SUCCESS) { + if (logr_syslog_parse_entry(node->ln_logline, entry) != 0) { node = list_next(&queue, node); continue; } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h index 88f5440a44..439fec50e2 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h +++ b/usr/src/lib/smbsrv/libmlsvc/common/libmlsvc.h @@ -48,48 +48,6 @@ extern "C" { #endif -typedef struct lsa_nt_domaininfo { - smb_sid_t *n_sid; - char n_domain[NETBIOS_NAME_SZ]; -} lsa_nt_domaininfo_t; - -typedef struct lsa_trusted_domainlist { - uint32_t t_num; - lsa_nt_domaininfo_t *t_domains; -} lsa_trusted_domainlist_t; - -typedef struct lsa_dns_domaininfo { - smb_sid_t *d_sid; - char d_nbdomain[NETBIOS_NAME_SZ]; - char d_fqdomain[MAXHOSTNAMELEN]; - char d_forest[MAXHOSTNAMELEN]; - mslsa_guid_t d_guid; -} lsa_dns_domaininfo_t; - -typedef enum lsa_info_type { - LSA_INFO_NONE, - LSA_INFO_PRIMARY_DOMAIN, - LSA_INFO_ACCOUNT_DOMAIN, - LSA_INFO_DNS_DOMAIN, - LSA_INFO_TRUSTED_DOMAINS -} lsa_info_type_t; - -typedef struct lsa_info { - lsa_info_type_t i_type; - union { - lsa_nt_domaininfo_t di_primary; - lsa_nt_domaininfo_t di_account; - lsa_dns_domaininfo_t di_dns; - lsa_trusted_domainlist_t di_trust; - } i_domain; -} lsa_info_t; - -extern DWORD lsa_query_primary_domain_info(char *, char *, lsa_info_t *); -extern DWORD lsa_query_account_domain_info(char *, char *, lsa_info_t *); -extern DWORD lsa_query_dns_domain_info(char *, char *, lsa_info_t *); -extern DWORD lsa_enum_trusted_domains(char *, char *, lsa_info_t *); -extern void lsa_free_info(lsa_info_t *); - extern uint32_t mlsvc_lookup_name(char *, smb_sid_t **, uint16_t *); extern uint32_t mlsvc_lookup_sid(smb_sid_t *, char **); @@ -165,12 +123,6 @@ typedef struct smb_autohome { extern void smb_autohome_add(const char *); extern void smb_autohome_remove(const char *); -smb_userinfo_t *mlsvc_alloc_user_info(void); -void mlsvc_free_user_info(smb_userinfo_t *user_info); -void mlsvc_release_user_info(smb_userinfo_t *user_info); -void mlsvc_setadmin_user_info(smb_userinfo_t *user_info); -char *mlsvc_sid_name_use(unsigned int snu_id); - /* * A local unique id (LUID) is an opaque id used by servers to identify * local resources, such as privileges. A client will use lookup diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c index 50a2c1586b..6419a99c3f 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.c @@ -39,22 +39,17 @@ #include <lsalib.h> -static uint32_t lsa_lookup_name_builtin(char *, char *, smb_userinfo_t *); -static uint32_t lsa_lookup_name_local(char *, char *, uint16_t, - smb_userinfo_t *); -static uint32_t lsa_lookup_name_domain(char *, smb_userinfo_t *); -static uint32_t lsa_lookup_name_lusr(char *, smb_sid_t **); -static uint32_t lsa_lookup_name_lgrp(char *, smb_sid_t **); +static uint32_t lsa_lookup_name_builtin(char *, char *, smb_account_t *); +static uint32_t lsa_lookup_name_domain(char *, smb_account_t *); -static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_userinfo_t *); -static uint32_t lsa_lookup_sid_local(smb_sid_t *, smb_userinfo_t *); -static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_userinfo_t *); +static uint32_t lsa_lookup_sid_builtin(smb_sid_t *, smb_account_t *); +static uint32_t lsa_lookup_sid_domain(smb_sid_t *, smb_account_t *); static int lsa_list_accounts(mlsvc_handle_t *); /* * Lookup the given account and returns the account information - * in the passed smb_userinfo_t structure. + * in the passed smb_account_t structure. * * The lookup is performed in the following order: * well known accounts @@ -78,7 +73,7 @@ static int lsa_list_accounts(mlsvc_handle_t *); * NT_STATUS_NONE_MAPPED Couldn't translate the account */ uint32_t -lsa_lookup_name(char *account, uint16_t sid_type, smb_userinfo_t *info) +lsa_lookup_name(char *account, uint16_t type, smb_account_t *info) { char nambuf[SMB_USERNAME_MAXLEN]; char dombuf[SMB_PI_MAX_DOMAIN]; @@ -105,7 +100,7 @@ lsa_lookup_name(char *account, uint16_t sid_type, smb_userinfo_t *info) status = lsa_lookup_name_builtin(domain, name, info); if (status == NT_STATUS_NOT_FOUND) { - status = lsa_lookup_name_local(domain, name, sid_type, info); + status = smb_sam_lookup_name(domain, name, type, info); if (status == NT_STATUS_SUCCESS) return (status); @@ -117,18 +112,21 @@ lsa_lookup_name(char *account, uint16_t sid_type, smb_userinfo_t *info) } uint32_t -lsa_lookup_sid(smb_sid_t *sid, smb_userinfo_t *ainfo) +lsa_lookup_sid(smb_sid_t *sid, smb_account_t *info) { + uint32_t status; + if (!smb_sid_isvalid(sid)) return (NT_STATUS_INVALID_SID); - if (smb_sid_islocal(sid)) - return (lsa_lookup_sid_local(sid, ainfo)); - - if (smb_wka_lookup_sid(sid, NULL)) - return (lsa_lookup_sid_builtin(sid, ainfo)); + status = lsa_lookup_sid_builtin(sid, info); + if (status == NT_STATUS_NOT_FOUND) { + status = smb_sam_lookup_sid(sid, info); + if (status == NT_STATUS_NOT_FOUND) + status = lsa_lookup_sid_domain(sid, info); + } - return (lsa_lookup_sid_domain(sid, ainfo)); + return ((status == NT_STATUS_SUCCESS) ? status : NT_STATUS_NONE_MAPPED); } /* @@ -309,12 +307,14 @@ lsa_free_info(lsa_info_t *info) * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure */ static uint32_t -lsa_lookup_name_builtin(char *domain, char *name, smb_userinfo_t *info) +lsa_lookup_name_builtin(char *domain, char *name, smb_account_t *info) { smb_wka_t *wka; char *wkadom; - if ((wka = smb_wka_lookup(name)) == NULL) + bzero(info, sizeof (smb_account_t)); + + if ((wka = smb_wka_lookup_name(name)) == NULL) return (NT_STATUS_NOT_FOUND); if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) @@ -323,98 +323,17 @@ lsa_lookup_name_builtin(char *domain, char *name, smb_userinfo_t *info) if ((domain != NULL) && (utf8_strcasecmp(domain, wkadom) != 0)) return (NT_STATUS_NONE_MAPPED); - info->user_sid = smb_sid_dup(wka->wka_binsid); - info->domain_sid = smb_sid_dup(wka->wka_binsid); - info->domain_name = strdup(wkadom); + info->a_name = strdup(name); + info->a_sid = smb_sid_dup(wka->wka_binsid); + info->a_domain = strdup(wkadom); + info->a_domsid = smb_sid_split(wka->wka_binsid, &info->a_rid); + info->a_type = wka->wka_type; - if ((info->user_sid == NULL) || (info->domain_sid == NULL) || - (info->domain_name == NULL)) + if (!smb_account_validate(info)) { + smb_account_free(info); return (NT_STATUS_NO_MEMORY); - - if (smb_sid_split(info->domain_sid, &info->rid) < 0) - return (NT_STATUS_INTERNAL_ERROR); - - info->sid_name_use = wka->wka_type; - return (NT_STATUS_SUCCESS); -} - -/* - * Obtains the infomation for the given local account name if it - * can be found. The type of account is specified by sid_type, - * which can be of user, group or unknown type. If the caller - * doesn't know whether the name is a user or group name then - * SidTypeUnknown should be passed, in which case this - * function first tries to find a user and then a group match. - * - * Return status: - * - * NT_STATUS_NOT_FOUND This is not a local account - * NT_STATUS_NONE_MAPPED It's a local account but cannot be - * translated. - * other error status codes. - */ -static uint32_t -lsa_lookup_name_local(char *domain, char *name, uint16_t sid_type, - smb_userinfo_t *info) -{ - char hostname[MAXHOSTNAMELEN]; - smb_sid_t *sid; - uint32_t status; - - (void) smb_getnetbiosname(hostname, sizeof (hostname)); - - if (domain != NULL) { - if (!smb_ishostname(domain)) - return (NT_STATUS_NOT_FOUND); - - /* Only Netbios hostname is accepted */ - if (utf8_strcasecmp(domain, hostname) != 0) - return (NT_STATUS_NONE_MAPPED); - } - - if ((info->domain_name = strdup(hostname)) == NULL) - return (NT_STATUS_NO_MEMORY); - - switch (sid_type) { - case SidTypeUser: - status = lsa_lookup_name_lusr(name, &sid); - if (status != NT_STATUS_SUCCESS) - return (status); - break; - - case SidTypeGroup: - case SidTypeAlias: - status = lsa_lookup_name_lgrp(name, &sid); - if (status != NT_STATUS_SUCCESS) - return (status); - break; - - case SidTypeUnknown: - sid_type = SidTypeUser; - status = lsa_lookup_name_lusr(name, &sid); - if (status == NT_STATUS_SUCCESS) - break; - - if (status == NT_STATUS_NONE_MAPPED) - return (status); - - sid_type = SidTypeAlias; - status = lsa_lookup_name_lgrp(name, &sid); - if (status != NT_STATUS_SUCCESS) - return (status); - break; - - default: - return (NT_STATUS_INVALID_PARAMETER); } - info->sid_name_use = sid_type; - info->user_sid = sid; - info->domain_sid = smb_sid_dup(sid); - if (info->domain_sid == NULL) - return (NT_STATUS_NO_MEMORY); - - (void) smb_sid_split(info->domain_sid, &info->rid); return (NT_STATUS_SUCCESS); } @@ -426,7 +345,7 @@ lsa_lookup_name_local(char *domain, char *name, uint16_t sid_type, * this structure. */ static uint32_t -lsa_lookup_name_domain(char *account_name, smb_userinfo_t *user_info) +lsa_lookup_name_domain(char *account_name, smb_account_t *info) { mlsvc_handle_t domain_handle; smb_domain_t dinfo; @@ -439,14 +358,13 @@ lsa_lookup_name_domain(char *account_name, smb_userinfo_t *user_info) if (lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user, &domain_handle) != 0) return (NT_STATUS_INVALID_PARAMETER); - status = lsar_lookup_names2(&domain_handle, account_name, user_info); + status = lsar_lookup_names2(&domain_handle, account_name, info); if (status == NT_STATUS_REVISION_MISMATCH) { /* * Not a Windows 2000 domain controller: * use the NT compatible call. */ - status = lsar_lookup_names(&domain_handle, account_name, - user_info); + status = lsar_lookup_names(&domain_handle, account_name, info); } (void) lsar_close(&domain_handle); @@ -468,8 +386,7 @@ lsa_lookup_name_domain(char *account_name, smb_userinfo_t *user_info) */ /*ARGSUSED*/ int -lsa_lookup_privs(char *account_name, char *target_name, - smb_userinfo_t *user_info) +lsa_lookup_privs(char *account_name, char *target_name, smb_account_t *ainfo) { mlsvc_handle_t domain_handle; int rc; @@ -526,30 +443,6 @@ lsa_list_privs(char *server, char *domain) } /* - * lsa_test - * - * LSA test routine: open and close the LSA interface. - * - * On success 0 is returned. Otherwise a -ve error code. - */ -int -lsa_test(char *server, char *domain) -{ - mlsvc_handle_t domain_handle; - int rc; - char *user = smbrdr_ipc_get_user(); - - rc = lsar_open(server, domain, user, &domain_handle); - if (rc != 0) - return (-1); - - if (lsar_close(&domain_handle) != 0) - return (-1); - - return (0); -} - -/* * lsa_list_accounts * * This function can be used to list the accounts in the specified @@ -563,14 +456,11 @@ lsa_list_accounts(mlsvc_handle_t *domain_handle) mlsvc_handle_t account_handle; struct mslsa_EnumAccountBuf accounts; struct mslsa_sid *sid; - char *name; - WORD sid_name_use; - smb_userinfo_t *user_info; + smb_account_t ainfo; DWORD enum_context = 0; int rc; int i; - user_info = mlsvc_alloc_user_info(); bzero(&accounts, sizeof (struct mslsa_EnumAccountBuf)); do { @@ -582,169 +472,63 @@ lsa_list_accounts(mlsvc_handle_t *domain_handle) for (i = 0; i < accounts.entries_read; ++i) { sid = accounts.info[i].sid; - name = smb_wka_lookup_sid((smb_sid_t *)sid, - &sid_name_use); - - if (name == 0) { - if (lsar_lookup_sids(domain_handle, sid, - user_info) == 0) { - name = user_info->name; - sid_name_use = user_info->sid_name_use; - } else { - name = "unknown"; - sid_name_use = SidTypeUnknown; - } - } - if (lsar_open_account(domain_handle, sid, &account_handle) == 0) { (void) lsar_enum_privs_account(&account_handle, - user_info); + &ainfo); (void) lsar_close(&account_handle); } free(accounts.info[i].sid); - mlsvc_release_user_info(user_info); } if (accounts.info) free(accounts.info); } while (rc == 0 && accounts.entries_read != 0); - mlsvc_free_user_info(user_info); return (0); } /* - * Lookup local SMB user account database (/var/smb/smbpasswd) - * if there's a match query its SID from idmap service and make - * sure the SID is a local SID. + * Lookup well known accounts table for the given SID * - * The memory for the returned SID must be freed by the caller. - */ -static uint32_t -lsa_lookup_name_lusr(char *name, smb_sid_t **sid) -{ - smb_passwd_t smbpw; - - if (smb_pwd_getpwnam(name, &smbpw) == NULL) - return (NT_STATUS_NO_SUCH_USER); - - if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid) - != IDMAP_SUCCESS) - return (NT_STATUS_NONE_MAPPED); - - if (!smb_sid_islocal(*sid)) { - smb_sid_free(*sid); - return (NT_STATUS_NONE_MAPPED); - } - - return (NT_STATUS_SUCCESS); -} - -/* - * Lookup local SMB group account database (/var/smb/smbgroup.db) - * The memory for the returned SID must be freed by the caller. + * Return status: + * + * NT_STATUS_SUCCESS Account is translated successfully + * NT_STATUS_NOT_FOUND This is not a well known account + * NT_STATUS_NO_MEMORY Memory shortage + * NT_STATUS_INTERNAL_ERROR Internal error/unexpected failure */ static uint32_t -lsa_lookup_name_lgrp(char *name, smb_sid_t **sid) -{ - smb_group_t grp; - - if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS) - return (NT_STATUS_NO_SUCH_ALIAS); - - *sid = smb_sid_dup(grp.sg_id.gs_sid); - smb_lgrp_free(&grp); - - return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS); -} - -static uint32_t -lsa_lookup_sid_local(smb_sid_t *sid, smb_userinfo_t *ainfo) +lsa_lookup_sid_builtin(smb_sid_t *sid, smb_account_t *ainfo) { - char hostname[MAXHOSTNAMELEN]; - smb_passwd_t smbpw; - smb_group_t grp; - uint32_t rid; - uid_t id; - int id_type; - int rc; - - id_type = SMB_IDMAP_UNKNOWN; - if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS) - return (NT_STATUS_NONE_MAPPED); - - switch (id_type) { - case SMB_IDMAP_USER: - ainfo->sid_name_use = SidTypeUser; - if (smb_pwd_getpwuid(id, &smbpw) == NULL) - return (NT_STATUS_NO_SUCH_USER); - - ainfo->name = strdup(smbpw.pw_name); - break; - - case SMB_IDMAP_GROUP: - ainfo->sid_name_use = SidTypeAlias; - (void) smb_sid_getrid(sid, &rid); - rc = smb_lgrp_getbyrid(rid, SMB_LGRP_LOCAL, &grp); - if (rc != SMB_LGRP_SUCCESS) - return (NT_STATUS_NO_SUCH_ALIAS); - - ainfo->name = strdup(grp.sg_name); - smb_lgrp_free(&grp); - break; + smb_wka_t *wka; + char *wkadom; - default: - return (NT_STATUS_NONE_MAPPED); - } + bzero(ainfo, sizeof (smb_account_t)); - if (ainfo->name == NULL) - return (NT_STATUS_NO_MEMORY); + if ((wka = smb_wka_lookup_sid(sid)) == NULL) + return (NT_STATUS_NOT_FOUND); - ainfo->domain_sid = smb_sid_dup(sid); - if (smb_sid_split(ainfo->domain_sid, &ainfo->rid) < 0) + if ((wkadom = smb_wka_get_domain(wka->wka_domidx)) == NULL) return (NT_STATUS_INTERNAL_ERROR); - *hostname = '\0'; - (void) smb_getnetbiosname(hostname, MAXHOSTNAMELEN); - if ((ainfo->domain_name = strdup(hostname)) == NULL) - return (NT_STATUS_NO_MEMORY); - - return (NT_STATUS_SUCCESS); -} -static uint32_t -lsa_lookup_sid_builtin(smb_sid_t *sid, smb_userinfo_t *ainfo) -{ - char *name; - WORD sid_name_use; + ainfo->a_name = strdup(wka->wka_name); + ainfo->a_sid = smb_sid_dup(wka->wka_binsid); + ainfo->a_domain = strdup(wkadom); + ainfo->a_domsid = smb_sid_split(ainfo->a_sid, &ainfo->a_rid); + ainfo->a_type = wka->wka_type; - if ((name = smb_wka_lookup_sid(sid, &sid_name_use)) == NULL) - return (NT_STATUS_NONE_MAPPED); - - ainfo->sid_name_use = sid_name_use; - ainfo->name = strdup(name); - ainfo->domain_sid = smb_sid_dup(sid); - - if (ainfo->name == NULL || ainfo->domain_sid == NULL) - return (NT_STATUS_NO_MEMORY); - - if (sid_name_use != SidTypeDomain) - (void) smb_sid_split(ainfo->domain_sid, &ainfo->rid); - - if ((name = smb_wka_lookup_domain(ainfo->name)) != NULL) - ainfo->domain_name = strdup(name); - else - ainfo->domain_name = strdup("UNKNOWN"); - - if (ainfo->domain_name == NULL) + if (!smb_account_validate(ainfo)) { + smb_account_free(ainfo); return (NT_STATUS_NO_MEMORY); + } return (NT_STATUS_SUCCESS); } static uint32_t -lsa_lookup_sid_domain(smb_sid_t *sid, smb_userinfo_t *ainfo) +lsa_lookup_sid_domain(smb_sid_t *sid, smb_account_t *ainfo) { mlsvc_handle_t domain_handle; char *user = smbrdr_ipc_get_user(); @@ -757,8 +541,8 @@ lsa_lookup_sid_domain(smb_sid_t *sid, smb_userinfo_t *ainfo) if (lsar_open(dinfo.d_dc, dinfo.d_nbdomain, user, &domain_handle) != 0) return (NT_STATUS_INVALID_PARAMETER); - status = lsar_lookup_sids2(&domain_handle, - (struct mslsa_sid *)sid, ainfo); + status = lsar_lookup_sids2(&domain_handle, (struct mslsa_sid *)sid, + ainfo); if (status == NT_STATUS_REVISION_MISMATCH) { /* diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h index 526ad35bec..b761b9b8fd 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsalib.h @@ -19,12 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _SMBSRV_LSALIB_H -#define _SMBSRV_LSALIB_H +#ifndef _LSALIB_H +#define _LSALIB_H /* * Prototypes for the LSA library and RPC client side library interface. @@ -36,6 +36,7 @@ */ #include <smbsrv/ndl/lsarpc.ndl> +#include <smbsrv/libsmb.h> #include <smbsrv/libmlsvc.h> #include <smbsrv/smb_sid.h> @@ -44,88 +45,84 @@ extern "C" { #endif +typedef struct lsa_nt_domaininfo { + smb_sid_t *n_sid; + char n_domain[NETBIOS_NAME_SZ]; +} lsa_nt_domaininfo_t; + +typedef struct lsa_trusted_domainlist { + uint32_t t_num; + lsa_nt_domaininfo_t *t_domains; +} lsa_trusted_domainlist_t; + +typedef struct lsa_dns_domaininfo { + smb_sid_t *d_sid; + char d_nbdomain[NETBIOS_NAME_SZ]; + char d_fqdomain[MAXHOSTNAMELEN]; + char d_forest[MAXHOSTNAMELEN]; + mslsa_guid_t d_guid; +} lsa_dns_domaininfo_t; + +typedef enum lsa_info_type { + LSA_INFO_NONE, + LSA_INFO_PRIMARY_DOMAIN, + LSA_INFO_ACCOUNT_DOMAIN, + LSA_INFO_DNS_DOMAIN, + LSA_INFO_TRUSTED_DOMAINS +} lsa_info_type_t; + +typedef struct lsa_info { + lsa_info_type_t i_type; + union { + lsa_nt_domaininfo_t di_primary; + lsa_nt_domaininfo_t di_account; + lsa_dns_domaininfo_t di_dns; + lsa_trusted_domainlist_t di_trust; + } i_domain; +} lsa_info_t; + /* * lsalib.c */ -extern uint32_t lsa_lookup_name(char *, uint16_t, smb_userinfo_t *); -extern uint32_t lsa_lookup_sid(smb_sid_t *, smb_userinfo_t *); -extern int lsa_lookup_privs(char *, char *, smb_userinfo_t *); -extern int lsa_test(char *, char *); +uint32_t lsa_lookup_name(char *, uint16_t, smb_account_t *); +uint32_t lsa_lookup_sid(smb_sid_t *, smb_account_t *); +void lsa_free_info(lsa_info_t *); +DWORD lsa_query_primary_domain_info(char *, char *, lsa_info_t *); +DWORD lsa_query_account_domain_info(char *, char *, lsa_info_t *); +DWORD lsa_query_dns_domain_info(char *, char *, lsa_info_t *); +DWORD lsa_enum_trusted_domains(char *, char *, lsa_info_t *); + /* * lsar_open.c */ -int lsar_open(char *server, - char *domain, - char *username, - mlsvc_handle_t *domain_handle); - -int lsar_open_policy2(char *server, - char *domain, - char *username, - mlsvc_handle_t *lsa_handle); - -int lsar_open_account(mlsvc_handle_t *lsa_handle, - struct mslsa_sid *sid, - mlsvc_handle_t *lsa_account_handle); - -int lsar_close(mlsvc_handle_t *lsa_handle); - +int lsar_open(char *, char *, char *, mlsvc_handle_t *); +int lsar_open_policy2(char *, char *, char *, mlsvc_handle_t *); +int lsar_open_account(mlsvc_handle_t *, struct mslsa_sid *, mlsvc_handle_t *); +int lsar_close(mlsvc_handle_t *); /* * lsar_lookup.c */ -int lsar_query_security_desc(mlsvc_handle_t *lsa_handle); - -DWORD lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass, - lsa_info_t *); - -uint32_t lsar_lookup_names(mlsvc_handle_t *lsa_handle, - char *name, - smb_userinfo_t *user_info); - -uint32_t lsar_lookup_sids(mlsvc_handle_t *lsa_handle, - struct mslsa_sid *sid, - smb_userinfo_t *user_info); - -DWORD lsar_get_userid(char *server, char *name); - -int lsar_enum_accounts(mlsvc_handle_t *lsa_handle, - DWORD *enum_context, - struct mslsa_EnumAccountBuf *accounts); - -DWORD lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, - DWORD *enum_context, lsa_info_t *); - -int lsar_enum_privs_account(mlsvc_handle_t *account_handle, - smb_userinfo_t *user_info); - -int lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, - char *name, - struct ms_luid *luid); - -int lsar_lookup_priv_name(mlsvc_handle_t *lsa_handle, - struct ms_luid *luid, - char *name, - int namelen); - -DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, - char *name, - char *display_name, - int display_len); - -uint32_t lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, - struct mslsa_sid *sid, - smb_userinfo_t *user_info); - -uint32_t lsar_lookup_names2(mlsvc_handle_t *lsa_handle, - char *name, - smb_userinfo_t *user_info); - +int lsar_query_security_desc(mlsvc_handle_t *); +DWORD lsar_query_info_policy(mlsvc_handle_t *, WORD, lsa_info_t *); +uint32_t lsar_lookup_names(mlsvc_handle_t *, char *, smb_account_t *); +uint32_t lsar_lookup_names2(mlsvc_handle_t *, char *, smb_account_t *); +uint32_t lsar_lookup_sids(mlsvc_handle_t *, struct mslsa_sid *, + smb_account_t *); +uint32_t lsar_lookup_sids2(mlsvc_handle_t *, struct mslsa_sid *, + smb_account_t *); + +int lsar_enum_accounts(mlsvc_handle_t *, DWORD *, + struct mslsa_EnumAccountBuf *); +DWORD lsar_enum_trusted_domains(mlsvc_handle_t *, DWORD *, lsa_info_t *); +int lsar_enum_privs_account(mlsvc_handle_t *, smb_account_t *); +int lsar_lookup_priv_value(mlsvc_handle_t *, char *, struct ms_luid *); +int lsar_lookup_priv_name(mlsvc_handle_t *, struct ms_luid *, char *, int); +DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *, char *, char *, int); #ifdef __cplusplus } #endif - -#endif /* _SMBSRV_LSALIB_H */ +#endif /* _LSALIB_H */ diff --git a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c index 33bc6c6311..5fc961cc98 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/lsar_lookup.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -188,24 +188,21 @@ lsar_query_info_policy(mlsvc_handle_t *lsa_handle, WORD infoClass, * NT_STATUS_NONE_MAPPED. */ uint32_t -lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, - smb_userinfo_t *user_info) +lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) { - int opnum; - int index; - uint32_t status; struct mslsa_LookupNames arg; - size_t length; - lookup_name_table_t name_table; struct mslsa_rid_entry *rid_entry; struct mslsa_domain_entry *domain_entry; + lookup_name_table_t name_table; + uint32_t status = NT_STATUS_SUCCESS; + int opnum; + size_t length; char *p; - if (lsa_handle == NULL || name == NULL || user_info == NULL) + if (lsa_handle == NULL || name == NULL || info == NULL) return (NT_STATUS_INVALID_PARAMETER); - bzero(user_info, sizeof (smb_userinfo_t)); - user_info->sid_name_use = SidTypeUnknown; + bzero(info, sizeof (smb_account_t)); opnum = LSARPC_OPNUM_LookupNames; @@ -248,34 +245,39 @@ lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, name_table.name[0].str = (unsigned char *)name; if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.status != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { ndr_rpc_status(lsa_handle, opnum, arg.status); - status = NT_SC_VALUE(arg.status); - } else if (arg.mapped_count == 0) { - user_info->sid_name_use = SidTypeInvalid; - status = NT_STATUS_NONE_MAPPED; - } else { - rid_entry = &arg.translated_sids.rids[0]; - user_info->sid_name_use = rid_entry->sid_name_use; - user_info->rid = rid_entry->rid; - user_info->name = MEM_STRDUP("ndr", name); - - if ((index = rid_entry->domain_index) == -1) { - user_info->domain_sid = 0; - user_info->domain_name = 0; - } else { - domain_entry = - &arg.domain_table->entries[index]; - user_info->domain_sid = smb_sid_dup( - (smb_sid_t *)domain_entry->domain_sid); - user_info->domain_name = MEM_STRDUP("ndr", - (const char *) - domain_entry->domain_name.str); - user_info->user_sid = smb_sid_splice( - user_info->domain_sid, user_info->rid); - } - status = NT_STATUS_SUCCESS; + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); + } + + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + rid_entry = &arg.translated_sids.rids[0]; + if (rid_entry->domain_index != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + domain_entry = &arg.domain_table->entries[0]; + + info->a_type = rid_entry->sid_name_use; + info->a_name = strdup(name); + info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + info->a_domain = strdup((const char *)domain_entry->domain_name.str); + info->a_rid = rid_entry->rid; + info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid); + + if (!smb_account_validate(info)) { + smb_account_free(info); + status = NT_STATUS_NO_MEMORY; } ndr_rpc_release(lsa_handle); @@ -293,19 +295,19 @@ lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, */ uint32_t lsar_lookup_sids(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, - smb_userinfo_t *user_info) + smb_account_t *account) { struct mslsa_LookupSids arg; struct mslsa_lup_sid_entry sid_entry; struct mslsa_name_entry *name_entry; struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; int opnum; - int index; - uint32_t status; - if (lsa_handle == NULL || sid == NULL || user_info == NULL) + if (lsa_handle == NULL || sid == NULL || account == NULL) return (NT_STATUS_INVALID_PARAMETER); + bzero(account, sizeof (smb_account_t)); opnum = LSARPC_OPNUM_LookupSids; bzero(&arg, sizeof (struct mslsa_LookupSids)); @@ -317,43 +319,38 @@ lsar_lookup_sids(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, arg.lup_sid_table.entries = &sid_entry; if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.mapped_count == 0) { - user_info->sid_name_use = SidTypeInvalid; - status = NT_STATUS_NONE_MAPPED; - } else if (arg.status != 0) { - ndr_rpc_status(lsa_handle, opnum, arg.status); - status = NT_SC_VALUE(arg.status); - } else { - name_entry = &arg.name_table.entries[0]; - user_info->sid_name_use = name_entry->sid_name_use; + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } - if (user_info->sid_name_use == SidTypeUser || - user_info->sid_name_use == SidTypeGroup || - user_info->sid_name_use == SidTypeAlias) { + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); + } - user_info->rid = - sid->SubAuthority[sid->SubAuthCount - 1]; + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } - user_info->name = MEM_STRDUP("ndr", - (const char *)name_entry->name.str); - } + name_entry = &arg.name_table.entries[0]; + if (name_entry->domain_ix != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } - if ((index = name_entry->domain_ix) == -1) { - user_info->domain_sid = 0; - user_info->domain_name = 0; - } else { - domain_entry = - &arg.domain_table->entries[index]; + domain_entry = &arg.domain_table->entries[0]; - user_info->domain_sid = smb_sid_dup( - (smb_sid_t *)domain_entry->domain_sid); + account->a_type = name_entry->sid_name_use; + account->a_name = strdup((char const *)name_entry->name.str); + account->a_sid = smb_sid_dup((smb_sid_t *)sid); + account->a_domain = strdup((char const *)domain_entry->domain_name.str); + account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); - user_info->domain_name = MEM_STRDUP("ndr", - (const char *) - domain_entry->domain_name.str); - } - status = NT_STATUS_SUCCESS; + if (!smb_account_validate(account)) { + smb_account_free(account); + status = NT_STATUS_NO_MEMORY; } ndr_rpc_release(lsa_handle); @@ -496,8 +493,7 @@ lsar_enum_trusted_domains(mlsvc_handle_t *lsa_handle, DWORD *enum_context, */ /*ARGSUSED*/ int -lsar_enum_privs_account(mlsvc_handle_t *account_handle, - smb_userinfo_t *user_info) +lsar_enum_privs_account(mlsvc_handle_t *account_handle, smb_account_t *account) { struct mslsa_EnumPrivsAccount arg; int opnum; @@ -659,21 +655,21 @@ lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name, /* * lsar_lookup_sids2 */ -DWORD +uint32_t lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, - smb_userinfo_t *user_info) + smb_account_t *account) { struct lsar_lookup_sids2 arg; struct lsar_name_entry2 *name_entry; struct mslsa_lup_sid_entry sid_entry; struct mslsa_domain_entry *domain_entry; + uint32_t status = NT_STATUS_SUCCESS; int opnum; - int index; - DWORD status; - if (lsa_handle == NULL || sid == NULL || user_info == NULL) + if (lsa_handle == NULL || sid == NULL || account == NULL) return (NT_STATUS_INVALID_PARAMETER); + bzero(account, sizeof (smb_account_t)); opnum = LSARPC_OPNUM_LookupSids2; if (ndr_rpc_server_os(lsa_handle) != NATIVE_OS_WIN2000) @@ -689,42 +685,38 @@ lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, arg.requested_count = arg.lup_sid_table.n_entry; if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.mapped_count == 0) { - user_info->sid_name_use = SidTypeInvalid; - status = NT_STATUS_NONE_MAPPED; - } else if (arg.status != 0) { - ndr_rpc_status(lsa_handle, opnum, arg.status); - status = NT_SC_VALUE(arg.status); - } else { - name_entry = &arg.name_table.entries[0]; - user_info->sid_name_use = name_entry->sid_name_use; - - if (user_info->sid_name_use == SidTypeUser || - user_info->sid_name_use == SidTypeGroup || - user_info->sid_name_use == SidTypeAlias) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } - user_info->rid = - sid->SubAuthority[sid->SubAuthCount - 1]; + if (arg.status != NT_STATUS_SUCCESS) { + ndr_rpc_status(lsa_handle, opnum, arg.status); + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); + } - user_info->name = MEM_STRDUP("ndr", - (char const *)name_entry->name.str); + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } - } + name_entry = &arg.name_table.entries[0]; + if (name_entry->domain_ix != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } - if ((index = name_entry->domain_ix) == -1) { - user_info->domain_sid = 0; - user_info->domain_name = 0; - } else { - domain_entry = &arg.domain_table->entries[index]; + domain_entry = &arg.domain_table->entries[0]; - user_info->domain_sid = smb_sid_dup( - (smb_sid_t *)domain_entry->domain_sid); + account->a_type = name_entry->sid_name_use; + account->a_name = strdup((char const *)name_entry->name.str); + account->a_sid = smb_sid_dup((smb_sid_t *)sid); + account->a_domain = strdup((char const *)domain_entry->domain_name.str); + account->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); - user_info->domain_name = MEM_STRDUP("ndr", - (char const *)domain_entry->domain_name.str); - } - status = NT_STATUS_SUCCESS; + if (!smb_account_validate(account)) { + smb_account_free(account); + status = NT_STATUS_NO_MEMORY; } ndr_rpc_release(lsa_handle); @@ -749,23 +741,20 @@ lsar_lookup_sids2(mlsvc_handle_t *lsa_handle, struct mslsa_sid *sid, * It should be okay to lookup DOMAIN\Administrator in this function. */ uint32_t -lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name, - smb_userinfo_t *user_info) +lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) { - int opnum; - int index; struct lsar_LookupNames2 arg; - size_t length; - lookup_name_table_t name_table; struct lsar_rid_entry2 *rid_entry; struct mslsa_domain_entry *domain_entry; - uint32_t status; + lookup_name_table_t name_table; + uint32_t status = NT_STATUS_SUCCESS; + size_t length; + int opnum; - if (lsa_handle == NULL || name == NULL || user_info == NULL) + if (lsa_handle == NULL || name == NULL || info == NULL) return (NT_STATUS_INVALID_PARAMETER); - bzero(user_info, sizeof (smb_userinfo_t)); - user_info->sid_name_use = SidTypeUnknown; + bzero(info, sizeof (smb_account_t)); opnum = LSARPC_OPNUM_LookupNames2; @@ -786,39 +775,45 @@ lsar_lookup_names2(mlsvc_handle_t *lsa_handle, char *name, name_table.name[0].str = (unsigned char *)name; if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) { - status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.status != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_INVALID_PARAMETER); + } + + if (arg.status != NT_STATUS_SUCCESS) { ndr_rpc_status(lsa_handle, opnum, arg.status); - status = NT_SC_VALUE(arg.status); - } else if (arg.mapped_count == 0) { - user_info->sid_name_use = SidTypeInvalid; - status = NT_STATUS_NONE_MAPPED; - } else { - rid_entry = &arg.translated_sids.rids[0]; - user_info->sid_name_use = rid_entry->sid_name_use; - user_info->rid = rid_entry->rid; - user_info->name = MEM_STRDUP("ndr", name); - - if ((index = rid_entry->domain_index) == -1) { - user_info->domain_sid = 0; - user_info->domain_name = 0; - } else { - domain_entry = &arg.domain_table->entries[index]; - - user_info->domain_sid = smb_sid_dup( - (smb_sid_t *)domain_entry->domain_sid); - - user_info->domain_name = MEM_STRDUP("ndr", - (char const *)domain_entry->domain_name.str); - user_info->user_sid = smb_sid_splice( - user_info->domain_sid, user_info->rid); - } - status = NT_STATUS_SUCCESS; + ndr_rpc_release(lsa_handle); + return (NT_SC_VALUE(arg.status)); + } + + if (arg.mapped_count == 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + rid_entry = &arg.translated_sids.rids[0]; + if (rid_entry->domain_index != 0) { + ndr_rpc_release(lsa_handle); + return (NT_STATUS_NONE_MAPPED); + } + + domain_entry = &arg.domain_table->entries[0]; + + info->a_type = rid_entry->sid_name_use; + info->a_name = strdup(name); + info->a_domsid = smb_sid_dup((smb_sid_t *)domain_entry->domain_sid); + info->a_domain = strdup((char const *)domain_entry->domain_name.str); + info->a_rid = rid_entry->rid; + info->a_sid = smb_sid_splice(info->a_domsid, info->a_rid); + + if (!smb_account_validate(info)) { + smb_account_free(info); + status = NT_STATUS_NO_MEMORY; } ndr_rpc_release(lsa_handle); return (status); } + static void lsar_set_nt_domaininfo(smb_sid_t *sid, char *nb_domain, lsa_nt_domaininfo_t *info) diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers index 58fba14273..b9b0fc270e 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libmlsvc/common/mapfile-vers @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # @@ -27,11 +27,6 @@ SUNWprivate { global: dssetup_clear_domain_info; - lsa_enum_trusted_domains; - lsa_free_info; - lsa_query_account_domain_info; - lsa_query_dns_domain_info; - lsa_query_primary_domain_info; mlsvc_get_door_fd; mlsvc_get_num_users; mlsvc_get_user_list; diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c index dca7d17591..27eb05fce7 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_domain.c @@ -519,6 +519,8 @@ smb_domain_populate_table(char *domain, char *server) if (lsa_query_primary_domain_info(server, domain, &info) == NT_STATUS_SUCCESS) { + nt_domain_flush(NT_DOMAIN_PRIMARY); + nt_info = &info.i_domain.di_primary; smb_domain_update_tabent(NT_DOMAIN_PRIMARY, nt_info); lsa_free_info(&info); @@ -526,6 +528,8 @@ smb_domain_populate_table(char *domain, char *server) if (lsa_query_account_domain_info(server, domain, &info) == NT_STATUS_SUCCESS) { + nt_domain_flush(NT_DOMAIN_ACCOUNT); + nt_info = &info.i_domain.di_account; smb_domain_update_tabent(NT_DOMAIN_ACCOUNT, nt_info); lsa_free_info(&info); @@ -534,6 +538,9 @@ smb_domain_populate_table(char *domain, char *server) if (lsa_enum_trusted_domains(server, domain, &info) == NT_STATUS_SUCCESS) { lsa_trusted_domainlist_t *list = &info.i_domain.di_trust; + + nt_domain_flush(NT_DOMAIN_TRUSTED); + for (i = 0; i < list->t_num; i++) { nt_info = &list->t_domains[i]; smb_domain_update_tabent(NT_DOMAIN_TRUSTED, nt_info); @@ -549,7 +556,7 @@ static void smb_domain_update_tabent(int domain_type, lsa_nt_domaininfo_t *info) { nt_domain_t *entry; - nt_domain_flush(domain_type); + entry = nt_domain_new(domain_type, info->n_domain, info->n_sid); (void) nt_domain_add(entry); } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c index 4e546749e7..0e07735203 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_lsa.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -80,7 +80,7 @@ static DWORD lsarpc_s_PrimaryDomainInfo(struct mslsa_PrimaryDomainInfo *, static DWORD lsarpc_s_AccountDomainInfo(struct mslsa_AccountDomainInfo *, ndr_xa_t *); static int lsarpc_s_UpdateDomainTable(ndr_xa_t *, - smb_userinfo_t *, struct mslsa_domain_table *, DWORD *); + smb_account_t *, struct mslsa_domain_table *, DWORD *); static ndr_stub_table_t lsarpc_stub_table[] = { { lsarpc_s_CloseHandle, LSARPC_OPNUM_CloseHandle }, @@ -680,11 +680,11 @@ lsarpc_s_LookupNames(void *arg, ndr_xa_t *mxa) { struct mslsa_LookupNames *param = arg; struct mslsa_rid_entry *rids; - smb_userinfo_t *user_info = 0; struct mslsa_domain_table *domain_table; struct mslsa_domain_entry *domain_entry; - DWORD status = NT_STATUS_SUCCESS; - char *account; + smb_account_t account; + uint32_t status; + char *accname; int rc = 0; if (param->name_table->n_entry != 1) @@ -693,24 +693,26 @@ lsarpc_s_LookupNames(void *arg, ndr_xa_t *mxa) rids = NDR_NEW(mxa, struct mslsa_rid_entry); domain_table = NDR_NEW(mxa, struct mslsa_domain_table); domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry); - user_info = mlsvc_alloc_user_info(); - if (rids == NULL || domain_table == NULL || - domain_entry == NULL || user_info == NULL) { - status = NT_STATUS_NO_MEMORY; - goto name_lookup_failed; + if (rids == NULL || domain_table == NULL || domain_entry == NULL) { + bzero(param, sizeof (struct mslsa_LookupNames)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (NDR_DRC_OK); } - account = (char *)param->name_table->names->str; - status = lsa_lookup_name(account, SidTypeUnknown, user_info); - if (status != NT_STATUS_SUCCESS) - goto name_lookup_failed; + accname = (char *)param->name_table->names->str; + status = lsa_lookup_name(accname, SidTypeUnknown, &account); + if (status != NT_STATUS_SUCCESS) { + bzero(param, sizeof (struct mslsa_LookupNames)); + param->status = NT_SC_ERROR(status); + return (NDR_DRC_OK); + } /* * Set up the rid table. */ - rids[0].sid_name_use = user_info->sid_name_use; - rids[0].rid = user_info->rid; + rids[0].sid_name_use = account.a_type; + rids[0].rid = account.a_rid; rids[0].domain_index = 0; param->translated_sids.n_entry = 1; param->translated_sids.rids = rids; @@ -722,27 +724,23 @@ lsarpc_s_LookupNames(void *arg, ndr_xa_t *mxa) domain_table->n_entry = 1; domain_table->max_n_entry = MLSVC_DOMAIN_MAX; - rc = NDR_MSTRING(mxa, user_info->domain_name, + rc = NDR_MSTRING(mxa, account.a_domain, (ndr_mstring_t *)&domain_entry->domain_name); domain_entry->domain_sid = - (struct mslsa_sid *)NDR_SIDDUP(mxa, user_info->domain_sid); + (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid); if (rc == -1 || domain_entry->domain_sid == NULL) { - status = NT_STATUS_NO_MEMORY; - goto name_lookup_failed; + smb_account_free(&account); + bzero(param, sizeof (struct mslsa_LookupNames)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (NDR_DRC_OK); } param->domain_table = domain_table; param->mapped_count = 1; - param->status = 0; - - mlsvc_free_user_info(user_info); - return (NDR_DRC_OK); + param->status = NT_STATUS_SUCCESS; -name_lookup_failed: - mlsvc_free_user_info(user_info); - bzero(param, sizeof (struct mslsa_LookupNames)); - param->status = NT_SC_ERROR(status); + smb_account_free(&account); return (NDR_DRC_OK); } @@ -767,22 +765,19 @@ lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa) struct mslsa_domain_entry *domain_entry; struct mslsa_name_entry *names; struct mslsa_name_entry *name; - smb_userinfo_t *user_info; + smb_account_t account; smb_sid_t *sid; DWORD n_entry; int result; int i; - user_info = mlsvc_alloc_user_info(); - n_entry = param->lup_sid_table.n_entry; names = NDR_NEWN(mxa, struct mslsa_name_entry, n_entry); domain_table = NDR_NEW(mxa, struct mslsa_domain_table); domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry, MLSVC_DOMAIN_MAX); - if (names == NULL || domain_table == NULL || - domain_entry == NULL || user_info == NULL) { + if (names == NULL || domain_table == NULL || domain_entry == NULL) { bzero(param, sizeof (struct mslsa_LookupSids)); param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); return (NDR_DRC_OK); @@ -797,18 +792,18 @@ lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa) bzero(&names[i], sizeof (struct mslsa_name_entry)); sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid; - result = lsa_lookup_sid(sid, user_info); + result = lsa_lookup_sid(sid, &account); if (result != NT_STATUS_SUCCESS) goto lookup_sid_failed; - if (NDR_MSTRING(mxa, user_info->name, + if (NDR_MSTRING(mxa, account.a_name, (ndr_mstring_t *)&name->name) == -1) { result = NT_STATUS_NO_MEMORY; goto lookup_sid_failed; } - name->sid_name_use = user_info->sid_name_use; + name->sid_name_use = account.a_type; - result = lsarpc_s_UpdateDomainTable(mxa, user_info, + result = lsarpc_s_UpdateDomainTable(mxa, &account, domain_table, &name->domain_ix); if (result == -1) { @@ -816,7 +811,7 @@ lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa) goto lookup_sid_failed; } - mlsvc_release_user_info(user_info); + smb_account_free(&account); } param->domain_table = domain_table; @@ -825,7 +820,6 @@ lsarpc_s_LookupSids(void *arg, ndr_xa_t *mxa) param->mapped_count = n_entry; param->status = 0; - mlsvc_free_user_info(user_info); return (NDR_DRC_OK); lookup_sid_failed: @@ -835,7 +829,7 @@ lookup_sid_failed: param->mapped_count = 0; param->status = NT_SC_ERROR(result); - mlsvc_free_user_info(user_info); + smb_account_free(&account); return (NDR_DRC_OK); } @@ -850,7 +844,7 @@ lookup_sid_failed: */ static int lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa, - smb_userinfo_t *user_info, struct mslsa_domain_table *domain_table, + smb_account_t *account, struct mslsa_domain_table *domain_table, DWORD *domain_idx) { struct mslsa_domain_entry *dentry; @@ -858,8 +852,8 @@ lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa, DWORD i; int rc; - if (user_info->sid_name_use == SidTypeUnknown || - user_info->sid_name_use == SidTypeInvalid) { + if (account->a_type == SidTypeUnknown || + account->a_type == SidTypeInvalid) { /* * These types don't need to reference an entry in the * domain table. So return -1. @@ -876,7 +870,7 @@ lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa, for (i = 0; i < n_entry; ++i) { if (smb_sid_cmp((smb_sid_t *)dentry[i].domain_sid, - user_info->domain_sid)) { + account->a_domsid)) { *domain_idx = i; return (0); } @@ -885,10 +879,10 @@ lsarpc_s_UpdateDomainTable(ndr_xa_t *mxa, if (i == MLSVC_DOMAIN_MAX) return (-1); - rc = NDR_MSTRING(mxa, user_info->domain_name, + rc = NDR_MSTRING(mxa, account->a_domain, (ndr_mstring_t *)&dentry[i].domain_name); dentry[i].domain_sid = - (struct mslsa_sid *)NDR_SIDDUP(mxa, user_info->domain_sid); + (struct mslsa_sid *)NDR_SIDDUP(mxa, account->a_domsid); if (rc == -1 || dentry[i].domain_sid == NULL) return (-1); @@ -912,22 +906,19 @@ lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa) struct lsar_name_entry2 *name; struct mslsa_domain_table *domain_table; struct mslsa_domain_entry *domain_entry; - smb_userinfo_t *user_info; + smb_account_t account; smb_sid_t *sid; DWORD n_entry; int result; int i; - user_info = mlsvc_alloc_user_info(); - n_entry = param->lup_sid_table.n_entry; names = NDR_NEWN(mxa, struct lsar_name_entry2, n_entry); domain_table = NDR_NEW(mxa, struct mslsa_domain_table); domain_entry = NDR_NEWN(mxa, struct mslsa_domain_entry, MLSVC_DOMAIN_MAX); - if (names == NULL || domain_table == NULL || - domain_entry == NULL || user_info == NULL) { + if (names == NULL || domain_table == NULL || domain_entry == NULL) { bzero(param, sizeof (struct lsar_lookup_sids2)); param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); return (NDR_DRC_OK); @@ -942,18 +933,18 @@ lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa) bzero(name, sizeof (struct lsar_name_entry2)); sid = (smb_sid_t *)param->lup_sid_table.entries[i].psid; - result = lsa_lookup_sid(sid, user_info); + result = lsa_lookup_sid(sid, &account); if (result != NT_STATUS_SUCCESS) goto lookup_sid_failed; - if (NDR_MSTRING(mxa, user_info->name, + if (NDR_MSTRING(mxa, account.a_name, (ndr_mstring_t *)&name->name) == -1) { result = NT_STATUS_NO_MEMORY; goto lookup_sid_failed; } - name->sid_name_use = user_info->sid_name_use; + name->sid_name_use = account.a_type; - result = lsarpc_s_UpdateDomainTable(mxa, user_info, + result = lsarpc_s_UpdateDomainTable(mxa, &account, domain_table, &name->domain_ix); if (result == -1) { @@ -961,7 +952,7 @@ lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa) goto lookup_sid_failed; } - mlsvc_release_user_info(user_info); + smb_account_free(&account); } param->domain_table = domain_table; @@ -970,7 +961,6 @@ lsarpc_s_LookupSids2(void *arg, ndr_xa_t *mxa) param->mapped_count = n_entry; param->status = 0; - mlsvc_free_user_info(user_info); return (NDR_DRC_OK); lookup_sid_failed: @@ -980,7 +970,7 @@ lookup_sid_failed: param->mapped_count = 0; param->status = NT_SC_ERROR(result); - mlsvc_free_user_info(user_info); + smb_account_free(&account); return (NDR_DRC_OK); } @@ -995,11 +985,11 @@ lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa) { struct lsar_LookupNames2 *param = arg; struct lsar_rid_entry2 *rids; - smb_userinfo_t *user_info = 0; struct mslsa_domain_table *domain_table; struct mslsa_domain_entry *domain_entry; - char *account; - DWORD status = NT_STATUS_SUCCESS; + smb_account_t account; + uint32_t status; + char *accname; int rc = 0; if (param->name_table->n_entry != 1) @@ -1008,25 +998,27 @@ lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa) rids = NDR_NEW(mxa, struct lsar_rid_entry2); domain_table = NDR_NEW(mxa, struct mslsa_domain_table); domain_entry = NDR_NEW(mxa, struct mslsa_domain_entry); - user_info = mlsvc_alloc_user_info(); - if (rids == 0 || domain_table == 0 || - domain_entry == 0 || user_info == 0) { - status = NT_STATUS_NO_MEMORY; - goto name_lookup2_failed; + if (rids == NULL || domain_table == NULL || domain_entry == NULL) { + bzero(param, sizeof (struct lsar_LookupNames2)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (NDR_DRC_OK); } - account = (char *)param->name_table->names->str; - status = lsa_lookup_name(account, SidTypeUnknown, user_info); - if (status != NT_STATUS_SUCCESS) - goto name_lookup2_failed; + accname = (char *)param->name_table->names->str; + status = lsa_lookup_name(accname, SidTypeUnknown, &account); + if (status != NT_STATUS_SUCCESS) { + bzero(param, sizeof (struct lsar_LookupNames2)); + param->status = NT_SC_ERROR(status); + return (NDR_DRC_OK); + } /* * Set up the rid table. */ bzero(rids, sizeof (struct lsar_rid_entry2)); - rids[0].sid_name_use = user_info->sid_name_use; - rids[0].rid = user_info->rid; + rids[0].sid_name_use = account.a_type; + rids[0].rid = account.a_rid; rids[0].domain_index = 0; param->translated_sids.n_entry = 1; param->translated_sids.rids = rids; @@ -1038,28 +1030,24 @@ lsarpc_s_LookupNames2(void *arg, ndr_xa_t *mxa) domain_table->n_entry = 1; domain_table->max_n_entry = MLSVC_DOMAIN_MAX; - rc = NDR_MSTRING(mxa, user_info->domain_name, + rc = NDR_MSTRING(mxa, account.a_domain, (ndr_mstring_t *)&domain_entry->domain_name); domain_entry->domain_sid = - (struct mslsa_sid *)NDR_SIDDUP(mxa, user_info->domain_sid); + (struct mslsa_sid *)NDR_SIDDUP(mxa, account.a_domsid); if (rc == -1 || domain_entry->domain_sid == NULL) { - status = NT_STATUS_NO_MEMORY; - goto name_lookup2_failed; + smb_account_free(&account); + bzero(param, sizeof (struct lsar_LookupNames2)); + param->status = NT_SC_ERROR(NT_STATUS_NO_MEMORY); + return (NDR_DRC_OK); } param->domain_table = domain_table; param->mapped_count = 1; - param->status = 0; - - mlsvc_free_user_info(user_info); - return (NDR_DRC_OK); + param->status = NT_STATUS_SUCCESS; -name_lookup2_failed: - mlsvc_free_user_info(user_info); - bzero(param, sizeof (struct lsar_LookupNames2)); - param->status = NT_SC_ERROR(status); + smb_account_free(&account); return (NDR_DRC_OK); } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c index 319cd23050..339c56805f 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_sam.c @@ -31,8 +31,6 @@ #include <unistd.h> #include <netdb.h> #include <assert.h> -#include <pwd.h> -#include <grp.h> #include <smbsrv/libsmb.h> #include <smbsrv/libmlrpc.h> @@ -270,20 +268,19 @@ samr_s_LookupDomain(void *arg, ndr_xa_t *mxa) (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN); if (smb_ishostname(domain_name)) { - sid = smb_sid_dup(nt_domain_local_sid()); - } else if (strcasecmp(resource_domain, domain_name) == 0) { + sid = nt_domain_local_sid(); + } else if (utf8_strcasecmp(resource_domain, domain_name) == 0) { /* * We should not be asked to provide * the domain SID for the primary domain. */ sid = NULL; } else { - sid = smb_wka_lookup_name(domain_name, 0); + sid = smb_wka_get_sid(domain_name); } if (sid) { param->sid = (struct samr_sid *)NDR_SIDDUP(mxa, sid); - free(sid); if (param->sid == NULL) { bzero(param, sizeof (struct samr_LookupDomain)); @@ -465,15 +462,15 @@ samr_s_QueryDomainInfo(void *arg, ndr_xa_t *mxa) case NT_DOMAIN_BUILTIN: domain = "BUILTIN"; user_cnt = 0; - rc = smb_lgrp_numbydomain(SMB_LGRP_BUILTIN, &alias_cnt); + alias_cnt = smb_sam_grp_cnt(data->kd_type); break; case NT_DOMAIN_LOCAL: rc = smb_getnetbiosname(hostname, sizeof (hostname)); if (rc == 0) { domain = hostname; - user_cnt = smb_pwd_num(); - rc = smb_lgrp_numbydomain(SMB_LGRP_LOCAL, &alias_cnt); + user_cnt = smb_sam_usr_cnt(); + alias_cnt = smb_sam_grp_cnt(data->kd_type); } break; @@ -535,11 +532,11 @@ samr_s_QueryDomainInfo(void *arg, ndr_xa_t *mxa) } /* - * samr_s_LookupNames + * Looks up the given name in the specified domain which could + * be either the built-in or local domain. * - * The definition for this interface is obviously wrong but I can't - * seem to get it to work the way I think it should. It should - * support multiple name lookup but I can only get one working for now. + * CAVEAT: this function should be able to handle a list of + * names but currently it can only handle one name at a time. */ static int samr_s_LookupNames(void *arg, ndr_xa_t *mxa) @@ -548,12 +545,9 @@ samr_s_LookupNames(void *arg, ndr_xa_t *mxa) ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; ndr_handle_t *hd; samr_keydata_t *data; + smb_account_t account; smb_wka_t *wka; - smb_group_t grp; - smb_passwd_t smbpw; - smb_sid_t *sid; uint32_t status = NT_STATUS_SUCCESS; - int rc; if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) status = NT_STATUS_INVALID_HANDLE; @@ -582,7 +576,7 @@ samr_s_LookupNames(void *arg, ndr_xa_t *mxa) switch (data->kd_type) { case NT_DOMAIN_BUILTIN: - wka = smb_wka_lookup((char *)param->name.str); + wka = smb_wka_lookup_name((char *)param->name.str); if (wka != NULL) { param->rids.n_entry = 1; (void) smb_sid_getrid(wka->wka_binsid, @@ -595,30 +589,17 @@ samr_s_LookupNames(void *arg, ndr_xa_t *mxa) break; case NT_DOMAIN_LOCAL: - rc = smb_lgrp_getbyname((char *)param->name.str, &grp); - if (rc == SMB_LGRP_SUCCESS) { + status = smb_sam_lookup_name(NULL, (char *)param->name.str, + SidTypeUnknown, &account); + if (status == NT_STATUS_SUCCESS) { param->rids.n_entry = 1; - param->rids.rid[0] = grp.sg_rid; + param->rids.rid[0] = account.a_rid; param->rid_types.n_entry = 1; - param->rid_types.rid_type[0] = grp.sg_id.gs_type; + param->rid_types.rid_type[0] = account.a_type; param->status = NT_STATUS_SUCCESS; - smb_lgrp_free(&grp); + smb_account_free(&account); return (NDR_DRC_OK); } - - if (smb_pwd_getpwnam((const char *)param->name.str, &smbpw) - != NULL) { - if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, - &sid) == IDMAP_SUCCESS) { - param->rids.n_entry = 1; - (void) smb_sid_getrid(sid, ¶m->rids.rid[0]); - param->rid_types.n_entry = 1; - param->rid_types.rid_type[0] = SidTypeUser; - param->status = NT_STATUS_SUCCESS; - free(sid); - return (NDR_DRC_OK); - } - } break; default: @@ -728,7 +709,6 @@ samr_s_QueryUserGroups(void *arg, ndr_xa_t *mxa) ndr_hdid_t *id = (ndr_hdid_t *)¶m->user_handle; ndr_handle_t *hd; samr_keydata_t *data; - smb_wka_t *wka; smb_sid_t *user_sid = NULL; smb_sid_t *dom_sid; smb_group_t grp; @@ -745,12 +725,10 @@ samr_s_QueryUserGroups(void *arg, ndr_xa_t *mxa) data = (samr_keydata_t *)hd->nh_data; switch (data->kd_type) { case NT_DOMAIN_BUILTIN: - wka = smb_wka_lookup("builtin"); - if (wka == NULL) { + if ((dom_sid = smb_wka_get_sid("builtin")) == NULL) { status = NT_STATUS_INTERNAL_ERROR; goto query_error; } - dom_sid = wka->wka_binsid; break; case NT_DOMAIN_LOCAL: dom_sid = nt_domain_local_sid(); @@ -973,8 +951,9 @@ samr_s_QueryDispInfo(void *arg, ndr_xa_t *mxa) smb_pwditer_t pwi; smb_luser_t *uinfo; int num_users; - int start_idx, idx; - int ret_cnt; + int start_idx; + int max_retcnt, retcnt; + int skip; if ((hd = samr_hdlookup(mxa, id, SAMR_KEY_DOMAIN)) == NULL) { status = NT_STATUS_INVALID_HANDLE; @@ -998,34 +977,37 @@ samr_s_QueryDispInfo(void *arg, ndr_xa_t *mxa) goto no_info; case NT_DOMAIN_LOCAL: - num_users = smb_pwd_num(); + num_users = smb_sam_usr_cnt(); start_idx = param->start_idx; if ((num_users == 0) || (start_idx >= num_users)) goto no_info; - ret_cnt = num_users - start_idx; - if (ret_cnt > param->max_entries) - ret_cnt = param->max_entries; + max_retcnt = num_users - start_idx; + if (max_retcnt > param->max_entries) + max_retcnt = param->max_entries; param->users.acct = NDR_MALLOC(mxa, - ret_cnt * sizeof (struct user_acct_info)); + max_retcnt * sizeof (struct user_acct_info)); user = param->users.acct; if (user == NULL) { status = NT_STATUS_NO_MEMORY; goto error; } - bzero(user, ret_cnt * sizeof (struct user_acct_info)); + bzero(user, max_retcnt * sizeof (struct user_acct_info)); - ret_cnt = idx = 0; if (smb_pwd_iteropen(&pwi) != SMB_PWE_SUCCESS) goto no_info; + skip = retcnt = 0; while ((uinfo = smb_pwd_iterate(&pwi)) != NULL) { - if (idx++ < start_idx) + if (skip++ < start_idx) continue; + if (retcnt++ >= max_retcnt) + break; + assert(uinfo->su_name != NULL); - user->index = start_idx + ret_cnt + 1; + user->index = start_idx + retcnt; user->rid = uinfo->su_rid; user->ctrl = ACF_NORMUSER | ACF_PWDNOEXP; if (uinfo->su_ctrl & SMB_PWF_DISABLE) @@ -1041,17 +1023,21 @@ samr_s_QueryDispInfo(void *arg, ndr_xa_t *mxa) (void) NDR_MSTRING(mxa, uinfo->su_desc, (ndr_mstring_t *)&user->desc); user++; - ret_cnt++; } smb_pwd_iterclose(&pwi); + if (retcnt >= max_retcnt) { + retcnt = max_retcnt; + param->status = status; + } else { + param->status = ERROR_MORE_ENTRIES; + } + param->users.total_size = num_users; - param->users.returned_size = ret_cnt; + param->users.returned_size = retcnt; param->users.switch_value = param->level; - param->users.count = ret_cnt; + param->users.count = retcnt; - if (ret_cnt < (num_users - start_idx)) - param->status = ERROR_MORE_ENTRIES; break; default: @@ -1059,7 +1045,6 @@ samr_s_QueryDispInfo(void *arg, ndr_xa_t *mxa) goto error; } - param->status = status; return (NDR_DRC_OK); no_info: @@ -1422,7 +1407,7 @@ samr_s_EnumDomainAliases(void *arg, ndr_xa_t *mxa) data = (samr_keydata_t *)hd->nh_data; - (void) smb_lgrp_numbydomain((smb_gdomain_t)data->kd_type, &cnt); + cnt = smb_sam_grp_cnt(data->kd_type); if (cnt <= param->resume_handle) { param->aliases = (struct aliases_info *)NDR_MALLOC(mxa, sizeof (struct aliases_info)); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c index 7a130f78da..7af1eecc1b 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/mlsvc_util.c @@ -62,22 +62,19 @@ extern int mlsvc_user_getauth(char *, char *, smb_auth_info_t *); * call free when it is no longer required. */ uint32_t -mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type) +mlsvc_lookup_name(char *name, smb_sid_t **sid, uint16_t *sid_type) { - smb_userinfo_t *ainfo; + smb_account_t account; uint32_t status; - if ((ainfo = mlsvc_alloc_user_info()) == NULL) - return (NT_STATUS_NO_MEMORY); - - status = lsa_lookup_name(account, *sid_type, ainfo); + status = lsa_lookup_name(name, *sid_type, &account); if (status == NT_STATUS_SUCCESS) { - *sid = ainfo->user_sid; - ainfo->user_sid = NULL; - *sid_type = ainfo->sid_name_use; + *sid = account.a_sid; + account.a_sid = NULL; + *sid_type = account.a_type; + smb_account_free(&account); } - mlsvc_free_user_info(ainfo); return (status); } @@ -92,134 +89,24 @@ mlsvc_lookup_name(char *account, smb_sid_t **sid, uint16_t *sid_type) uint32_t mlsvc_lookup_sid(smb_sid_t *sid, char **name) { - smb_userinfo_t *ainfo; + smb_account_t ainfo; uint32_t status; int namelen; - if ((ainfo = mlsvc_alloc_user_info()) == NULL) - return (NT_STATUS_NO_MEMORY); + if ((status = lsa_lookup_sid(sid, &ainfo)) == NT_STATUS_SUCCESS) { + namelen = strlen(ainfo.a_domain) + strlen(ainfo.a_name) + 2; + if ((*name = malloc(namelen)) != NULL) + (void) snprintf(*name, namelen, "%s\\%s", + ainfo.a_domain, ainfo.a_name); + else + status = NT_STATUS_NO_MEMORY; - status = lsa_lookup_sid(sid, ainfo); - if (status == NT_STATUS_SUCCESS) { - namelen = strlen(ainfo->domain_name) + strlen(ainfo->name) + 2; - if ((*name = malloc(namelen)) == NULL) { - mlsvc_free_user_info(ainfo); - return (NT_STATUS_NO_MEMORY); - } - (void) snprintf(*name, namelen, "%s\\%s", - ainfo->domain_name, ainfo->name); + smb_account_free(&ainfo); } - mlsvc_free_user_info(ainfo); return (status); } -/* - * mlsvc_alloc_user_info - * - * Allocate a user_info structure and set the contents to zero. A - * pointer to the user_info structure is returned. - */ -smb_userinfo_t * -mlsvc_alloc_user_info(void) -{ - smb_userinfo_t *user_info; - - user_info = (smb_userinfo_t *)malloc(sizeof (smb_userinfo_t)); - if (user_info == NULL) - return (NULL); - - bzero(user_info, sizeof (smb_userinfo_t)); - return (user_info); -} - -/* - * mlsvc_free_user_info - * - * Free a user_info structure. This function ensures that the contents - * of the user_info are freed as well as the user_info itself. - */ -void -mlsvc_free_user_info(smb_userinfo_t *user_info) -{ - if (user_info) { - mlsvc_release_user_info(user_info); - free(user_info); - } -} - -/* - * mlsvc_release_user_info - * - * Release the contents of a user_info structure and zero out the - * elements but do not free the user_info structure itself. This - * function cleans out the structure so that it can be reused without - * worrying about stale contents. - */ -void -mlsvc_release_user_info(smb_userinfo_t *user_info) -{ - int i; - - if (user_info == NULL) - return; - - free(user_info->name); - free(user_info->domain_sid); - free(user_info->domain_name); - free(user_info->groups); - - if (user_info->n_other_grps) { - for (i = 0; i < user_info->n_other_grps; i++) - free(user_info->other_grps[i].sid); - - free(user_info->other_grps); - } - - free(user_info->session_key); - free(user_info->user_sid); - free(user_info->pgrp_sid); - bzero(user_info, sizeof (smb_userinfo_t)); -} - -/* - * mlsvc_setadmin_user_info - * - * Determines if the given user is the domain Administrator or a - * member of Domain Admins or Administrators group and set the - * user_info->flags accordingly. - */ -void -mlsvc_setadmin_user_info(smb_userinfo_t *user_info) -{ - nt_domain_t *domain; - smb_group_t grp; - int rc, i; - - if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) - return; - - if (!smb_sid_cmp((smb_sid_t *)user_info->domain_sid, domain->sid)) - return; - - if (user_info->rid == DOMAIN_USER_RID_ADMIN) - user_info->flags |= SMB_UINFO_FLAG_DADMIN; - else if (user_info->primary_group_rid == DOMAIN_GROUP_RID_ADMINS) - user_info->flags |= SMB_UINFO_FLAG_DADMIN; - else { - for (i = 0; i < user_info->n_groups; i++) - if (user_info->groups[i].rid == DOMAIN_GROUP_RID_ADMINS) - user_info->flags |= SMB_UINFO_FLAG_DADMIN; - } - - rc = smb_lgrp_getbyname("Administrators", &grp); - if (rc == SMB_LGRP_SUCCESS) { - if (smb_lgrp_is_member(&grp, user_info->user_sid)) - user_info->flags |= SMB_UINFO_FLAG_LADMIN; - smb_lgrp_free(&grp); - } -} - DWORD mlsvc_netlogon(char *server, char *domain) { diff --git a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c index 6169714d69..57d15ab693 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/netr_logon.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -47,9 +47,9 @@ #include <smbsrv/smb_token.h> #include <mlsvc.h> -static DWORD netlogon_logon_private(netr_client_t *, smb_userinfo_t *); -static DWORD netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *, - netr_client_t *, smb_userinfo_t *); +static uint32_t netlogon_logon_private(netr_client_t *, smb_token_t *); +static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *, + netr_client_t *, smb_token_t *); static void netr_invalidate_chain(void); static void netr_interactive_samlogon(netr_info_t *, netr_client_t *, struct netr_logon_info1 *); @@ -57,6 +57,11 @@ static void netr_network_samlogon(ndr_heap_t *, netr_info_t *, netr_client_t *, struct netr_logon_info2 *); static void netr_setup_identity(ndr_heap_t *, netr_client_t *, netr_logon_id_t *); +static boolean_t netr_isadmin(struct netr_validation_info3 *); +static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *, + smb_ids_t *); +static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *, + smb_token_t *); /* * Shared with netr_auth.c @@ -80,27 +85,27 @@ static mutex_t netlogon_logon_mutex; * NT status will be returned, in which case the token contents will * be invalid. */ -DWORD -netlogon_logon(netr_client_t *clnt, smb_userinfo_t *user_info) +uint32_t +netlogon_logon(netr_client_t *clnt, smb_token_t *token) { - DWORD status; + uint32_t status; (void) mutex_lock(&netlogon_logon_mutex); - status = netlogon_logon_private(clnt, user_info); + status = netlogon_logon_private(clnt, token); (void) mutex_unlock(&netlogon_logon_mutex); return (status); } -static DWORD -netlogon_logon_private(netr_client_t *clnt, smb_userinfo_t *user_info) +static uint32_t +netlogon_logon_private(netr_client_t *clnt, smb_token_t *token) { char resource_domain[SMB_PI_MAX_DOMAIN]; char server[NETBIOS_NAME_SZ * 2]; mlsvc_handle_t netr_handle; smb_domain_t di; - DWORD status; + uint32_t status; int retries = 0, server_changed = 0; (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN); @@ -144,7 +149,7 @@ netlogon_logon_private(netr_client_t *clnt, smb_userinfo_t *user_info) } status = netr_server_samlogon(&netr_handle, - &netr_global_info, di.d_dc, clnt, user_info); + &netr_global_info, di.d_dc, clnt, token); (void) netr_close(&netr_handle); } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3); @@ -155,75 +160,51 @@ netlogon_logon_private(netr_client_t *clnt, smb_userinfo_t *user_info) return (status); } -static DWORD -netr_setup_userinfo(struct netr_validation_info3 *info3, - smb_userinfo_t *user_info, netr_client_t *clnt, netr_info_t *netr_info) +static uint32_t +netr_setup_token(struct netr_validation_info3 *info3, netr_client_t *clnt, + netr_info_t *netr_info, smb_token_t *token) { - smb_sid_attrs_t *other_grps; char *username, *domain; - int i, nbytes; unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ]; + smb_sid_t *domsid; + uint32_t status; + char nbdomain[NETBIOS_NAME_SZ]; - user_info->sid_name_use = SidTypeUser; - user_info->rid = info3->UserId; - user_info->primary_group_rid = info3->PrimaryGroupId; - user_info->domain_sid = smb_sid_dup((smb_sid_t *)info3->LogonDomainId); + domsid = (smb_sid_t *)info3->LogonDomainId; - if (user_info->domain_sid == NULL) + token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId); + if (token->tkn_user.i_sid == NULL) return (NT_STATUS_NO_MEMORY); - user_info->user_sid = smb_sid_splice(user_info->domain_sid, - user_info->rid); - if (user_info->user_sid == NULL) - return (NT_STATUS_NO_MEMORY); - - user_info->pgrp_sid = smb_sid_splice(user_info->domain_sid, - user_info->primary_group_rid); - if (user_info->pgrp_sid == NULL) + token->tkn_primary_grp.i_sid = smb_sid_splice(domsid, + info3->PrimaryGroupId); + if (token->tkn_primary_grp.i_sid == NULL) return (NT_STATUS_NO_MEMORY); username = (info3->EffectiveName.str) - ? (char *)info3->EffectiveName.str : clnt->username; - domain = (info3->LogonDomainName.str) - ? (char *)info3->LogonDomainName.str : clnt->domain; + ? (char *)info3->EffectiveName.str : clnt->real_username; + + if (info3->LogonDomainName.str) { + domain = (char *)info3->LogonDomainName.str; + } else if (*clnt->real_domain != '\0') { + domain = clnt->real_domain; + } else { + (void) smb_getdomainname(nbdomain, sizeof (nbdomain)); + domain = nbdomain; + } if (username) - user_info->name = strdup(username); + token->tkn_account_name = strdup(username); if (domain) - user_info->domain_name = strdup(domain); + token->tkn_domain_name = strdup(domain); - if (user_info->name == NULL || user_info->domain_name == NULL) + if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL) return (NT_STATUS_NO_MEMORY); - nbytes = info3->GroupCount * sizeof (smb_rid_attrs_t); - if (nbytes) { - if ((user_info->groups = malloc(nbytes)) != NULL) { - user_info->n_groups = info3->GroupCount; - (void) memcpy(user_info->groups, - info3->GroupIds, nbytes); - } else { - return (NT_STATUS_NO_MEMORY); - } - } - nbytes = info3->SidCount * sizeof (smb_sid_attrs_t); - if (nbytes) { - if ((other_grps = malloc(nbytes)) != NULL) { - user_info->other_grps = other_grps; - for (i = 0; i < info3->SidCount; i++) { - other_grps[i].attrs = - info3->ExtraSids[i].attributes; - - other_grps[i].sid = smb_sid_dup( - (smb_sid_t *)info3->ExtraSids[i].sid); - - if (other_grps[i].sid == NULL) - break; - } - user_info->n_other_grps = i; - } else { - return (NT_STATUS_NO_MEMORY); - } - } + status = netr_setup_token_wingrps(info3, token); + if (status != NT_STATUS_SUCCESS) + return (status); + /* * The UserSessionKey in NetrSamLogon RPC is obfuscated using the * session key obtained in the NETLOGON credential chain. @@ -232,15 +213,15 @@ netr_setup_userinfo(struct netr_validation_info3 *info3, * exclusively ored with the 16 byte UserSessionKey to recover * the the clear form. */ - if ((user_info->session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) + if ((token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) return (NT_STATUS_NO_MEMORY); bzero(rc4key, SMBAUTH_SESSION_KEY_SZ); bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len); - bcopy(info3->UserSessionKey.data, user_info->session_key, + bcopy(info3->UserSessionKey.data, token->tkn_session_key, SMBAUTH_SESSION_KEY_SZ); - rand_hash((unsigned char *)user_info->session_key, + rand_hash((unsigned char *)token->tkn_session_key, SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ); - mlsvc_setadmin_user_info(user_info); + return (NT_STATUS_SUCCESS); } @@ -268,9 +249,9 @@ netr_setup_userinfo(struct netr_validation_info3 *info3, * NT_STATUS_PASSWORD_EXPIRED * NT_STATUS_ACCOUNT_DISABLED */ -DWORD +uint32_t netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, - char *server, netr_client_t *clnt, smb_userinfo_t *user_info) + char *server, netr_client_t *clnt, smb_token_t *token) { struct netr_SamLogon arg; struct netr_authenticator auth; @@ -281,7 +262,7 @@ netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, ndr_heap_t *heap; int opnum; int rc, len; - DWORD status; + uint32_t status; bzero(&arg, sizeof (struct netr_SamLogon)); opnum = NETR_OPNUM_SamLogon; @@ -359,7 +340,7 @@ netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info, } info3 = arg.ru.info3; - status = netr_setup_userinfo(info3, user_info, clnt, netr_info); + status = netr_setup_token(info3, clnt, netr_info, token); } ndr_rpc_release(netr_handle); @@ -476,7 +457,7 @@ netr_setup_authenticator(netr_info_t *netr_info, * * Generate the new seed for the credential chain. The new seed is * formed by adding (timestamp + 1) to the current client credential. - * The only quirk is the DWORD style addition. + * The only quirk is the uint32_t style addition. * * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a * NULL pointer. The Authenticator field of the SamLogon response packet @@ -487,12 +468,12 @@ netr_setup_authenticator(netr_info_t *netr_info, * Returns NT_STATUS_SUCCESS if the server returned a valid credential. * Otherwise we retirm NT_STATUS_UNSUCCESSFUL. */ -DWORD +uint32_t netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth) { netr_cred_t cred; - DWORD result = NT_STATUS_SUCCESS; - DWORD *dwp; + uint32_t result = NT_STATUS_SUCCESS; + uint32_t *dwp; ++netr_info->timestamp; @@ -523,7 +504,7 @@ netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth) * Otherwise generate the next step in the chain. */ /*LINTED E_BAD_PTR_CAST_ALIGN*/ - dwp = (DWORD *)&netr_info->client_credential; + dwp = (uint32_t *)&netr_info->client_credential; dwp[0] += netr_info->timestamp; netr_info->flags |= NETR_FLG_VALID; @@ -589,3 +570,127 @@ netr_setup_identity(ndr_heap_t *heap, netr_client_t *clnt, ndr_heap_mkvcs(heap, clnt->workstation, (ndr_vcstr_t *)&identity->workstation); } + +/* + * Sets up domain, local and well-known group membership for the given + * token. Two assumptions have been made here: + * + * a) token already contains a valid user SID so that group + * memberships can be established + * + * b) token belongs to a domain user + */ +static uint32_t +netr_setup_token_wingrps(struct netr_validation_info3 *info3, + smb_token_t *token) +{ + smb_ids_t tkn_grps; + uint32_t status; + + tkn_grps.i_cnt = 0; + tkn_grps.i_ids = NULL; + + status = netr_setup_domain_groups(info3, &tkn_grps); + if (status != NT_STATUS_SUCCESS) { + smb_ids_free(&tkn_grps); + return (status); + } + + status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps); + if (status != NT_STATUS_SUCCESS) { + smb_ids_free(&tkn_grps); + return (status); + } + + status = smb_wka_token_groups(netr_isadmin(info3), &tkn_grps); + if (status == NT_STATUS_SUCCESS) + token->tkn_win_grps = tkn_grps; + else + smb_ids_free(&tkn_grps); + + return (status); +} + +/* + * Converts groups information in the returned structure by domain controller + * (info3) to an internal representation (gids) + */ +static uint32_t +netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids) +{ + smb_sid_t *domain_sid; + smb_id_t *ids; + int i, total_cnt; + + if ((i = info3->GroupCount) == 0) + i++; + i += info3->SidCount; + + total_cnt = gids->i_cnt + i; + + gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); + if (gids->i_ids == NULL) + return (NT_STATUS_NO_MEMORY); + + domain_sid = (smb_sid_t *)info3->LogonDomainId; + + ids = gids->i_ids + gids->i_cnt; + for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) { + ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid); + if (ids->i_sid == NULL) + return (NT_STATUS_NO_MEMORY); + + ids->i_attrs = info3->GroupIds[i].attributes; + } + + if (info3->GroupCount == 0) { + /* + * if there's no global group should add the primary group. + */ + ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId); + if (ids->i_sid == NULL) + return (NT_STATUS_NO_MEMORY); + + ids->i_attrs = 0x7; + gids->i_cnt++; + ids++; + } + + /* Add the extra SIDs */ + for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) { + ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid); + if (ids->i_sid == NULL) + return (NT_STATUS_NO_MEMORY); + + ids->i_attrs = info3->ExtraSids[i].attributes; + } + + return (NT_STATUS_SUCCESS); +} + +/* + * Determines if the given user is the domain Administrator or a + * member of Domain Admins + */ +static boolean_t +netr_isadmin(struct netr_validation_info3 *info3) +{ + nt_domain_t *domain; + int i; + + if ((domain = nt_domain_lookupbytype(NT_DOMAIN_PRIMARY)) == NULL) + return (B_FALSE); + + if (!smb_sid_cmp((smb_sid_t *)info3->LogonDomainId, domain->sid)) + return (B_FALSE); + + if ((info3->UserId == DOMAIN_USER_RID_ADMIN) || + (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS)) + return (B_TRUE); + + for (i = 0; i < info3->GroupCount; i++) + if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS) + return (B_TRUE); + + return (B_FALSE); +} diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c index 3d76c7eddc..f33ac767ce 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,8 +28,6 @@ * functions. */ -#include <unistd.h> -#include <netdb.h> #include <alloca.h> #include <smbsrv/libsmb.h> @@ -48,9 +46,7 @@ #define SAM_KEYLEN 16 extern DWORD samr_set_user_info(mlsvc_handle_t *, smb_auth_info_t *); - -static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *, - smb_userinfo_t *); +static struct samr_sid *sam_get_domain_sid(mlsvc_handle_t *, char *, char *); /* * sam_create_trust_account @@ -113,7 +109,6 @@ sam_create_account(char *server, char *domain_name, char *account_name, mlsvc_handle_t samr_handle; mlsvc_handle_t domain_handle; mlsvc_handle_t user_handle; - smb_userinfo_t *user_info; union samr_user_info sui; struct samr_sid *sid; DWORD rid; @@ -121,9 +116,6 @@ sam_create_account(char *server, char *domain_name, char *account_name, int rc; char *user = smbrdr_ipc_get_user(); - if ((user_info = mlsvc_alloc_user_info()) == 0) - return (NT_STATUS_NO_MEMORY); - rc = samr_open(server, domain_name, user, SAM_CONNECT_CREATE_ACCOUNT, &samr_handle); @@ -131,11 +123,10 @@ sam_create_account(char *server, char *domain_name, char *account_name, status = NT_STATUS_OPEN_FAILED; smb_tracef("SamCreateAccount[%s\\%s]: %s", domain_name, account_name, xlate_nt_status(status)); - mlsvc_free_user_info(user_info); return (status); } - sid = sam_get_domain_sid(&samr_handle, server, domain_name, user_info); + sid = sam_get_domain_sid(&samr_handle, server, domain_name); status = samr_open_domain(&samr_handle, SAM_DOMAIN_CREATE_ACCOUNT, sid, &domain_handle); @@ -164,7 +155,6 @@ sam_create_account(char *server, char *domain_name, char *account_name, } (void) samr_close_handle(&samr_handle); - mlsvc_free_user_info(user_info); free(sid); return (status); } @@ -204,52 +194,41 @@ sam_delete_account(char *server, char *domain_name, char *account_name) mlsvc_handle_t samr_handle; mlsvc_handle_t domain_handle; mlsvc_handle_t user_handle; - smb_userinfo_t *user_info; + smb_account_t ainfo; struct samr_sid *sid; - DWORD rid; DWORD access_mask; DWORD status; int rc; char *user = smbrdr_ipc_get_user(); - if ((user_info = mlsvc_alloc_user_info()) == 0) - return (NT_STATUS_NO_MEMORY); - rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, &samr_handle); - if (rc != 0) { - mlsvc_free_user_info(user_info); + if (rc != 0) return (NT_STATUS_OPEN_FAILED); - } - sid = sam_get_domain_sid(&samr_handle, server, domain_name, user_info); + sid = sam_get_domain_sid(&samr_handle, server, domain_name); + status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid, + &domain_handle); + free(sid); + if (status != NT_STATUS_SUCCESS) { + (void) samr_close_handle(&samr_handle); + return (status); + } - status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, - sid, &domain_handle); - if (status == 0) { - mlsvc_release_user_info(user_info); - status = samr_lookup_domain_names(&domain_handle, - account_name, user_info); - - if (status == 0) { - rid = user_info->rid; - access_mask = STANDARD_RIGHTS_EXECUTE | DELETE; - - status = samr_open_user(&domain_handle, access_mask, - rid, &user_handle); - if (status == NT_STATUS_SUCCESS) { - if (samr_delete_user(&user_handle) != 0) - (void) samr_close_handle(&user_handle); - } + status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo); + if (status == NT_STATUS_SUCCESS) { + access_mask = STANDARD_RIGHTS_EXECUTE | DELETE; + status = samr_open_user(&domain_handle, access_mask, + ainfo.a_rid, &user_handle); + if (status == NT_STATUS_SUCCESS) { + if (samr_delete_user(&user_handle) != 0) + (void) samr_close_handle(&user_handle); } - - (void) samr_close_handle(&domain_handle); } + (void) samr_close_handle(&domain_handle); (void) samr_close_handle(&samr_handle); - mlsvc_free_user_info(user_info); - free(sid); return (status); } @@ -266,58 +245,46 @@ sam_check_user(char *server, char *domain_name, char *account_name) mlsvc_handle_t samr_handle; mlsvc_handle_t domain_handle; mlsvc_handle_t user_handle; - smb_userinfo_t *user_info; + smb_account_t ainfo; struct samr_sid *sid; - DWORD rid; DWORD access_mask; DWORD status; int rc; char *user = smbrdr_ipc_get_user(); - if ((user_info = mlsvc_alloc_user_info()) == 0) - return (NT_STATUS_NO_MEMORY); - rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, &samr_handle); - if (rc != 0) { - mlsvc_free_user_info(user_info); + if (rc != 0) return (NT_STATUS_OPEN_FAILED); - } - - sid = sam_get_domain_sid(&samr_handle, server, domain_name, user_info); + sid = sam_get_domain_sid(&samr_handle, server, domain_name); status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, sid, &domain_handle); - if (status == 0) { - mlsvc_release_user_info(user_info); - status = samr_lookup_domain_names(&domain_handle, account_name, - user_info); - - if (status == 0) { - rid = user_info->rid; - - /* - * Win2000 client uses this access mask. The - * following SAMR user specific rights bits are - * set: set password, set attributes, and get - * attributes. - */ - - access_mask = 0xb0; - - status = samr_open_user(&domain_handle, - access_mask, rid, &user_handle); - if (status == NT_STATUS_SUCCESS) - (void) samr_close_handle(&user_handle); - } + free(sid); + if (status != NT_STATUS_SUCCESS) { + (void) samr_close_handle(&samr_handle); + return (status); + } - (void) samr_close_handle(&domain_handle); + status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo); + if (status == NT_STATUS_SUCCESS) { + /* + * Win2000 client uses this access mask. The + * following SAMR user specific rights bits are + * set: set password, set attributes, and get + * attributes. + */ + + access_mask = 0xb0; + status = samr_open_user(&domain_handle, + access_mask, ainfo.a_rid, &user_handle); + if (status == NT_STATUS_SUCCESS) + (void) samr_close_handle(&user_handle); } + (void) samr_close_handle(&domain_handle); (void) samr_close_handle(&samr_handle); - mlsvc_free_user_info(user_info); - free(sid); return (status); } @@ -335,7 +302,7 @@ sam_lookup_name(char *server, char *domain_name, char *account_name, { mlsvc_handle_t samr_handle; mlsvc_handle_t domain_handle; - smb_userinfo_t *user_info; + smb_account_t ainfo; struct samr_sid *domain_sid; int rc; DWORD status; @@ -343,45 +310,34 @@ sam_lookup_name(char *server, char *domain_name, char *account_name, *rid_ret = 0; - if ((user_info = mlsvc_alloc_user_info()) == 0) - return (NT_STATUS_NO_MEMORY); - rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION, &samr_handle); - if (rc != 0) { - mlsvc_free_user_info(user_info); + if (rc != 0) return (NT_STATUS_OPEN_FAILED); - } - rc = samr_lookup_domain(&samr_handle, domain_name, user_info); - if (rc != 0) { + domain_sid = (struct samr_sid *)samr_lookup_domain(&samr_handle, + domain_name); + if (domain_sid == NULL) { (void) samr_close_handle(&samr_handle); - mlsvc_free_user_info(user_info); return (NT_STATUS_NO_SUCH_DOMAIN); } - domain_sid = (struct samr_sid *)user_info->domain_sid; - status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION, domain_sid, &domain_handle); - if (status == 0) { - mlsvc_release_user_info(user_info); - + if (status == NT_STATUS_SUCCESS) { status = samr_lookup_domain_names(&domain_handle, - account_name, user_info); - if (status == 0) - *rid_ret = user_info->rid; + account_name, &ainfo); + if (status == NT_STATUS_SUCCESS) + *rid_ret = ainfo.a_rid; (void) samr_close_handle(&domain_handle); } (void) samr_close_handle(&samr_handle); - mlsvc_free_user_info(user_info); return (status); } - /* * sam_get_local_domains * @@ -441,8 +397,7 @@ sam_oem_password(oem_password_t *oem_password, unsigned char *new_password, } static struct samr_sid * -sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name, - smb_userinfo_t *user_info) +sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name) { struct samr_sid *sid; @@ -461,11 +416,8 @@ sam_get_domain_sid(mlsvc_handle_t *samr_handle, char *server, char *domain_name, sid = (struct samr_sid *)smb_sid_dup(ntdp->sid); } } else { - if (samr_lookup_domain(samr_handle, domain_name, user_info) - != 0) - return (NULL); - - sid = (struct samr_sid *)smb_sid_dup(user_info->domain_sid); + sid = (struct samr_sid *)samr_lookup_domain(samr_handle, + domain_name); } return (sid); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h index c719a53925..4a12235b14 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samlib.h +++ b/usr/src/lib/smbsrv/libmlsvc/common/samlib.h @@ -19,12 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _SMBSRV_SAMLIB_H -#define _SMBSRV_SAMLIB_H +#ifndef _SAMLIB_H +#define _SAMLIB_H /* * Prototypes for the SAM library and RPC client side library interface. @@ -61,49 +61,26 @@ extern "C" { /* * samlib.c */ -int sam_lookup_user_info(char *server, char *domain_name, char *username, - smb_userinfo_t *user_info); - -DWORD sam_create_trust_account(char *server, char *domain, - smb_auth_info_t *auth); - -DWORD sam_create_account(char *server, char *domain_name, char *account_name, - smb_auth_info_t *auth, DWORD account_flags); - -DWORD sam_remove_trust_account(char *server, char *domain); - -DWORD sam_delete_account(char *server, char *domain_name, char *account_name); - -DWORD sam_lookup_name(char *server, char *domain_name, char *account_name, - DWORD *rid_ret); - -DWORD sam_get_local_domains(char *server, char *domain_name); -DWORD sam_check_user(char *server, char *domain_name, char *account_name); +DWORD sam_create_trust_account(char *, char *, smb_auth_info_t *); +DWORD sam_create_account(char *, char *, char *, smb_auth_info_t *, DWORD); +DWORD sam_remove_trust_account(char *, char *); +DWORD sam_delete_account(char *, char *, char *); +DWORD sam_get_local_domains(char *, char *); +DWORD sam_check_user(char *, char *, char *); /* * samr_open.c */ -int samr_open(char *server, char *domain, char *username, - DWORD access_mask, mlsvc_handle_t *samr_handle); - -int samr_connect(char *server, char *domain, char *username, - DWORD access_mask, mlsvc_handle_t *samr_handle); - -int samr_close_handle(mlsvc_handle_t *handle); - -DWORD samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask, - struct samr_sid *sid, mlsvc_handle_t *domain_handle); - -DWORD samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, - DWORD rid, mlsvc_handle_t *user_handle); - -DWORD samr_delete_user(mlsvc_handle_t *user_handle); - -int samr_open_group(mlsvc_handle_t *domain_handle, DWORD rid, - mlsvc_handle_t *group_handle); - -DWORD samr_create_user(mlsvc_handle_t *domain_handle, char *username, - DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle); +int samr_open(char *, char *, char *, DWORD, mlsvc_handle_t *); +int samr_connect(char *, char *, char *, DWORD, mlsvc_handle_t *); +int samr_close_handle(mlsvc_handle_t *); +DWORD samr_open_domain(mlsvc_handle_t *, DWORD, struct samr_sid *, + mlsvc_handle_t *); +DWORD samr_open_user(mlsvc_handle_t *, DWORD, DWORD, mlsvc_handle_t *); +DWORD samr_delete_user(mlsvc_handle_t *); +int samr_open_group(mlsvc_handle_t *, DWORD, mlsvc_handle_t *); +DWORD samr_create_user(mlsvc_handle_t *, char *, DWORD, DWORD *, + mlsvc_handle_t *); /* * samr_lookup.c @@ -140,21 +117,11 @@ union samr_user_info { }; -int samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name, - smb_userinfo_t *user_info); - -DWORD samr_enum_local_domains(mlsvc_handle_t *samr_handle); - -DWORD samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, - smb_userinfo_t *user_info); - -int samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value, - union samr_user_info *user_info); - -int samr_query_user_groups(mlsvc_handle_t *user_handle, - smb_userinfo_t *user_info); - -DWORD samr_get_user_pwinfo(mlsvc_handle_t *user_handle); +smb_sid_t *samr_lookup_domain(mlsvc_handle_t *, char *); +DWORD samr_enum_local_domains(mlsvc_handle_t *); +uint32_t samr_lookup_domain_names(mlsvc_handle_t *, char *, smb_account_t *); +int samr_query_user_info(mlsvc_handle_t *, WORD, union samr_user_info *); +DWORD samr_get_user_pwinfo(mlsvc_handle_t *); typedef struct oem_password { BYTE data[512]; @@ -162,12 +129,11 @@ typedef struct oem_password { } oem_password_t; -int sam_oem_password(oem_password_t *oem_password, unsigned char *new_password, - unsigned char *old_password); +int sam_oem_password(oem_password_t *, unsigned char *, unsigned char *); #ifdef __cplusplus } #endif -#endif /* _SMBSRV_SAMLIB_H */ +#endif /* _SAMLIB_H */ diff --git a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c index c599826fab..55f4e42364 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/samr_lookup.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -51,25 +51,19 @@ static int samr_set_user_password(smb_auth_info_t *, BYTE *); * samr_lookup_domain * * Lookup up the domain SID for the specified domain name. The handle - * should be one returned from samr_connect. The results will be - * returned in user_info - which should have been allocated by the - * caller. On success sid_name_use will be set to SidTypeDomain. - * - * Returns 0 on success, otherwise returns -ve error code. + * should be one returned from samr_connect. The allocated memory for + * the returned SID must be freed by caller. */ -int -samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name, - smb_userinfo_t *user_info) +smb_sid_t * +samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name) { struct samr_LookupDomain arg; + smb_sid_t *domsid = NULL; int opnum; - int rc; size_t length; - if (ndr_is_null_handle(samr_handle) || - domain_name == NULL || user_info == NULL) { - return (-1); - } + if (ndr_is_null_handle(samr_handle) || domain_name == NULL) + return (NULL); opnum = SAMR_OPNUM_LookupDomain; bzero(&arg, sizeof (struct samr_LookupDomain)); @@ -85,15 +79,11 @@ samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name, arg.domain_name.allosize = length; arg.domain_name.str = (unsigned char *)domain_name; - rc = ndr_rpc_call(samr_handle, opnum, &arg); - if (rc == 0) { - user_info->sid_name_use = SidTypeDomain; - user_info->domain_sid = smb_sid_dup((smb_sid_t *)arg.sid); - user_info->domain_name = MEM_STRDUP("ndr", domain_name); - } + if (ndr_rpc_call(samr_handle, opnum, &arg) == 0) + domsid = smb_sid_dup((smb_sid_t *)arg.sid); ndr_rpc_release(samr_handle); - return (rc); + return (domsid); } /* @@ -140,26 +130,27 @@ samr_enum_local_domains(mlsvc_handle_t *samr_handle) /* * samr_lookup_domain_names * - * Lookup up a name - * returned in user_info - which should have been allocated by the - * caller. On success sid_name_use will be set to SidTypeDomain. + * Lookup up the given name in the domain specified by domain_handle. + * Upon a successful lookup the information is returned in the account + * arg and caller must free allocated memories by calling smb_account_free(). * - * Returns 0 on success. Otherwise returns an NT status code. + * Returns NT status codes. */ -DWORD +uint32_t samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, - smb_userinfo_t *user_info) + smb_account_t *account) { struct samr_LookupNames arg; int opnum; - DWORD status; + uint32_t status; size_t length; if (ndr_is_null_handle(domain_handle) || - name == NULL || user_info == NULL) { + name == NULL || account == NULL) { return (NT_STATUS_INVALID_PARAMETER); } + bzero(account, sizeof (smb_account_t)); opnum = SAMR_OPNUM_LookupNames; bzero(&arg, sizeof (struct samr_LookupNames)); @@ -180,7 +171,7 @@ samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { status = NT_STATUS_INVALID_PARAMETER; - } else if (arg.status != 0) { + } else if (arg.status != NT_STATUS_SUCCESS) { status = NT_SC_VALUE(arg.status); /* @@ -189,10 +180,9 @@ samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, if (status != NT_STATUS_NONE_MAPPED) ndr_rpc_status(domain_handle, opnum, arg.status); } else { - user_info->name = MEM_STRDUP("ndr", name); - user_info->sid_name_use = arg.rid_types.rid_type[0]; - user_info->rid = arg.rids.rid[0]; - status = 0; + account->a_type = arg.rid_types.rid_type[0]; + account->a_rid = arg.rids.rid[0]; + status = NT_STATUS_SUCCESS; } ndr_rpc_release(domain_handle); @@ -248,7 +238,8 @@ samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value, * * Returns 0 on success, otherwise returns -1. */ -static int samr_setup_user_info(WORD switch_value, +static int +samr_setup_user_info(WORD switch_value, struct samr_QueryUserInfo *arg, union samr_user_info *user_info) { struct samr_QueryUserInfo1 *info1; @@ -312,14 +303,15 @@ static int samr_setup_user_info(WORD switch_value, * Returns 0 on success, otherwise returns -1. */ int -samr_query_user_groups(mlsvc_handle_t *user_handle, smb_userinfo_t *user_info) +samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups, + struct samr_UserGroups **groups) { struct samr_QueryUserGroups arg; int opnum; int rc; int nbytes; - if (ndr_is_null_handle(user_handle) || user_info == NULL) + if (ndr_is_null_handle(user_handle)) return (-1); opnum = SAMR_OPNUM_QueryUserGroups; @@ -335,15 +327,13 @@ samr_query_user_groups(mlsvc_handle_t *user_handle, smb_userinfo_t *user_info) } else { nbytes = arg.info->n_entry * sizeof (struct samr_UserGroups); - user_info->groups = malloc(nbytes); - if (user_info->groups == NULL) { - user_info->n_groups = 0; + if ((*groups = malloc(nbytes)) == NULL) { + *n_groups = 0; rc = -1; } else { - user_info->n_groups = arg.info->n_entry; - (void) memcpy(user_info->groups, - arg.info->groups, nbytes); + *n_groups = arg.info->n_entry; + bcopy(arg.info->groups, *groups, nbytes); } } } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c index 8de32423a5..f57c6e0d00 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_logon.c @@ -41,18 +41,17 @@ #include <smbsrv/smb_token.h> #include <lsalib.h> -extern uint32_t netlogon_logon(netr_client_t *clnt, smb_userinfo_t *uinfo); -static uint32_t smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo); -static uint32_t smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo); -static uint32_t smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo); +extern uint32_t netlogon_logon(netr_client_t *, smb_token_t *); +static uint32_t smb_logon_domain(netr_client_t *, smb_token_t *); +static uint32_t smb_logon_local(netr_client_t *, smb_token_t *); +static uint32_t smb_logon_anon(netr_client_t *, smb_token_t *); -static uint32_t smb_setup_luinfo(smb_userinfo_t *, netr_client_t *, uid_t); +static uint32_t smb_token_setup_local(smb_passwd_t *, smb_token_t *); +static uint32_t smb_token_setup_anon(smb_token_t *token); -static int smb_token_is_member(smb_token_t *token, smb_sid_t *sid); -static int smb_token_is_valid(smb_token_t *token); -static smb_win_grps_t *smb_token_create_wingrps(smb_userinfo_t *user_info); - -static smb_posix_grps_t *smb_token_create_pxgrps(uid_t uid); +static boolean_t smb_token_is_member(smb_token_t *, smb_sid_t *); +static uint32_t smb_token_setup_wingrps(smb_token_t *); +static smb_posix_grps_t *smb_token_create_pxgrps(uid_t); /* Consolidation private function from Network Repository */ extern int _getgroupsbymember(const char *, gid_t[], int, int); @@ -71,43 +70,43 @@ smb_token_idmap(smb_token_t *token, smb_idmap_batch_t *sib) sim = sib->sib_maps; if (token->tkn_flags & SMB_ATF_ANON) { - token->tkn_user->i_id = UID_NOBODY; - token->tkn_owner->i_id = UID_NOBODY; + token->tkn_user.i_id = UID_NOBODY; + token->tkn_owner.i_id = UID_NOBODY; } else { /* User SID */ - id = token->tkn_user; + id = &token->tkn_user; sim->sim_id = &id->i_id; stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++, - id->i_sidattr.sid, SMB_IDMAP_USER); + id->i_sid, SMB_IDMAP_USER); if (stat != IDMAP_SUCCESS) return (stat); /* Owner SID */ - id = token->tkn_owner; + id = &token->tkn_owner; sim->sim_id = &id->i_id; stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++, - id->i_sidattr.sid, SMB_IDMAP_USER); + id->i_sid, SMB_IDMAP_USER); if (stat != IDMAP_SUCCESS) return (stat); } /* Primary Group SID */ - id = token->tkn_primary_grp; + id = &token->tkn_primary_grp; sim->sim_id = &id->i_id; - stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++, - id->i_sidattr.sid, SMB_IDMAP_GROUP); + stat = smb_idmap_batch_getid(sib->sib_idmaph, sim++, id->i_sid, + SMB_IDMAP_GROUP); if (stat != IDMAP_SUCCESS) return (stat); /* Other Windows Group SIDs */ - for (i = 0; i < token->tkn_win_grps->wg_count; i++, sim++) { - id = &token->tkn_win_grps->wg_groups[i]; + for (i = 0; i < token->tkn_win_grps.i_cnt; i++, sim++) { + id = &token->tkn_win_grps.i_ids[i]; sim->sim_id = &id->i_id; stat = smb_idmap_batch_getid(sib->sib_idmaph, sim, - id->i_sidattr.sid, SMB_IDMAP_GROUP); + id->i_sid, SMB_IDMAP_GROUP); if (stat != IDMAP_SUCCESS) break; @@ -132,17 +131,12 @@ smb_token_sids2ids(smb_token_t *token) /* * Number of idmap lookups: user SID, owner SID, primary group SID, - * and all Windows group SIDs + * and all Windows group SIDs. Skip user/owner SID for Anonymous. */ if (token->tkn_flags & SMB_ATF_ANON) - /* - * Don't include user and owner SID, they're Anonymous - */ - nmaps = 1; + nmaps = token->tkn_win_grps.i_cnt + 1; else - nmaps = 3; - - nmaps += token->tkn_win_grps->wg_count; + nmaps = token->tkn_win_grps.i_cnt + 3; do { stat = smb_idmap_batch_create(&sib, nmaps, SMB_IDMAP_SID2ID); @@ -245,61 +239,18 @@ smb_token_create_pxgrps(uid_t uid) void smb_token_destroy(smb_token_t *token) { - smb_win_grps_t *groups; - int i; - - if (token == NULL) - return; - - if (token->tkn_user) { - free(token->tkn_user->i_sidattr.sid); - free(token->tkn_user); - } - - if (token->tkn_owner) { - free(token->tkn_owner->i_sidattr.sid); - free(token->tkn_owner); - } - - if (token->tkn_primary_grp) { - free(token->tkn_primary_grp->i_sidattr.sid); - free(token->tkn_primary_grp); - } - - if ((groups = token->tkn_win_grps) != NULL) { - for (i = 0; i < groups->wg_count; ++i) - free(groups->wg_groups[i].i_sidattr.sid); - free(groups); - } - - smb_privset_free(token->tkn_privileges); - - free(token->tkn_posix_grps); - free(token->tkn_account_name); - free(token->tkn_domain_name); - free(token->tkn_session_key); - - free(token); -} - -static smb_id_t * -smb_token_create_id(smb_sid_t *sid) -{ - smb_id_t *id; - - if ((id = malloc(sizeof (smb_id_t))) == NULL) - return (NULL); - - id->i_id = (uid_t)-1; - id->i_sidattr.attrs = 7; - id->i_sidattr.sid = smb_sid_dup(sid); - - if (id->i_sidattr.sid == NULL) { - free(id); - id = NULL; + if (token != NULL) { + smb_sid_free(token->tkn_user.i_sid); + smb_sid_free(token->tkn_owner.i_sid); + smb_sid_free(token->tkn_primary_grp.i_sid); + smb_ids_free(&token->tkn_win_grps); + smb_privset_free(token->tkn_privileges); + free(token->tkn_posix_grps); + free(token->tkn_account_name); + free(token->tkn_domain_name); + free(token->tkn_session_key); + free(token); } - - return (id); } /* @@ -308,28 +259,26 @@ smb_token_create_id(smb_sid_t *sid) * 1. The logged on user is a member of Domain Admins group * 2. he/she is a member of local Administrators group */ -static smb_id_t * -smb_token_create_owner(smb_userinfo_t *user_info) +static void +smb_token_set_owner(smb_token_t *token) { #ifdef SMB_SUPPORT_GROUP_OWNER smb_sid_t *owner_sid; - smb_wka_t *wka; - if (user_info->flags & SMB_UINFO_FLAG_ADMIN) { - wka = smb_wka_lookup("Administrators"); - assert(wka); - owner_sid = wka->wka_binsid; + if (token->tkn_flags & SMB_ATF_ADMIN) { + owner_sid = smb_wka_get_sid("Administrators"); + assert(owner_sid); } else { - owner_sid = user_info->user_sid; + owner_sid = token->tkn_user->i_sid; } - return (smb_token_create_id(owner_sid)); + token->tkn_owner.i_sid = smb_sid_dup(owner_sid); #endif - return (smb_token_create_id(user_info->user_sid)); + token->tkn_owner.i_sid = smb_sid_dup(token->tkn_user.i_sid); } static smb_privset_t * -smb_token_create_privs(smb_userinfo_t *user_info) +smb_token_create_privs(smb_token_t *token) { smb_privset_t *privs; smb_giter_t gi; @@ -346,14 +295,13 @@ smb_token_create_privs(smb_userinfo_t *user_info) } while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) { - if (smb_lgrp_is_member(&grp, user_info->user_sid)) { + if (smb_lgrp_is_member(&grp, token->tkn_user.i_sid)) smb_privset_merge(privs, grp.sg_privs); - } smb_lgrp_free(&grp); } smb_lgrp_iterclose(&gi); - if (user_info->flags & SMB_UINFO_FLAG_ADMIN) { + if (token->tkn_flags & SMB_ATF_ADMIN) { rc = smb_lgrp_getbyname("Administrators", &grp); if (rc == SMB_LGRP_SUCCESS) { smb_privset_merge(privs, grp.sg_privs); @@ -370,248 +318,57 @@ smb_token_create_privs(smb_userinfo_t *user_info) } static void -smb_token_set_flags(smb_token_t *token, smb_userinfo_t *user_info) +smb_token_set_flags(smb_token_t *token) { - smb_wka_t *wka; - - if (user_info->flags & SMB_UINFO_FLAG_ANON) { - token->tkn_flags |= SMB_ATF_ANON; - return; - } + uint32_t rid; - if (user_info->rid == DOMAIN_USER_RID_GUEST) { + (void) smb_sid_getrid(token->tkn_user.i_sid, &rid); + if (rid == DOMAIN_USER_RID_GUEST) { token->tkn_flags |= SMB_ATF_GUEST; return; } - wka = smb_wka_lookup("Administrators"); - if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid)) + if (smb_token_is_member(token, smb_wka_get_sid("Administrators"))) token->tkn_flags |= SMB_ATF_ADMIN; - wka = smb_wka_lookup("Power Users"); - if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid)) + if (smb_token_is_member(token, smb_wka_get_sid("Power Users"))) token->tkn_flags |= SMB_ATF_POWERUSER; - wka = smb_wka_lookup("Backup Operators"); - if (wka->wka_binsid && smb_token_is_member(token, wka->wka_binsid)) + if (smb_token_is_member(token, smb_wka_get_sid("Backup Operators"))) token->tkn_flags |= SMB_ATF_BACKUPOP; - } /* - * smb_token_create + * Common token setup for both local and domain users. + * This function must be called after the initial setup + * has been done. * - * Build an access token based on the given user information (user_info). - * - * If everything is successful, a pointer to an access token is - * returned. Otherwise a null pointer is returned. + * Note that the order of calls in this function are important. */ -static smb_token_t * -smb_token_create(smb_userinfo_t *user_info) +static uint32_t +smb_token_setup_common(smb_token_t *token) { - smb_token_t *token; - - if (user_info->sid_name_use != SidTypeUser) - return (NULL); - - token = (smb_token_t *)malloc(sizeof (smb_token_t)); - if (token == NULL) { - syslog(LOG_ERR, "smb_token_create: resource shortage"); - return (NULL); - } - bzero(token, sizeof (smb_token_t)); - - /* User */ - token->tkn_user = smb_token_create_id(user_info->user_sid); - if (token->tkn_user == NULL) { - smb_token_destroy(token); - return (NULL); - } + smb_token_set_flags(token); - /* Owner */ - token->tkn_owner = smb_token_create_owner(user_info); - if (token->tkn_owner == NULL) { - smb_token_destroy(token); - return (NULL); - } - - /* Primary Group */ - token->tkn_primary_grp = smb_token_create_id(user_info->pgrp_sid); - if (token->tkn_primary_grp == NULL) { - smb_token_destroy(token); - return (NULL); - } + smb_token_set_owner(token); + if (token->tkn_owner.i_sid == NULL) + return (NT_STATUS_NO_MEMORY); /* Privileges */ - token->tkn_privileges = smb_token_create_privs(user_info); - if (token->tkn_privileges == NULL) { - smb_token_destroy(token); - return (NULL); - } - - /* Windows Groups */ - token->tkn_win_grps = smb_token_create_wingrps(user_info); - - smb_token_set_flags(token, user_info); + token->tkn_privileges = smb_token_create_privs(token); + if (token->tkn_privileges == NULL) + return (NT_STATUS_NO_MEMORY); - /* - * IMPORTANT - * - * This function has to be called after all the SIDs in the - * token are setup (i.e. user, owner, primary and supplementary - * groups) and before setting up Solaris groups. - */ if (smb_token_sids2ids(token) != 0) { syslog(LOG_ERR, "%s\\%s: idmap failed", - (user_info->domain_name) ? user_info->domain_name : "", - (user_info->name) ? user_info->name : ""); - smb_token_destroy(token); - return (NULL); + token->tkn_domain_name, token->tkn_account_name); + return (NT_STATUS_INTERNAL_ERROR); } /* Solaris Groups */ - token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user->i_id); - - if (user_info->session_key) { - token->tkn_session_key = malloc(sizeof (smb_session_key_t)); - if (token->tkn_session_key == NULL) { - smb_token_destroy(token); - return (NULL); - } + token->tkn_posix_grps = smb_token_create_pxgrps(token->tkn_user.i_id); - (void) memcpy(token->tkn_session_key, - user_info->session_key, sizeof (smb_session_key_t)); - } - - token->tkn_account_name = strdup(user_info->name); - token->tkn_domain_name = strdup(user_info->domain_name); - - if (!smb_token_is_valid(token)) { - smb_token_destroy(token); - return (NULL); - } - - return (token); -} - -/* - * smb_token_create_wingrps - * - * This private function supports smb_token_create() by mapping the group - * information in the user_info structure to the form required in an - * access token. The main difference is that the user_info contains - * RIDs while and access token contains full SIDs. Memory allocated - * here will be deallocated as part of smb_token_destroy(). - * - * If everything is successful, a pointer to a smb_win_grps_t - * structure is returned. Otherwise a null pointer is returned. - */ -static smb_win_grps_t * -smb_token_create_wingrps(smb_userinfo_t *user_info) -{ - static char *wk_grps[] = - {"Authenticated Users", "NETWORK", "Administrators"}; - smb_win_grps_t *tkn_grps; - smb_sid_attrs_t *dlg_grps; - smb_rid_attrs_t *g_grps; - smb_sid_attrs_t *grp; - smb_sid_t *builtin_sid; - smb_giter_t gi; - smb_group_t lgrp; - uint32_t n_gg, n_lg, n_dlg, n_wg; - uint32_t i, j; - int size, count; - - if (user_info == NULL) - return (NULL); - - n_gg = user_info->n_groups; /* Global Groups */ - n_dlg = user_info->n_other_grps; /* Domain Local Groups */ - - /* Local Groups */ - (void) smb_lgrp_numbymember(user_info->user_sid, (int *)&n_lg); - - /* Well known Groups */ - if ((user_info->flags & SMB_UINFO_FLAG_ADMIN) == SMB_UINFO_FLAG_DADMIN) - /* if user is a domain admin but not a local admin */ - n_wg = 3; - else if (user_info->flags & SMB_UINFO_FLAG_ANON) - n_wg = 0; - else - n_wg = 2; - - count = n_gg + n_dlg + n_lg + n_wg; - size = sizeof (smb_win_grps_t) + (count * sizeof (smb_id_t)); - - if ((tkn_grps = malloc(size)) == NULL) - return (NULL); - bzero(tkn_grps, size); - - /* Add global groups */ - g_grps = user_info->groups; - for (i = 0; i < n_gg; i++) { - grp = &tkn_grps->wg_groups[i].i_sidattr; - grp->sid = smb_sid_splice(user_info->domain_sid, g_grps[i].rid); - if (grp->sid == NULL) - break; - grp->attrs = g_grps[i].attributes; - } - - if (n_gg == 0) { - /* - * if there's no global group should add the - * primary group. - */ - grp = &tkn_grps->wg_groups[i].i_sidattr; - grp->sid = smb_sid_dup(user_info->pgrp_sid); - if (grp->sid != NULL) { - grp->attrs = 0x7; - i++; - } - } - - /* Add domain local groups */ - dlg_grps = user_info->other_grps; - for (j = 0; j < n_dlg; j++, i++) { - grp = &tkn_grps->wg_groups[i].i_sidattr; - grp->sid = smb_sid_dup(dlg_grps[j].sid); - if (grp->sid == NULL) - break; - grp->attrs = dlg_grps[j].attrs; - } - - /* Add local groups */ - if (n_lg && (smb_lgrp_iteropen(&gi) == SMB_LGRP_SUCCESS)) { - j = 0; - while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { - if ((j < n_lg) && - smb_lgrp_is_member(&lgrp, user_info->user_sid)) { - grp = &tkn_grps->wg_groups[i].i_sidattr; - grp->sid = smb_sid_dup(lgrp.sg_id.gs_sid); - if (grp->sid == NULL) { - smb_lgrp_free(&lgrp); - break; - } - grp->attrs = lgrp.sg_attr; - i++; - j++; - } - smb_lgrp_free(&lgrp); - } - smb_lgrp_iterclose(&gi); - } - - /* Add well known groups */ - for (j = 0; j < n_wg; j++, i++) { - builtin_sid = smb_wka_lookup_name(wk_grps[j], NULL); - if (builtin_sid == NULL) - break; - tkn_grps->wg_groups[i].i_sidattr.sid = builtin_sid; - tkn_grps->wg_groups[i].i_sidattr.attrs = 0x7; - } - - tkn_grps->wg_count = i; - return (tkn_grps); + return (NT_STATUS_SUCCESS); } /* @@ -626,38 +383,31 @@ smb_token_t * smb_logon(netr_client_t *clnt) { smb_token_t *token = NULL; - smb_userinfo_t *uinfo; uint32_t status; - if ((uinfo = mlsvc_alloc_user_info()) == 0) + if ((token = malloc(sizeof (smb_token_t))) == NULL) { + syslog(LOG_ERR, "smb_logon: resource shortage"); return (NULL); + } + bzero(token, sizeof (smb_token_t)); - switch (clnt->flags) { - case NETR_CFLG_DOMAIN: - /* Pass through authentication with DC */ - status = smb_logon_domain(clnt, uinfo); - break; - - case NETR_CFLG_LOCAL: - /* Local authentication */ - status = smb_logon_local(clnt, uinfo); - break; - - case NETR_CFLG_ANON: - /* Anonymous user; no authentication */ - status = smb_logon_none(clnt, uinfo); - break; - - default: - status = NT_STATUS_INVALID_PARAMETER; - break; + status = smb_logon_anon(clnt, token); + if (status == NT_STATUS_INVALID_LOGON_TYPE) { + status = smb_logon_local(clnt, token); + if (status != NT_STATUS_SUCCESS) { + if ((status == NT_STATUS_INVALID_LOGON_TYPE) || + (*clnt->real_domain == '\0')) + status = smb_logon_domain(clnt, token); + } } - if (status == NT_STATUS_SUCCESS) - token = smb_token_create(uinfo); + if (status == NT_STATUS_SUCCESS) { + if (smb_token_setup_common(token) == NT_STATUS_SUCCESS) + return (token); + } - mlsvc_free_user_info(uinfo); - return (token); + smb_token_destroy(token); + return (NULL); } /* @@ -666,15 +416,15 @@ smb_logon(netr_client_t *clnt) * Performs pass through authentication with PDC. */ static uint32_t -smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo) +smb_logon_domain(netr_client_t *clnt, smb_token_t *token) { uint32_t status; - if ((status = netlogon_logon(clnt, uinfo)) != 0) { + if ((status = netlogon_logon(clnt, token)) != 0) { if (status == NT_STATUS_CANT_ACCESS_DOMAIN_INFO) { - if ((status = netlogon_logon(clnt, uinfo)) != 0) { + if ((status = netlogon_logon(clnt, token)) != 0) { syslog(LOG_INFO, "SmbLogon[%s\\%s]: %s", - clnt->domain, clnt->username, + clnt->real_domain, clnt->real_username, xlate_nt_status(status)); return (status); } @@ -692,20 +442,28 @@ smb_logon_domain(netr_client_t *clnt, smb_userinfo_t *uinfo) * hash with user's password(s) to authenticate the user. */ static uint32_t -smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo) +smb_logon_local(netr_client_t *clnt, smb_token_t *token) { smb_passwd_t smbpw; boolean_t lm_ok, nt_ok; uint32_t status; + nt_domain_t *domain; - if (smb_pwd_getpwnam(clnt->username, &smbpw) == NULL) { + /* Make sure this is not a domain user */ + if (smb_config_get_secmode() == SMB_SECMODE_DOMAIN) { + domain = nt_domain_lookup_name(clnt->real_domain); + if (domain && (domain->type != NT_DOMAIN_LOCAL)) + return (NT_STATUS_INVALID_LOGON_TYPE); + } + + if (smb_pwd_getpwnam(clnt->real_username, &smbpw) == NULL) { /* * If user doesn't have entry either in smbpasswd * or passwd it's considered as an invalid user. */ status = NT_STATUS_NO_SUCH_USER; syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s", - clnt->domain, clnt->username, + clnt->real_domain, clnt->real_username, xlate_nt_status(status)); return (status); } @@ -723,12 +481,12 @@ smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo) clnt->lm_password.lm_password_len, clnt->domain, clnt->username); - uinfo->session_key = NULL; + token->tkn_session_key = NULL; } if (!lm_ok && (clnt->nt_password.nt_password_len != 0)) { - if ((uinfo->session_key = - malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL) + token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ); + if (token->tkn_session_key == NULL) return (NT_STATUS_NO_MEMORY); nt_ok = smb_auth_validate_nt( clnt->challenge_key.challenge_key_val, @@ -738,84 +496,67 @@ smb_logon_local(netr_client_t *clnt, smb_userinfo_t *uinfo) clnt->nt_password.nt_password_len, clnt->domain, clnt->username, - (uchar_t *)uinfo->session_key); + (uchar_t *)token->tkn_session_key); } if (!nt_ok && !lm_ok) { status = NT_STATUS_WRONG_PASSWORD; syslog(LOG_NOTICE, "SmbLogon[%s\\%s]: %s", - clnt->domain, clnt->username, + clnt->real_domain, clnt->real_username, xlate_nt_status(status)); return (status); } - status = smb_setup_luinfo(uinfo, clnt, smbpw.pw_uid); + status = smb_token_setup_local(&smbpw, token); return (status); } /* - * smb_logon_none - * - * Setup user information for anonymous user. - * No authentication is required. + * If 'clnt' represents an anonymous user (no password) + * then setup the token accordingly, otherwise return + * NT_STATUS_INVALID_LOGON_TYPE */ static uint32_t -smb_logon_none(netr_client_t *clnt, smb_userinfo_t *uinfo) +smb_logon_anon(netr_client_t *clnt, smb_token_t *token) { - return (smb_setup_luinfo(uinfo, clnt, (uid_t)-1)); + if ((clnt->nt_password.nt_password_len == 0) && + (clnt->lm_password.lm_password_len == 0 || + (clnt->lm_password.lm_password_len == 1 && + *clnt->lm_password.lm_password_val == '\0'))) { + return (smb_token_setup_anon(token)); + } + + return (NT_STATUS_INVALID_LOGON_TYPE); } /* - * smb_setup_luinfo - * - * Setup local user information based on the client information and - * user's record in the local password file. + * Setup an access token for the specified local user. */ static uint32_t -smb_setup_luinfo(smb_userinfo_t *lui, netr_client_t *clnt, uid_t uid) +smb_token_setup_local(smb_passwd_t *smbpw, smb_token_t *token) { idmap_stat stat; smb_idmap_batch_t sib; smb_idmap_t *umap, *gmap; - smb_group_t grp; struct passwd pw; char pwbuf[1024]; char nbname[NETBIOS_NAME_SZ]; (void) smb_getnetbiosname(nbname, sizeof (nbname)); - lui->sid_name_use = SidTypeUser; - lui->domain_sid = smb_sid_dup(nt_domain_local_sid()); - lui->name = strdup(clnt->username); - lui->domain_name = strdup(nbname); - lui->n_groups = 0; - lui->groups = NULL; - lui->n_other_grps = 0; - lui->other_grps = NULL; - lui->flags = 0; - - if (lui->name == NULL || lui->domain_name == NULL || - lui->domain_sid == NULL) - return (NT_STATUS_INVALID_PARAMETER); - - if (clnt->flags & NETR_CFLG_ANON) { - lui->user_sid = smb_wka_lookup_name("Anonymous", NULL); - lui->pgrp_sid = smb_wka_lookup_name("Anonymous", NULL); - lui->flags = SMB_UINFO_FLAG_ANON; - - if (lui->user_sid == NULL || lui->pgrp_sid == NULL) - return (NT_STATUS_NO_MEMORY); + token->tkn_account_name = strdup(smbpw->pw_name); + token->tkn_domain_name = strdup(nbname); - return (NT_STATUS_SUCCESS); - } + if (token->tkn_account_name == NULL || + token->tkn_domain_name == NULL) + return (NT_STATUS_NO_MEMORY); - if (getpwuid_r(uid, &pw, pwbuf, sizeof (pwbuf)) == NULL) + if (getpwuid_r(smbpw->pw_uid, &pw, pwbuf, sizeof (pwbuf)) == NULL) return (NT_STATUS_NO_SUCH_USER); /* Get the SID for user's uid & gid */ stat = smb_idmap_batch_create(&sib, 2, SMB_IDMAP_ID2SID); - if (stat != IDMAP_SUCCESS) { + if (stat != IDMAP_SUCCESS) return (NT_STATUS_INTERNAL_ERROR); - } umap = &sib.sib_maps[0]; stat = smb_idmap_batch_getsid(sib.sib_idmaph, umap, pw.pw_uid, @@ -835,54 +576,45 @@ smb_setup_luinfo(smb_userinfo_t *lui, netr_client_t *clnt, uid_t uid) return (NT_STATUS_INTERNAL_ERROR); } - stat = smb_idmap_batch_getmappings(&sib); - - if (stat != IDMAP_SUCCESS) { + if (smb_idmap_batch_getmappings(&sib) != IDMAP_SUCCESS) return (NT_STATUS_INTERNAL_ERROR); - } - - lui->rid = umap->sim_rid; - lui->user_sid = smb_sid_dup(umap->sim_sid); - lui->primary_group_rid = gmap->sim_rid; - lui->pgrp_sid = smb_sid_dup(gmap->sim_sid); + token->tkn_user.i_sid = smb_sid_dup(umap->sim_sid); + token->tkn_primary_grp.i_sid = smb_sid_dup(gmap->sim_sid); smb_idmap_batch_destroy(&sib); - if ((lui->user_sid == NULL) || (lui->pgrp_sid == NULL)) + if (token->tkn_user.i_sid == NULL || + token->tkn_primary_grp.i_sid == NULL) return (NT_STATUS_NO_MEMORY); - if (smb_lgrp_getbyname("Administrators", &grp) == SMB_LGRP_SUCCESS) { - if (smb_lgrp_is_member(&grp, lui->user_sid)) - lui->flags = SMB_UINFO_FLAG_LADMIN; - smb_lgrp_free(&grp); - } - - return (NT_STATUS_SUCCESS); + return (smb_token_setup_wingrps(token)); } /* - * smb_token_is_valid - * - * check to see if specified fields of the given access - * token are valid. - * Returns 1 if all of them are valid; otherwise 0. + * Setup access token for an anonymous connection */ -static int -smb_token_is_valid(smb_token_t *token) +static uint32_t +smb_token_setup_anon(smb_token_t *token) { - int valid; - - valid = (token->tkn_user != 0) && - (token->tkn_user->i_sidattr.sid != 0) && - (token->tkn_privileges != 0) && - (token->tkn_win_grps != 0) && - (token->tkn_owner != 0) && - (token->tkn_owner->i_sidattr.sid != 0) && - (token->tkn_primary_grp != 0) && - (token->tkn_primary_grp->i_sidattr.sid != 0); - - return (valid); + char nbname[NETBIOS_NAME_SZ]; + smb_sid_t *user_sid; + + (void) smb_getnetbiosname(nbname, sizeof (nbname)); + token->tkn_account_name = strdup("Anonymous"); + token->tkn_domain_name = strdup("NT Authority"); + user_sid = smb_wka_get_sid("Anonymous"); + token->tkn_user.i_sid = smb_sid_dup(user_sid); + token->tkn_primary_grp.i_sid = smb_sid_dup(user_sid); + token->tkn_flags = SMB_ATF_ANON; + + if (token->tkn_account_name == NULL || + token->tkn_domain_name == NULL || + token->tkn_user.i_sid == NULL || + token->tkn_primary_grp.i_sid == NULL) + return (NT_STATUS_NO_MEMORY); + + return (smb_token_setup_wingrps(token)); } /* @@ -894,10 +626,7 @@ smb_token_is_valid(smb_token_t *token) static smb_sid_t * smb_token_user_sid(smb_token_t *token) { - if (token && token->tkn_user) - return ((token)->tkn_user->i_sidattr.sid); - - return (NULL); + return ((token) ? token->tkn_user.i_sid : NULL); } /* @@ -917,25 +646,21 @@ smb_token_user_sid(smb_token_t *token) static smb_sid_t * smb_token_group_sid(smb_token_t *token, int *iterator) { - smb_win_grps_t *groups; int index; - if (token == NULL || iterator == NULL) { + if (token == NULL || iterator == NULL) return (NULL); - } - if ((groups = token->tkn_win_grps) == NULL) { + if (token->tkn_win_grps.i_ids == NULL) return (NULL); - } index = *iterator; - if (index < 0 || index >= groups->wg_count) { + if (index < 0 || index >= token->tkn_win_grps.i_cnt) return (NULL); - } ++(*iterator); - return (groups->wg_groups[index].i_sidattr.sid); + return (token->tkn_win_grps.i_ids[index].i_sid); } /* @@ -945,21 +670,24 @@ smb_token_group_sid(smb_token_t *token, int *iterator) * member of a token. The user SID and all group SIDs are tested. * Returns 1 if the SID is a member of the token. Otherwise returns 0. */ -static int +static boolean_t smb_token_is_member(smb_token_t *token, smb_sid_t *sid) { smb_sid_t *tsid; int iterator = 0; + if (token == NULL || sid == NULL) + return (B_FALSE); + tsid = smb_token_user_sid(token); while (tsid) { if (smb_sid_cmp(tsid, sid)) - return (1); + return (B_TRUE); tsid = smb_token_group_sid(token, &iterator); } - return (0); + return (B_FALSE); } /* @@ -970,9 +698,9 @@ smb_token_is_member(smb_token_t *token, smb_sid_t *sid) void smb_token_log(smb_token_t *token) { - smb_win_grps_t *w_grps; + smb_ids_t *w_grps; + smb_id_t *grp; smb_posix_grps_t *x_grps; - smb_sid_attrs_t *grp; char sidstr[SMB_SID_STRSZ]; int i; @@ -983,54 +711,97 @@ smb_token_log(smb_token_t *token) (token->tkn_domain_name) ? token->tkn_domain_name : "-NULL-", (token->tkn_account_name) ? token->tkn_account_name : "-NULL-"); - syslog(LOG_DEBUG, " User->Attr: %d", - token->tkn_user->i_sidattr.attrs); - smb_sid_tostr((smb_sid_t *)token->tkn_user->i_sidattr.sid, sidstr); - syslog(LOG_DEBUG, " User->Sid: %s (id=%u)", - sidstr, token->tkn_user->i_id); + syslog(LOG_DEBUG, " User->Attr: %d", token->tkn_user.i_attrs); + smb_sid_tostr((smb_sid_t *)token->tkn_user.i_sid, sidstr); + syslog(LOG_DEBUG, " User->Sid: %s (id=%u)", sidstr, + token->tkn_user.i_id); - smb_sid_tostr((smb_sid_t *)token->tkn_owner->i_sidattr.sid, sidstr); + smb_sid_tostr((smb_sid_t *)token->tkn_owner.i_sid, sidstr); syslog(LOG_DEBUG, " Ownr->Sid: %s (id=%u)", - sidstr, token->tkn_owner->i_id); + sidstr, token->tkn_owner.i_id); - smb_sid_tostr((smb_sid_t *)token->tkn_primary_grp->i_sidattr.sid, - sidstr); + smb_sid_tostr((smb_sid_t *)token->tkn_primary_grp.i_sid, sidstr); syslog(LOG_DEBUG, " PGrp->Sid: %s (id=%u)", - sidstr, token->tkn_primary_grp->i_id); - - w_grps = token->tkn_win_grps; - if (w_grps) { - syslog(LOG_DEBUG, " Windows groups: %d", - w_grps->wg_count); + sidstr, token->tkn_primary_grp.i_id); - for (i = 0; i < w_grps->wg_count; ++i) { - grp = &w_grps->wg_groups[i].i_sidattr; + w_grps = &token->tkn_win_grps; + if (w_grps->i_ids) { + syslog(LOG_DEBUG, " Windows groups: %d", w_grps->i_cnt); + grp = w_grps->i_ids; + for (i = 0; i < w_grps->i_cnt; ++i, grp++) { syslog(LOG_DEBUG, - " Grp[%d].Attr:%d", i, grp->attrs); - if (w_grps->wg_groups[i].i_sidattr.sid) { - smb_sid_tostr((smb_sid_t *)grp->sid, sidstr); + " Grp[%d].Attr:%d", i, grp->i_attrs); + if (grp->i_sid != NULL) { + smb_sid_tostr((smb_sid_t *)grp->i_sid, sidstr); syslog(LOG_DEBUG, " Grp[%d].Sid: %s (id=%u)", i, sidstr, - w_grps->wg_groups[i].i_id); + grp->i_id); } } - } - else + } else { syslog(LOG_DEBUG, " No Windows groups"); + } x_grps = token->tkn_posix_grps; if (x_grps) { - syslog(LOG_DEBUG, " Solaris groups: %d", - x_grps->pg_ngrps); + syslog(LOG_DEBUG, " Solaris groups: %d", x_grps->pg_ngrps); for (i = 0; i < x_grps->pg_ngrps; i++) - syslog(LOG_DEBUG, " %u", - x_grps->pg_grps[i]); - } - else + syslog(LOG_DEBUG, " %u", x_grps->pg_grps[i]); + } else { syslog(LOG_DEBUG, " No Solaris groups"); + } if (token->tkn_privileges) smb_privset_log(token->tkn_privileges); else syslog(LOG_DEBUG, " No privileges"); } + +/* + * Sets up local and well-known group membership for the given + * token. Two assumptions have been made here: + * + * a) token already contains a valid user SID so that group + * memberships can be established + * + * b) token belongs to a local or anonymous user + */ +static uint32_t +smb_token_setup_wingrps(smb_token_t *token) +{ + smb_ids_t tkn_grps; + uint32_t status; + + + /* + * We always want the user's primary group in the list + * of groups. + */ + tkn_grps.i_cnt = 1; + if ((tkn_grps.i_ids = malloc(sizeof (smb_id_t))) == NULL) + return (NT_STATUS_NO_MEMORY); + + tkn_grps.i_ids->i_sid = smb_sid_dup(token->tkn_primary_grp.i_sid); + tkn_grps.i_ids->i_attrs = token->tkn_primary_grp.i_attrs; + if (tkn_grps.i_ids->i_sid == NULL) { + smb_ids_free(&tkn_grps); + return (NT_STATUS_NO_MEMORY); + } + + status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps); + if (status != NT_STATUS_SUCCESS) { + smb_ids_free(&tkn_grps); + return (status); + } + + if ((token->tkn_flags & SMB_ATF_ANON) == 0) { + status = smb_wka_token_groups(B_FALSE, &tkn_grps); + if (status != NT_STATUS_SUCCESS) { + smb_ids_free(&tkn_grps); + return (status); + } + } + + token->tkn_win_grps = tkn_grps; + return (status); +} diff --git a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c index 95142bb0db..a4ab4da9bf 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/smb_share.c @@ -624,9 +624,11 @@ smb_shr_exists(char *sharename) * Precedence is none is checked first followed by ro then rw if * needed. If x is wildcard (< 0) then check to see if the other * values are a match. If a match, that wins. + * + * ipv6 is wide open for now, see smb_chk_hostaccess */ void -smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr) +smb_shr_hostaccess(smb_share_t *si, smb_inaddr_t *ipaddr) { int acc = SMB_SHRF_ACC_OPEN; @@ -634,7 +636,8 @@ smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr) * Check to see if there area any share level access * restrictions. */ - if (ipaddr != 0 && (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) { + if ((!smb_inet_iszero(ipaddr)) && + (si->shr_flags & SMB_SHRF_ACC_ALL) != 0) { int none = SMB_SHRF_ACC_OPEN; int rw = SMB_SHRF_ACC_OPEN; int ro = SMB_SHRF_ACC_OPEN; @@ -645,7 +648,6 @@ smb_shr_hostaccess(smb_share_t *si, ipaddr_t ipaddr) rw = smb_chk_hostaccess(ipaddr, si->shr_access_rw); if (si->shr_flags & SMB_SHRF_ACC_RO) ro = smb_chk_hostaccess(ipaddr, si->shr_access_ro); - /* make first pass to get basic value */ if (none != 0) acc = SMB_SHRF_ACC_NONE; @@ -864,7 +866,6 @@ smb_shr_lookup(char *sharename, smb_share_t *si) if (sharename == NULL || *sharename == '\0') return (NERR_NetNameNotFound); - if (smb_shr_cache_lock(SMB_SHR_CACHE_RDLOCK) == NERR_Success) { cached_si = smb_shr_cache_findent(sharename); if (cached_si != NULL) { @@ -874,7 +875,6 @@ smb_shr_lookup(char *sharename, smb_share_t *si) smb_shr_cache_unlock(); } - return (status); } @@ -1323,7 +1323,6 @@ smb_shr_sa_get(sa_share_t share, sa_resource_t resource, smb_share_t *si) (void) strlcpy(si->shr_path, path, sizeof (si->shr_path)); (void) strlcpy(si->shr_name, rname, sizeof (si->shr_name)); - sa_free_attr_string(path); sa_free_attr_string(rname); diff --git a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c index f26f992d4c..6da809af8b 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/srvsvc_svc.c @@ -36,8 +36,6 @@ #include <netdb.h> #include <strings.h> #include <time.h> -#include <tzfile.h> -#include <time.h> #include <thread.h> #include <ctype.h> #include <stdlib.h> @@ -861,7 +859,7 @@ mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions, smb_dr_ulist_t *ulist; smb_opipe_context_t *user; char *workstation; - char ipaddr_buf[INET_ADDRSTRLEN]; + char ipaddr_buf[INET6_ADDRSTRLEN]; int n_users; int offset = 0; int i; @@ -888,8 +886,8 @@ mlsvc_NetSessionEnumLevel0(struct mslm_infonres *infonres, DWORD n_sessions, workstation = user->oc_workstation; if (workstation == NULL || *workstation == '\0') { - (void) inet_ntop(AF_INET, (char *)&user->oc_ipaddr, - ipaddr_buf, sizeof (ipaddr_buf)); + (void) smb_inet_ntop(&user->oc_ipaddr, + ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); workstation = ipaddr_buf; } @@ -920,7 +918,7 @@ mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions, smb_opipe_context_t *user; char *workstation; char account[MAXNAMELEN]; - char ipaddr_buf[INET_ADDRSTRLEN]; + char ipaddr_buf[INET6_ADDRSTRLEN]; int n_users; int offset = 0; int i; @@ -947,8 +945,8 @@ mlsvc_NetSessionEnumLevel1(struct mslm_infonres *infonres, DWORD n_sessions, workstation = user->oc_workstation; if (workstation == NULL || *workstation == '\0') { - (void) inet_ntop(AF_INET, (char *)&user->oc_ipaddr, - ipaddr_buf, sizeof (ipaddr_buf)); + (void) smb_inet_ntop(&user->oc_ipaddr, + ipaddr_buf, SMB_IPSTRLEN(user->oc_ipaddr.a_family)); workstation = ipaddr_buf; } diff --git a/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c b/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c index 14c733dde4..e689b95e57 100644 --- a/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c +++ b/usr/src/lib/smbsrv/libmlsvc/common/winreg_svc.c @@ -26,10 +26,24 @@ /* * Windows Registry RPC (WINREG) server-side interface. * - * The WINREG RPC interface returns Win32 error codes. + * The registry is a database with a hierarchical structure similar to + * a file system, with keys in place of directories and values in place + * of files. The top level keys are known as root keys and each key can + * contain subkeys and values. As with directories and sub-directories, + * the terms key and subkey are used interchangeably. Values, analogous + * to files, contain data. + * + * A specific subkey can be identifies by its fully qualified name (FQN), + * which is analogous to a file system path. In the registry, the key + * separator is the '\' character, which is reserved and cannot appear + * in key or value names. Registry names are case-insensitive. + * + * For example: HKEY_LOCAL_MACHINE\System\CurrentControlSet * - * HKLM Hive Key Local Machine - * HKU Hive Key Users + * The HKEY_LOCAL_MACHINE root key contains a subkey call System, and + * System contains a subkey called CurrentControlSet. + * + * The WINREG RPC interface returns Win32 error codes. */ #include <sys/utsname.h> @@ -42,22 +56,13 @@ #include <smbsrv/libmlsvc.h> #include <smbsrv/ndl/winreg.ndl> -#define WINREG_LOGR_SYSTEMKEY \ - "System\\CurrentControlSet\\Services\\Eventlog\\System" - -/* - * Local handle management keys. - */ -static int winreg_hk; -static int winreg_hklm; -static int winreg_hkuser; -static int winreg_hkkey; - /* * List of supported registry keys (case-insensitive). */ static char *winreg_keys[] = { "System\\CurrentControlSet\\Services\\Eventlog", + "System\\CurrentControlSet\\Services\\Eventlog\\Application", + "System\\CurrentControlSet\\Services\\Eventlog\\Security", "System\\CurrentControlSet\\Services\\Eventlog\\System", "System\\CurrentControlSet\\Control\\ProductOptions", "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion" @@ -78,12 +83,19 @@ typedef struct winreg_keylist { static winreg_keylist_t winreg_keylist; static boolean_t winreg_key_has_subkey(const char *); +static char *winreg_enum_subkey(ndr_xa_t *, const char *, uint32_t); static char *winreg_lookup_value(const char *); -static char *winreg_lookup_eventlog_registry(char *, char *); -static int winreg_s_OpenHK(void *, ndr_xa_t *); +static int winreg_s_OpenHKCR(void *, ndr_xa_t *); +static int winreg_s_OpenHKCU(void *, ndr_xa_t *); static int winreg_s_OpenHKLM(void *, ndr_xa_t *); -static int winreg_s_OpenHKUsers(void *, ndr_xa_t *); +static int winreg_s_OpenHKPD(void *, ndr_xa_t *); +static int winreg_s_OpenHKU(void *, ndr_xa_t *); +static int winreg_s_OpenHKCC(void *, ndr_xa_t *); +static int winreg_s_OpenHKDD(void *, ndr_xa_t *); +static int winreg_s_OpenHKPT(void *, ndr_xa_t *); +static int winreg_s_OpenHKPN(void *, ndr_xa_t *); +static int winreg_s_OpenHK(void *, ndr_xa_t *, const char *); static int winreg_s_Close(void *, ndr_xa_t *); static int winreg_s_CreateKey(void *, ndr_xa_t *); static int winreg_s_DeleteKey(void *, ndr_xa_t *); @@ -103,11 +115,11 @@ static int winreg_s_AbortShutdown(void *, ndr_xa_t *); static int winreg_s_GetVersion(void *, ndr_xa_t *); static ndr_stub_table_t winreg_stub_table[] = { - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKCR }, - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKCU }, + { winreg_s_OpenHKCR, WINREG_OPNUM_OpenHKCR }, + { winreg_s_OpenHKCU, WINREG_OPNUM_OpenHKCU }, { winreg_s_OpenHKLM, WINREG_OPNUM_OpenHKLM }, - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKPD }, - { winreg_s_OpenHKUsers, WINREG_OPNUM_OpenHKUsers }, + { winreg_s_OpenHKPD, WINREG_OPNUM_OpenHKPD }, + { winreg_s_OpenHKU, WINREG_OPNUM_OpenHKUsers }, { winreg_s_Close, WINREG_OPNUM_Close }, { winreg_s_CreateKey, WINREG_OPNUM_CreateKey }, { winreg_s_DeleteKey, WINREG_OPNUM_DeleteKey }, @@ -125,10 +137,10 @@ static ndr_stub_table_t winreg_stub_table[] = { { winreg_s_Shutdown, WINREG_OPNUM_Shutdown }, { winreg_s_AbortShutdown, WINREG_OPNUM_AbortShutdown }, { winreg_s_GetVersion, WINREG_OPNUM_GetVersion }, - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKCC }, - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKDD }, - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKPT }, - { winreg_s_OpenHK, WINREG_OPNUM_OpenHKPN }, + { winreg_s_OpenHKCC, WINREG_OPNUM_OpenHKCC }, + { winreg_s_OpenHKDD, WINREG_OPNUM_OpenHKDD }, + { winreg_s_OpenHKPT, WINREG_OPNUM_OpenHKPT }, + { winreg_s_OpenHKPN, WINREG_OPNUM_OpenHKPN }, {0} }; @@ -188,70 +200,80 @@ winreg_initialize(void) (void) ndr_svc_register(&winreg_service); } -/* - * winreg_s_OpenHK - * - * Stub. - */ static int -winreg_s_OpenHK(void *arg, ndr_xa_t *mxa) +winreg_s_OpenHKCR(void *arg, ndr_xa_t *mxa) { - struct winreg_OpenHKCR *param = arg; - ndr_hdid_t *id; - - if ((id = ndr_hdalloc(mxa, &winreg_hk)) == NULL) { - bzero(¶m->handle, sizeof (winreg_handle_t)); - param->status = ERROR_ACCESS_DENIED; - } else { - bcopy(id, ¶m->handle, sizeof (winreg_handle_t)); - param->status = ERROR_SUCCESS; - } + return (winreg_s_OpenHK(arg, mxa, "HKCR")); +} - return (NDR_DRC_OK); +static int +winreg_s_OpenHKCU(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKCU")); } -/* - * winreg_s_OpenHKLM - * - * This is a request to open the HKLM and get a handle. - * The client should treat the handle as an opaque object. - * - * Status: - * ERROR_SUCCESS Valid handle returned. - * ERROR_ACCESS_DENIED Unable to allocate a handle. - */ static int winreg_s_OpenHKLM(void *arg, ndr_xa_t *mxa) { - struct winreg_OpenHKLM *param = arg; - ndr_hdid_t *id; + return (winreg_s_OpenHK(arg, mxa, "HKLM")); +} - if ((id = ndr_hdalloc(mxa, &winreg_hklm)) == NULL) { - bzero(¶m->handle, sizeof (winreg_handle_t)); - param->status = ERROR_ACCESS_DENIED; - } else { - bcopy(id, ¶m->handle, sizeof (winreg_handle_t)); - param->status = ERROR_SUCCESS; - } +static int +winreg_s_OpenHKPD(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKPD")); +} - return (NDR_DRC_OK); +static int +winreg_s_OpenHKU(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKU")); +} + +static int +winreg_s_OpenHKCC(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKCC")); +} + +static int +winreg_s_OpenHKDD(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKDD")); +} + +static int +winreg_s_OpenHKPT(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKPT")); +} + +static int +winreg_s_OpenHKPN(void *arg, ndr_xa_t *mxa) +{ + return (winreg_s_OpenHK(arg, mxa, "HKPN")); } /* - * winreg_s_OpenHKUsers + * winreg_s_OpenHK * - * This is a request to get a HKUsers handle. I'm not sure we are - * ready to fully support this interface yet, mostly due to the need - * to support subsequent requests, but we may support enough now. It - * seems okay with regedt32. + * Common code to open root HKEYs. */ static int -winreg_s_OpenHKUsers(void *arg, ndr_xa_t *mxa) +winreg_s_OpenHK(void *arg, ndr_xa_t *mxa, const char *hkey) { - struct winreg_OpenHKUsers *param = arg; + struct winreg_OpenHKCR *param = arg; ndr_hdid_t *id; + char *dupkey; - if ((id = ndr_hdalloc(mxa, &winreg_hkuser)) == NULL) { + if ((dupkey = strdup(hkey)) == NULL) { + bzero(¶m->handle, sizeof (winreg_handle_t)); + param->status = ERROR_NOT_ENOUGH_MEMORY; + return (NDR_DRC_OK); + } + + if ((id = ndr_hdalloc(mxa, dupkey)) == NULL) { + free(dupkey); bzero(¶m->handle, sizeof (winreg_handle_t)); param->status = ERROR_ACCESS_DENIED; } else { @@ -275,6 +297,12 @@ winreg_s_Close(void *arg, ndr_xa_t *mxa) { struct winreg_Close *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; + ndr_handle_t *hd; + + if ((hd = ndr_hdlookup(mxa, id)) != NULL) { + free(hd->nh_data); + hd->nh_data = NULL; + } ndr_hdfree(mxa, id); @@ -294,6 +322,7 @@ winreg_s_CreateKey(void *arg, ndr_xa_t *mxa) ndr_handle_t *hd; winreg_subkey_t *key; char *subkey; + char *dupkey; DWORD *action; subkey = (char *)param->subkey.str; @@ -339,10 +368,17 @@ new_key: /* * Create a new key. */ - id = ndr_hdalloc(mxa, &winreg_hkkey); + if ((dupkey = strdup(subkey)) == NULL) { + bzero(param, sizeof (struct winreg_CreateKey)); + param->status = ERROR_NOT_ENOUGH_MEMORY; + return (NDR_DRC_OK); + } + + id = ndr_hdalloc(mxa, dupkey); key = malloc(sizeof (winreg_subkey_t)); if ((id == NULL) || (key == NULL)) { + free(dupkey); bzero(param, sizeof (struct winreg_CreateKey)); param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); @@ -369,6 +405,7 @@ winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa) { struct winreg_DeleteKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; + ndr_handle_t *hd; winreg_subkey_t *key; char *subkey; @@ -396,6 +433,13 @@ winreg_s_DeleteKey(void *arg, ndr_xa_t *mxa) list_remove(&winreg_keylist.kl_list, key); --winreg_keylist.kl_count; + + hd = ndr_hdlookup(mxa, &key->sk_handle); + if (hd != NULL) { + free(hd->nh_data); + hd->nh_data = NULL; + } + ndr_hdfree(mxa, &key->sk_handle); free(key); param->status = ERROR_SUCCESS; @@ -433,34 +477,14 @@ winreg_key_has_subkey(const char *subkey) return (B_FALSE); } -/* - * winreg_subkey_get_relative_name - * - * Each key contains one or more child keys, each called a subkey. - * For any specified key, its name MUST be unique for any other subkeys that - * have the same parent key. - * - * To accurately identify a given subkey within the key namespace, its fully - * qualified name (FQN) is used. The FQN MUST consist of the name of the subkey - * and the name of all of its parent keys all the way to the root of the tree. - * - * The "\" character MUST be used as a hierarchy separator to identify each key - * in the FQN and therefore MUST not be used in the name of a single key. - * For example, the subkey "MountedDevices" belongs to the subtree - * HKEY_LOCAL_MACHINE, as shown in the following example. - * - * HKEY_LOCAL_MACHINE -> SYSTEM -> MountedDevices - * - * The FQN for MountedDevices is HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices. - * The relative name of the subkey is "MountedDevices". The relative name - * MUST be used only for operations that are performed on its immediate parent - * key (SYSTEM in the previous example). - */ static char * -winreg_subkey_get_relative_name(const char *subkey) +winreg_enum_subkey(ndr_xa_t *mxa, const char *subkey, uint32_t index) { winreg_subkey_t *key; - char *value; + char *entry; + char *p; + int subkeylen; + int count = 0; if (subkey == NULL) return (NULL); @@ -468,14 +492,37 @@ winreg_subkey_get_relative_name(const char *subkey) if (list_is_empty(&winreg_keylist.kl_list)) return (NULL); - key = list_head(&winreg_keylist.kl_list); - do { - if (strcasecmp(subkey, key->sk_name) == 0) { - value = strrchr(key->sk_name, '\\'); - if (value != NULL) - return (++value); + subkeylen = strlen(subkey); + + for (key = list_head(&winreg_keylist.kl_list); + key != NULL; key = list_next(&winreg_keylist.kl_list, key)) { + if (strncasecmp(subkey, key->sk_name, subkeylen) == 0) { + p = key->sk_name + subkeylen; + + if ((*p != '\\') || (*p == '\0')) { + /* + * Not the same subkey or an exact match. + * We're looking for children of subkey. + */ + continue; + } + + ++p; + + if (count < index) { + ++count; + continue; + } + + if ((entry = NDR_STRDUP(mxa, p)) == NULL) + return (NULL); + + if ((p = strchr(entry, '\\')) != NULL) + *p = '\0'; + + return (entry); } - } while ((key = list_next(&winreg_keylist.kl_list, key)) != NULL); + } return (NULL); } @@ -501,45 +548,35 @@ winreg_s_EnumKey(void *arg, ndr_xa_t *mxa) { struct winreg_EnumKey *param = arg; ndr_hdid_t *id = (ndr_hdid_t *)¶m->handle; - winreg_string_t *name, *class; - char *value, *namep = NULL, *classp = NULL; - int slen = 0; + ndr_handle_t *hd; + char *subkey; + char *name = NULL; - if (ndr_hdlookup(mxa, id) == NULL) { - bzero(param, sizeof (struct winreg_EnumKey)); - param->status = ERROR_NO_MORE_ITEMS; - return (NDR_DRC_OK); - } + if ((hd = ndr_hdlookup(mxa, id)) != NULL) + name = hd->nh_data; - if (param->index > 0) { + if (hd == NULL || name == NULL) { bzero(param, sizeof (struct winreg_EnumKey)); param->status = ERROR_NO_MORE_ITEMS; return (NDR_DRC_OK); } - name = (winreg_string_t *)¶m->name_in; - class = (winreg_string_t *)¶m->class_in; - if (name->length != 0) - namep = (char *)name->str; - - if (class->length != 0) - classp = (char *)class->str; - - value = winreg_lookup_eventlog_registry(namep, classp); - if (value == NULL) { + subkey = winreg_enum_subkey(mxa, name, param->index); + if (subkey == NULL) { bzero(param, sizeof (struct winreg_EnumKey)); - param->status = ERROR_CANTREAD; + param->status = ERROR_NO_MORE_ITEMS; return (NDR_DRC_OK); } - slen = mts_wcequiv_strlen(value) + sizeof (mts_wchar_t); - param->name_out.length = slen; - param->name_out.allosize = slen; - if ((param->name_out.str = NDR_STRDUP(mxa, value)) == NULL) { + if (NDR_MSTRING(mxa, subkey, (ndr_mstring_t *)¶m->name_out) == -1) { bzero(param, sizeof (struct winreg_EnumKey)); param->status = ERROR_NOT_ENOUGH_MEMORY; return (NDR_DRC_OK); } + /* + * This request requires that the length includes the null. + */ + param->name_out.length = param->name_out.allosize; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); @@ -631,8 +668,9 @@ winreg_s_OpenKey(void *arg, ndr_xa_t *mxa) char *subkey = (char *)param->name.str; ndr_hdid_t *id = NULL; winreg_subkey_t *key; + char *dupkey; - if (list_is_empty(&winreg_keylist.kl_list)) { + if (subkey == NULL || list_is_empty(&winreg_keylist.kl_list)) { bzero(¶m->result_handle, sizeof (winreg_handle_t)); param->status = ERROR_FILE_NOT_FOUND; return (NDR_DRC_OK); @@ -641,10 +679,16 @@ winreg_s_OpenKey(void *arg, ndr_xa_t *mxa) key = list_head(&winreg_keylist.kl_list); do { if (strcasecmp(subkey, key->sk_name) == 0) { - if (key->sk_predefined == B_TRUE) - id = ndr_hdalloc(mxa, &winreg_hkkey); - else + if (key->sk_predefined == B_TRUE) { + if ((dupkey = strdup(subkey)) == NULL) + break; + + id = ndr_hdalloc(mxa, dupkey); + if (id == NULL) + free(dupkey); + } else { id = &key->sk_handle; + } if (id == NULL) break; @@ -790,22 +834,6 @@ winreg_lookup_value(const char *name) } /* - * winreg_lookup_eventlog_registry - * - * Return the subkey of the specified EventLog key. Decoding of - * class paramater not yet supported. - */ -/*ARGSUSED*/ -static char * -winreg_lookup_eventlog_registry(char *name, char *class) -{ - if (name == NULL) - return (winreg_subkey_get_relative_name(WINREG_LOGR_SYSTEMKEY)); - - return (winreg_subkey_get_relative_name(name)); -} - -/* * winreg_s_SetKeySec */ /*ARGSUSED*/ diff --git a/usr/src/lib/smbsrv/libsmb/Makefile.com b/usr/src/lib/smbsrv/libsmb/Makefile.com index 04182f247c..7889b4fc4f 100644 --- a/usr/src/lib/smbsrv/libsmb/Makefile.com +++ b/usr/src/lib/smbsrv/libsmb/Makefile.com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -28,6 +28,7 @@ VERS= .1 OBJS_SHARED = \ smb_common_door_decode.o \ + smb_inet.o \ smb_match.o \ smb_msgbuf.o \ smb_native.o \ @@ -62,6 +63,7 @@ OBJS_COMMON = \ smb_nicmon.o \ smb_pwdutil.o \ smb_privilege.o \ + smb_sam.o \ smb_scfutil.o \ smb_util.o \ smb_wksids.o diff --git a/usr/src/lib/smbsrv/libsmb/common/libsmb.h b/usr/src/lib/smbsrv/libsmb/common/libsmb.h index cfb848f9b9..37fb0756cc 100644 --- a/usr/src/lib/smbsrv/libsmb/common/libsmb.h +++ b/usr/src/lib/smbsrv/libsmb/common/libsmb.h @@ -34,6 +34,7 @@ extern "C" { #include <sys/list.h> #include <arpa/inet.h> #include <net/if.h> +#include <inet/tcp.h> #include <netdb.h> #include <stdlib.h> #include <libscf.h> @@ -140,6 +141,7 @@ typedef enum { SMB_CI_KPASSWD_DOMAIN, SMB_CI_KPASSWD_SEQNUM, SMB_CI_NETLOGON_SEQNUM, + SMB_CI_IPV6_ENABLE, SMB_CI_MAX } smb_cfg_id_t; @@ -183,7 +185,7 @@ extern int smb_config_get_secmode(void); extern int smb_config_set_secmode(int); extern int smb_config_set_idmap_domain(char *); extern int smb_config_refresh_idmap(void); - +extern int smb_config_getip(smb_cfg_id_t, smb_inaddr_t *); extern void smb_load_kconfig(smb_kmod_cfg_t *kcfg); extern uint32_t smb_crc_gen(uint8_t *, size_t); @@ -220,7 +222,7 @@ extern void smb_config_getdomaininfo(char *domain, char *fqdn, char *forest, char *guid); extern void smb_config_setdomaininfo(char *domain, char *fqdn, char *forest, char *guid); -extern uint32_t smb_get_dcinfo(char *, uint32_t, uint32_t *); +extern uint32_t smb_get_dcinfo(char *, uint32_t, smb_inaddr_t *); /* * buffer context structure. This is used to keep track of the buffer @@ -270,10 +272,10 @@ extern int smb_getsamaccount(char *, size_t); extern smb_sid_t *smb_getdomainsid(void); -extern int smb_get_nameservers(struct in_addr *, int); +extern int smb_get_nameservers(smb_inaddr_t *, int); extern void smb_tonetbiosname(char *, char *, char); -extern int smb_chk_hostaccess(ipaddr_t, char *); +extern int smb_chk_hostaccess(smb_inaddr_t *, char *); void smb_trace(const char *s); void smb_tracef(const char *fmt, ...); @@ -446,7 +448,6 @@ extern smb_passwd_t *smb_pwd_getpwnam(const char *, smb_passwd_t *); extern smb_passwd_t *smb_pwd_getpwuid(uid_t, smb_passwd_t *); extern int smb_pwd_setpasswd(const char *, const char *); extern int smb_pwd_setcntl(const char *, int); -extern int smb_pwd_num(void); extern int smb_pwd_iteropen(smb_pwditer_t *); extern smb_luser_t *smb_pwd_iterate(smb_pwditer_t *); @@ -637,8 +638,6 @@ int smb_lgrp_add_member(char *, smb_sid_t *, uint16_t); int smb_lgrp_del_member(char *, smb_sid_t *, uint16_t); int smb_lgrp_getbyname(char *, smb_group_t *); int smb_lgrp_getbyrid(uint32_t, smb_gdomain_t, smb_group_t *); -int smb_lgrp_numbydomain(smb_gdomain_t, int *); -int smb_lgrp_numbymember(smb_sid_t *, int *); void smb_lgrp_free(smb_group_t *); boolean_t smb_lgrp_is_member(smb_group_t *, smb_sid_t *); char *smb_lgrp_strerror(int); @@ -702,7 +701,7 @@ typedef struct { char nic_nbname[NETBIOS_NAME_SZ]; char nic_cmnt[SMB_PI_MAX_COMMENT]; char nic_ifname[LIFNAMSIZ]; - uint32_t nic_ip; + smb_inaddr_t nic_ip; uint32_t nic_mask; uint32_t nic_bcast; uint32_t nic_smbflags; @@ -723,7 +722,7 @@ int smb_nic_addhost(const char *, const char *, int, const char **); int smb_nic_delhost(const char *); int smb_nic_getfirst(smb_niciter_t *); int smb_nic_getnext(smb_niciter_t *); -boolean_t smb_nic_exists(uint32_t, boolean_t); +boolean_t smb_nic_exists(smb_inaddr_t *, boolean_t); /* NIC Monitoring functions */ int smb_nicmon_start(const char *); @@ -764,12 +763,31 @@ typedef struct smb_wka { */ int smb_wka_init(void); void smb_wka_fini(void); -smb_wka_t *smb_wka_lookup(char *); -char *smb_wka_lookup_sid(smb_sid_t *, uint16_t *); -smb_sid_t *smb_wka_lookup_name(char *, uint16_t *); -char *smb_wka_lookup_domain(char *); -boolean_t smb_wka_is_wellknown(char *); +smb_wka_t *smb_wka_lookup_name(char *); +smb_wka_t *smb_wka_lookup_sid(smb_sid_t *); +smb_sid_t *smb_wka_get_sid(char *); char *smb_wka_get_domain(int); +uint32_t smb_wka_token_groups(boolean_t, smb_ids_t *); + +/* + * In memory account representation + */ +typedef struct smb_account { + char *a_name; + char *a_domain; + uint16_t a_type; + smb_sid_t *a_sid; + smb_sid_t *a_domsid; + uint32_t a_rid; +} smb_account_t; + +uint32_t smb_sam_lookup_name(char *, char *, uint16_t, smb_account_t *); +uint32_t smb_sam_lookup_sid(smb_sid_t *, smb_account_t *); +int smb_sam_usr_cnt(void); +uint32_t smb_sam_usr_groups(smb_sid_t *, smb_ids_t *); +int smb_sam_grp_cnt(nt_domain_type_t); +void smb_account_free(smb_account_t *); +boolean_t smb_account_validate(smb_account_t *); #ifdef __cplusplus } diff --git a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers index df13aff630..2fd070e53d 100644 --- a/usr/src/lib/smbsrv/libsmb/common/mapfile-vers +++ b/usr/src/lib/smbsrv/libsmb/common/mapfile-vers @@ -87,6 +87,8 @@ SUNWprivate { oemstounicodes; rand_hash; randomize; + smb_account_free; + smb_account_validate; smb_auth_DES; smb_auth_gen_session_key; smb_auth_hmac_md5; @@ -103,6 +105,7 @@ SUNWprivate { smb_config_get_secmode; smb_config_getbool; smb_config_getdomaininfo; + smb_config_getip; smb_config_getname; smb_config_getnum; smb_config_getstr; @@ -183,7 +186,11 @@ SUNWprivate { smb_idmap_restart; smb_idmap_start; smb_idmap_stop; + smb_ids_free; smb_ishostname; + smb_inet_equal; + smb_inet_iszero; + smb_inet_ntop; smb_join; smb_lgrp_add; smb_lgrp_add_member; @@ -198,8 +205,6 @@ SUNWprivate { smb_lgrp_iterate; smb_lgrp_iterclose; smb_lgrp_iteropen; - smb_lgrp_numbydomain; - smb_lgrp_numbymember; smb_lgrp_rename; smb_lgrp_setcmnt; smb_lgrp_setpriv; @@ -267,9 +272,13 @@ SUNWprivate { smb_pwd_iterate = AUXILIARY libsmb_pwd.so; smb_pwd_iterclose = AUXILIARY libsmb_pwd.so; smb_pwd_iteropen = AUXILIARY libsmb_pwd.so; - smb_pwd_num = AUXILIARY libsmb_pwd.so; smb_pwd_setcntl = AUXILIARY libsmb_pwd.so; smb_pwd_setpasswd = AUXILIARY libsmb_pwd.so; + smb_sam_lookup_name; + smb_sam_lookup_sid; + smb_sam_grp_cnt; + smb_sam_usr_cnt; + smb_sam_usr_groups; smb_setdomainprops; smb_sid_cmp; smb_sid_dup; @@ -294,12 +303,11 @@ SUNWprivate { smb_update_netlogon_seqnum; smb_wka_fini; smb_wka_get_domain; + smb_wka_get_sid; smb_wka_init; - smb_wka_is_wellknown; - smb_wka_lookup; - smb_wka_lookup_domain; smb_wka_lookup_name; smb_wka_lookup_sid; + smb_wka_token_groups; smbnative_lm_value; smbnative_os_value; smbnative_pdc_value; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c index 1e3215544f..c4153b32a1 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_api_door_calls.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -249,7 +249,7 @@ smb_join(smb_joininfo_t *jdi) * domain information. */ uint32_t -smb_get_dcinfo(char *namebuf, uint32_t namebuflen, uint32_t *ipaddr) +smb_get_dcinfo(char *namebuf, uint32_t namebuflen, smb_inaddr_t *ipaddr) { door_arg_t arg; char *buf; @@ -285,7 +285,7 @@ smb_get_dcinfo(char *namebuf, uint32_t namebuflen, uint32_t *ipaddr) if (srvname) { (void) strlcpy(namebuf, srvname, namebuflen); if ((h = smb_gethostbyname(srvname, &error_num)) == NULL) { - *ipaddr = 0; + bzero(ipaddr, sizeof (smb_inaddr_t)); } else { (void) memcpy(ipaddr, h->h_addr, h->h_length); freehostent(h); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c index 41ae235675..a9677209a3 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_cfg.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -130,7 +130,8 @@ static smb_cfg_param_t smb_cfg_table[] = {SMB_CI_KPASSWD_SEQNUM, "kpasswd_seqnum", SCF_TYPE_INTEGER, 0}, {SMB_CI_NETLOGON_SEQNUM, "netlogon_seqnum", SCF_TYPE_INTEGER, - 0} + 0}, + {SMB_CI_IPV6_ENABLE, "ipv6_enable", SCF_TYPE_BOOLEAN, 0} /* SMB_CI_MAX */ }; @@ -391,6 +392,24 @@ error: return (rc); } +int +smb_config_getip(smb_cfg_id_t sc_id, smb_inaddr_t *ipaddr) +{ + int rc; + char ipstr[INET6_ADDRSTRLEN]; + + rc = smb_config_getstr(sc_id, ipstr, sizeof (ipstr)); + if (rc == SMBD_SMF_OK) { + rc = inet_pton(AF_INET, ipstr, ipaddr); + if (rc == 0) { + rc = inet_pton(AF_INET6, ipstr, ipaddr); + if (rc == 0) + bzero(ipaddr, sizeof (smb_inaddr_t)); + } + } + return (rc); +} + /* * smb_config_getnum * diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_domain.c b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c index 4438b3f426..a9b7c8692e 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_domain.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_domain.c @@ -293,11 +293,20 @@ nt_domain_xlat_type_name(char *type_name) nt_domain_t * nt_domain_lookup_name(char *domain_name) { + char nbname[MAXHOSTNAMELEN]; nt_domain_t *domain = nt_domain_list; + char *p; + + if (domain_name == NULL || *domain_name == '\0') + return (NULL); + + (void) strlcpy(nbname, domain_name, sizeof (nbname)); + if ((p = strchr(nbname, '.')) != NULL) + *p = '\0'; (void) rw_rdlock(&nt_domain_lock); while (domain) { - if (utf8_strcasecmp(domain->name, domain_name) == 0) + if (utf8_strcasecmp(domain->name, nbname) == 0) break; domain = domain->next; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c index 39c5e7746e..9bb0e720cc 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_idmap.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -285,18 +285,12 @@ smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, idmap_stat stat; int flag = 0; - if (!idmaph || !sim || !sid) + if (idmaph == NULL || sim == NULL || sid == NULL) return (IDMAP_ERR_ARG); - tmpsid = smb_sid_dup(sid); - if (!tmpsid) + if ((tmpsid = smb_sid_split(sid, &sim->sim_rid)) == NULL) return (IDMAP_ERR_MEMORY); - if (smb_sid_split(tmpsid, &sim->sim_rid) != 0) { - smb_sid_free(tmpsid); - return (IDMAP_ERR_ARG); - } - smb_sid_tostr(tmpsid, sidstr); sim->sim_domsid = sidstr; smb_sid_free(tmpsid); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_info.c b/usr/src/lib/smbsrv/libsmb/common/smb_info.c index ad1eb7ceda..2c7ff42b3e 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_info.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_info.c @@ -67,6 +67,7 @@ smb_load_kconfig(smb_kmod_cfg_t *kcfg) kcfg->skc_restrict_anon = smb_config_getbool(SMB_CI_RESTRICT_ANON); kcfg->skc_signing_enable = smb_config_getbool(SMB_CI_SIGNING_ENABLE); kcfg->skc_signing_required = smb_config_getbool(SMB_CI_SIGNING_REQD); + kcfg->skc_ipv6_enable = smb_config_getbool(SMB_CI_IPV6_ENABLE); kcfg->skc_oplock_enable = smb_config_getbool(SMB_CI_OPLOCK_ENABLE); kcfg->skc_sync_enable = smb_config_getbool(SMB_CI_SYNC_ENABLE); kcfg->skc_secmode = smb_config_get_secmode(); @@ -448,11 +449,12 @@ smb_tonetbiosname(char *name, char *nb_name, char suffix) } int -smb_get_nameservers(struct in_addr *ips, int sz) +smb_get_nameservers(smb_inaddr_t *ips, int sz) { union res_sockaddr_union set[MAXNS]; int i, cnt; struct __res_state res_state; + char ipstr[INET6_ADDRSTRLEN]; if (ips == NULL) return (0); @@ -465,15 +467,23 @@ smb_get_nameservers(struct in_addr *ips, int sz) for (i = 0; i < cnt; i++) { if (i >= sz) break; - ips[i] = set[i].sin.sin_addr; - syslog(LOG_DEBUG, "NS Found %s name server\n", - inet_ntoa(ips[i])); + ips[i].a_family = AF_INET; + bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv4, INADDRSZ); + if (inet_ntop(AF_INET, &ips[i].a_ipv4, ipstr, + INET_ADDRSTRLEN)) { + syslog(LOG_DEBUG, "Found %s name server\n", ipstr); + continue; + } + ips[i].a_family = AF_INET6; + bcopy(&set[i].sin.sin_addr, &ips[i].a_ipv6, IPV6_ADDR_LEN); + if (inet_ntop(AF_INET6, &ips[i].a_ipv6, ipstr, + INET6_ADDRSTRLEN)) { + syslog(LOG_DEBUG, "Found %s name server\n", ipstr); + } } - syslog(LOG_DEBUG, "NS Found %d name servers\n", i); res_ndestroy(&res_state); return (i); } - /* * smb_gethostbyname * @@ -492,7 +502,8 @@ smb_gethostbyname(const char *name, int *err_num) struct hostent *h; h = getipnodebyname(name, AF_INET, 0, err_num); - + if ((h == NULL) || h->h_length != INADDRSZ) + h = getipnodebyname(name, AF_INET6, AI_DEFAULT, err_num); return (h); } diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c index 220cdd1b38..c92f00e3c9 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_lgrp.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -216,7 +216,7 @@ smb_lgrp_add(char *gname, char *cmnt) grp.sg_name = utf8_strlwr(gname); grp.sg_cmnt = cmnt; - wka = smb_wka_lookup(gname); + wka = smb_wka_lookup_name(gname); if (wka == NULL) { if ((pxgrp = getgrnam(gname)) == NULL) return (SMB_LGRP_NOT_FOUND); @@ -289,11 +289,11 @@ smb_lgrp_rename(char *gname, char *new_gname) return (SMB_LGRP_SUCCESS); /* Cannot rename well-known groups */ - if (smb_wka_is_wellknown(gname)) + if (smb_wka_lookup_name(gname) != NULL) return (SMB_LGRP_WKSID); /* Cannot rename to a well-known groups */ - if (smb_wka_is_wellknown(new_gname)) + if (smb_wka_lookup_name(new_gname) != NULL) return (SMB_LGRP_WKSID); grp.sg_name = new_gname; @@ -321,7 +321,7 @@ smb_lgrp_delete(char *gname) return (SMB_LGRP_INVALID_NAME); /* Cannot remove a built-in group */ - if (smb_wka_is_wellknown(gname)) + if (smb_wka_lookup_name(gname) != NULL) return (SMB_LGRP_WKSID); db = smb_lgrp_db_open(SMB_LGRP_DB_ORW); @@ -619,33 +619,6 @@ smb_lgrp_numbydomain(smb_gdomain_t dom_type, int *count) } /* - * smb_lgrp_numbydomain - * - * Returns the number of groups which have the given SID - * as a member. - */ -int -smb_lgrp_numbymember(smb_sid_t *msid, int *count) -{ - smb_giter_t gi; - smb_group_t grp; - int rc; - - *count = 0; - rc = smb_lgrp_iteropen(&gi); - if (rc != SMB_LGRP_SUCCESS) - return (rc); - - while (smb_lgrp_iterate(&gi, &grp) == SMB_LGRP_SUCCESS) { - if (smb_lgrp_is_member(&grp, msid)) - (*count)++; - smb_lgrp_free(&grp); - } - smb_lgrp_iterclose(&gi); - return (SMB_LGRP_SUCCESS); -} - -/* * smb_lgrp_free * * Frees the allocated memory for the fields of the given @@ -935,7 +908,7 @@ smb_lgrp_start(void) ngrp = sizeof (supported_bg) / sizeof (supported_bg[0]); for (i = 0; i < ngrp; i++) { - wka = smb_wka_lookup(supported_bg[i]); + wka = smb_wka_lookup_name(supported_bg[i]); if (wka == NULL) continue; rc = smb_lgrp_add(wka->wka_name, wka->wka_desc); @@ -1636,11 +1609,9 @@ smb_lgrp_dtbl_getidx(sqlite *db, smb_sid_t *sid, uint16_t sid_type, return (SMB_LGRP_SUCCESS); } - dom_sid = smb_sid_dup(sid); - if (dom_sid == NULL) + if ((dom_sid = smb_sid_split(sid, rid)) == NULL) return (SMB_LGRP_NO_MEMORY); - (void) smb_sid_split(dom_sid, rid); smb_sid_tostr(dom_sid, sidstr); free(dom_sid); diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_nic.c b/usr/src/lib/smbsrv/libsmb/common/smb_nic.c index 82ea440ced..6646883ab1 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_nic.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_nic.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -124,10 +124,13 @@ static int smb_nic_dbaddhost(const char *, const char *, char *); static int smb_nic_dbdelhost(const char *); static int smb_nic_dbsetinfo(sqlite *); -static int smb_nic_getinfo(char *, smb_nic_t *); +static int smb_nic_getinfo(char *, smb_nic_t *, int); static boolean_t smb_nic_nbt_exclude(const smb_nic_t *, const char **, int); static int smb_nic_nbt_get_exclude_list(char *, char **, int); +static void smb_close_sockets(int, int); +static boolean_t smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp); + /* This is the list we will monitor */ static smb_niclist_t smb_niclist; @@ -265,18 +268,11 @@ smb_nic_getnext(smb_niciter_t *ni) return (rc); } -/* - * smb_nic_exists - * - * Check to see if there's a NIC with the given IP address - * in the list. Subnet mask will be applied when comparing the - * IPs if the use_mask arg is true. - */ boolean_t -smb_nic_exists(uint32_t ipaddr, boolean_t use_mask) +smb_nic_exists(smb_inaddr_t *ipaddr, boolean_t use_mask) { smb_nic_t *cfg; - uint32_t mask = 0xFFFFFFFF; + uint32_t mask = 0; int i; (void) rw_rdlock(&smb_niclist.nl_rwl); @@ -285,15 +281,12 @@ smb_nic_exists(uint32_t ipaddr, boolean_t use_mask) cfg = &smb_niclist.nl_nics[i]; if (use_mask) mask = cfg->nic_mask; - - if ((ipaddr & mask) == (cfg->nic_ip & mask)) { + if (smb_inet_equal(ipaddr, &cfg->nic_ip, mask)) { (void) rw_unlock(&smb_niclist.nl_rwl); return (B_TRUE); } } - (void) rw_unlock(&smb_niclist.nl_rwl); - return (B_FALSE); } @@ -425,8 +418,12 @@ smb_nic_list_create(void) do { for (i = 0; i < iflist->if_num; i++) { ifname = iflist->if_names[i]; - if (smb_nic_getinfo(ifname, nc) < 0) - continue; + if (smb_nic_getinfo(ifname, nc, AF_INET) < 0) { + if (smb_nic_getinfo(ifname, nc, + AF_INET6) < 0) { + continue; + } + } (void) strlcpy(nc->nic_host, iflist->if_host, sizeof (nc->nic_host)); @@ -460,19 +457,16 @@ smb_nic_list_destroy(void) smb_niclist.nl_cnt = 0; } -/* - * smb_nic_getinfo - * - * Get IP info and more for the given interface - */ static int -smb_nic_getinfo(char *interface, smb_nic_t *nc) +smb_nic_getinfo(char *interface, smb_nic_t *nc, int family) { struct lifreq lifrr; - struct sockaddr_in *sa; int s; + boolean_t isv6; + struct sockaddr_in6 *sin6; + struct sockaddr_in *sin; - if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) { + if ((s = socket(family, SOCK_DGRAM, IPPROTO_IP)) < 0) { return (-1); } @@ -481,28 +475,36 @@ smb_nic_getinfo(char *interface, smb_nic_t *nc) (void) close(s); return (-1); } - sa = (struct sockaddr_in *)&lifrr.lifr_addr; - nc->nic_ip = (uint32_t)sa->sin_addr.s_addr; - - if (nc->nic_ip == 0) { - (void) close(s); - return (-1); + isv6 = (lifrr.lifr_addr.ss_family == AF_INET6); + if (isv6) { + sin6 = (struct sockaddr_in6 *)(&lifrr.lifr_addr); + nc->nic_ip.a_ipv6 = sin6->sin6_addr; + nc->nic_ip.a_family = AF_INET6; + } else { + sin = (struct sockaddr_in *)(&lifrr.lifr_addr); + nc->nic_ip.a_ipv4 = (in_addr_t)(sin->sin_addr.s_addr); + nc->nic_ip.a_family = AF_INET; } - - if (ioctl(s, SIOCGLIFBRDADDR, &lifrr) < 0) { + if (smb_inet_iszero(&nc->nic_ip)) { (void) close(s); return (-1); } - sa = (struct sockaddr_in *)&lifrr.lifr_broadaddr; - nc->nic_bcast = (uint32_t)sa->sin_addr.s_addr; + /* there is no broadcast or netmask for v6 */ + if (!isv6) { + if (ioctl(s, SIOCGLIFBRDADDR, &lifrr) < 0) { + (void) close(s); + return (-1); + } + sin = (struct sockaddr_in *)&lifrr.lifr_broadaddr; + nc->nic_bcast = (uint32_t)sin->sin_addr.s_addr; - if (ioctl(s, SIOCGLIFNETMASK, &lifrr) < 0) { - (void) close(s); - return (-1); + if (ioctl(s, SIOCGLIFNETMASK, &lifrr) < 0) { + (void) close(s); + return (-1); + } + sin = (struct sockaddr_in *)&lifrr.lifr_addr; + nc->nic_mask = (uint32_t)sin->sin_addr.s_addr; } - sa = (struct sockaddr_in *)&lifrr.lifr_addr; - nc->nic_mask = (uint32_t)sa->sin_addr.s_addr; - if (ioctl(s, SIOCGLIFFLAGS, &lifrr) < 0) { (void) close(s); return (-1); @@ -564,6 +566,15 @@ smb_nic_hlist_destroy(smb_hosts_t *hlist) list_destroy(&hlist->h_list); } +static void +smb_close_sockets(int s4, int s6) +{ + if (s4) + (void) close(s4); + if (s6) + (void) close(s6); +} + /* * smb_nic_hlist_sysget * @@ -574,13 +585,14 @@ static int smb_nic_hlist_sysget(smb_hosts_t *hlist) { smb_hostifs_t *iflist; - struct ifconf ifc; - struct ifreq ifr; - struct ifreq *ifrp; + struct lifconf lifc; + struct lifreq lifrl; + struct lifreq *lifrp; char *ifname; int ifnum; int i; - int s; + int s4, s6; + struct lifnum lifn; iflist = malloc(sizeof (smb_hostifs_t)); if (iflist == NULL) @@ -596,77 +608,102 @@ smb_nic_hlist_sysget(smb_hosts_t *hlist) (void) smb_config_getstr(SMB_CI_SYS_CMNT, iflist->if_cmnt, sizeof (iflist->if_cmnt)); - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { free(iflist); return (-1); } + s6 = socket(AF_INET6, SOCK_DGRAM, 0); - if (ioctl(s, SIOCGIFNUM, (char *)&ifnum) < 0) { - (void) close(s); + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = 0; + if (ioctl(s4, SIOCGLIFNUM, (char *)&lifn) < 0) { + smb_close_sockets(s4, s6); free(iflist); + syslog(LOG_ERR, "hlist_sysget: SIOCGLIFNUM errno=%d", errno); return (-1); } - ifc.ifc_len = ifnum * sizeof (struct ifreq); - ifc.ifc_buf = malloc(ifc.ifc_len); - if (ifc.ifc_buf == NULL) { - (void) close(s); + lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); + lifc.lifc_buf = malloc(lifc.lifc_len); + if (lifc.lifc_buf == NULL) { + smb_close_sockets(s4, s6); free(iflist); return (-1); } - bzero(ifc.ifc_buf, ifc.ifc_len); + bzero(lifc.lifc_buf, lifc.lifc_len); + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_flags = 0; - if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { - (void) close(s); + if (ioctl(s4, SIOCGLIFCONF, (char *)&lifc) < 0) { + smb_close_sockets(s4, s6); free(iflist); - free(ifc.ifc_buf); + free(lifc.lifc_buf); return (-1); } - ifrp = ifc.ifc_req; - ifnum = ifc.ifc_len / sizeof (struct ifreq); + lifrp = lifc.lifc_req; + ifnum = lifc.lifc_len / sizeof (struct lifreq); + hlist->h_num = 0; + for (i = 0; i < ifnum; i++, lifrp++) { - for (i = 0; i < ifnum; i++, ifrp++) { + if ((iflist->if_num > 0) && smb_duplicate_nic(iflist, lifrp)) + continue; /* * Get the flags so that we can skip the loopback interface */ - (void) memset(&ifr, 0, sizeof (ifr)); - (void) strlcpy(ifr.ifr_name, ifrp->ifr_name, - sizeof (ifr.ifr_name)); - - if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { - (void) close(s); - free(ifc.ifc_buf); - smb_nic_iflist_destroy(iflist); - return (-1); + (void) memset(&lifrl, 0, sizeof (lifrl)); + (void) strlcpy(lifrl.lifr_name, lifrp->lifr_name, + sizeof (lifrl.lifr_name)); + + if (ioctl(s4, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0) { + if ((s6 < 0) || + (ioctl(s6, SIOCGLIFFLAGS, (caddr_t)&lifrl) < 0)) { + smb_close_sockets(s4, s6); + free(lifc.lifc_buf); + smb_nic_iflist_destroy(iflist); + return (-1); + } } - - if (ifr.ifr_flags & IFF_LOOPBACK) + if (lifrl.lifr_flags & IFF_LOOPBACK) { continue; + } - if ((ifr.ifr_flags & IFF_UP) == 0) + if ((lifrl.lifr_flags & IFF_UP) == 0) { continue; - - ifname = strdup(ifrp->ifr_name); + } + ifname = strdup(lifrp->lifr_name); if (ifname == NULL) { - (void) close(s); - free(ifc.ifc_buf); + smb_close_sockets(s4, s6); + free(lifc.lifc_buf); smb_nic_iflist_destroy(iflist); return (-1); } iflist->if_names[iflist->if_num++] = ifname; } - - (void) close(s); - free(ifc.ifc_buf); - - hlist->h_num = 1; hlist->h_ifnum = iflist->if_num; + hlist->h_num = 1; + smb_close_sockets(s4, s6); + free(lifc.lifc_buf); list_insert_tail(&hlist->h_list, iflist); return (0); } +static boolean_t +smb_duplicate_nic(smb_hostifs_t *iflist, struct lifreq *lifrp) +{ + int j; + /* + * throw out duplicate names + */ + for (j = 0; j < iflist->if_num; j++) { + if (strcmp(iflist->if_names[j], + lifrp->lifr_name) == 0) + return (B_TRUE); + } + return (B_FALSE); +} + static int smb_nic_hlist_dbget(smb_hosts_t *hlist) { diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_sam.c b/usr/src/lib/smbsrv/libsmb/common/smb_sam.c new file mode 100644 index 0000000000..fc6f3791bc --- /dev/null +++ b/usr/src/lib/smbsrv/libsmb/common/smb_sam.c @@ -0,0 +1,385 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <strings.h> +#include <smbsrv/libsmb.h> + +extern int smb_pwd_num(void); +extern int smb_lgrp_numbydomain(smb_gdomain_t, int *); + +static uint32_t smb_sam_lookup_user(char *, smb_sid_t **); +static uint32_t smb_sam_lookup_group(char *, smb_sid_t **); + +/* + * Looks up the given name in local account databases: + * + * SMB Local users are looked up in /var/smb/smbpasswd + * SMB Local groups are looked up in /var/smb/smbgroup.db + * + * If the account is found, its information is populated + * in the passed smb_account_t structure. Caller must free + * allocated memories by calling smb_account_free() upon + * successful return. + * + * The type of account is specified by 'type', which can be user, + * alias (local group) or unknown. If the caller doesn't know + * whether the name is a user or group name then SidTypeUnknown + * should be passed. + * + * If a local user and group have the same name, the user will + * always be picked. Note that this situation cannot happen on + * Windows systems. + * + * If a SMB local user/group is found but it turns out that + * it'll be mapped to a domain user/group the lookup is considered + * failed and NT_STATUS_NONE_MAPPED is returned. + * + * Return status: + * + * NT_STATUS_NOT_FOUND This is not a local account + * NT_STATUS_NONE_MAPPED It's a local account but cannot be + * translated. + * other error status codes. + */ +uint32_t +smb_sam_lookup_name(char *domain, char *name, uint16_t type, + smb_account_t *account) +{ + char hostname[MAXHOSTNAMELEN]; + smb_sid_t *sid; + uint32_t status; + + bzero(account, sizeof (smb_account_t)); + (void) smb_getnetbiosname(hostname, sizeof (hostname)); + + if (domain != NULL) { + if (!smb_ishostname(domain)) + return (NT_STATUS_NOT_FOUND); + + /* Only Netbios hostname is accepted */ + if (utf8_strcasecmp(domain, hostname) != 0) + return (NT_STATUS_NONE_MAPPED); + } + + switch (type) { + case SidTypeUser: + status = smb_sam_lookup_user(name, &sid); + if (status != NT_STATUS_SUCCESS) + return (status); + break; + + case SidTypeAlias: + status = smb_sam_lookup_group(name, &sid); + if (status != NT_STATUS_SUCCESS) + return (status); + break; + + case SidTypeUnknown: + type = SidTypeUser; + status = smb_sam_lookup_user(name, &sid); + if (status == NT_STATUS_SUCCESS) + break; + + if (status == NT_STATUS_NONE_MAPPED) + return (status); + + type = SidTypeAlias; + status = smb_sam_lookup_group(name, &sid); + if (status != NT_STATUS_SUCCESS) + return (status); + break; + + default: + return (NT_STATUS_INVALID_PARAMETER); + } + + account->a_name = strdup(name); + account->a_sid = sid; + account->a_domain = strdup(hostname); + account->a_domsid = smb_sid_split(sid, &account->a_rid); + account->a_type = type; + + if (!smb_account_validate(account)) { + smb_account_free(account); + return (NT_STATUS_NO_MEMORY); + } + + return (NT_STATUS_SUCCESS); +} + +/* + * Looks up the given SID in local account databases: + * + * SMB Local users are looked up in /var/smb/smbpasswd + * SMB Local groups are looked up in /var/smb/smbgroup.db + * + * If the account is found, its information is populated + * in the passed smb_account_t structure. Caller must free + * allocated memories by calling smb_account_free() upon + * successful return. + * + * Return status: + * + * NT_STATUS_NOT_FOUND This is not a local account + * NT_STATUS_NONE_MAPPED It's a local account but cannot be + * translated. + * other error status codes. + */ +uint32_t +smb_sam_lookup_sid(smb_sid_t *sid, smb_account_t *account) +{ + char hostname[MAXHOSTNAMELEN]; + smb_passwd_t smbpw; + smb_group_t grp; + uint32_t rid; + uid_t id; + int id_type; + int rc; + + bzero(account, sizeof (smb_account_t)); + + if (!smb_sid_islocal(sid)) + return (NT_STATUS_NOT_FOUND); + + id_type = SMB_IDMAP_UNKNOWN; + if (smb_idmap_getid(sid, &id, &id_type) != IDMAP_SUCCESS) + return (NT_STATUS_NONE_MAPPED); + + switch (id_type) { + case SMB_IDMAP_USER: + account->a_type = SidTypeUser; + if (smb_pwd_getpwuid(id, &smbpw) == NULL) + return (NT_STATUS_NO_SUCH_USER); + + account->a_name = strdup(smbpw.pw_name); + break; + + case SMB_IDMAP_GROUP: + account->a_type = SidTypeAlias; + (void) smb_sid_getrid(sid, &rid); + rc = smb_lgrp_getbyrid(rid, SMB_LGRP_LOCAL, &grp); + if (rc != SMB_LGRP_SUCCESS) + return (NT_STATUS_NO_SUCH_ALIAS); + + account->a_name = strdup(grp.sg_name); + smb_lgrp_free(&grp); + break; + + default: + return (NT_STATUS_NONE_MAPPED); + } + + if (smb_getnetbiosname(hostname, MAXHOSTNAMELEN) == 0) + account->a_domain = strdup(hostname); + account->a_sid = smb_sid_dup(sid); + account->a_domsid = smb_sid_split(sid, &account->a_rid); + + if (!smb_account_validate(account)) { + smb_account_free(account); + return (NT_STATUS_NO_MEMORY); + } + + return (NT_STATUS_SUCCESS); +} + +/* + * Returns number of SMB users, i.e. users who have entry + * in /var/smb/smbpasswd + */ +int +smb_sam_usr_cnt(void) +{ + return (smb_pwd_num()); +} + +/* + * Returns a list of local groups which the given user is + * their member. A pointer to an array of smb_ids_t + * structure is returned which must be freed by caller. + */ +uint32_t +smb_sam_usr_groups(smb_sid_t *user_sid, smb_ids_t *gids) +{ + smb_id_t *ids; + smb_giter_t gi; + smb_group_t lgrp; + int total_cnt, gcnt; + + gcnt = 0; + if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) + return (NT_STATUS_INTERNAL_ERROR); + + while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { + if (smb_lgrp_is_member(&lgrp, user_sid)) + gcnt++; + smb_lgrp_free(&lgrp); + } + smb_lgrp_iterclose(&gi); + + if (gcnt == 0) + return (NT_STATUS_SUCCESS); + + total_cnt = gids->i_cnt + gcnt; + gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); + if (gids->i_ids == NULL) + return (NT_STATUS_NO_MEMORY); + + if (smb_lgrp_iteropen(&gi) != SMB_LGRP_SUCCESS) + return (NT_STATUS_INTERNAL_ERROR); + + ids = gids->i_ids + gids->i_cnt; + while (smb_lgrp_iterate(&gi, &lgrp) == SMB_LGRP_SUCCESS) { + if (gcnt == 0) { + smb_lgrp_free(&lgrp); + break; + } + if (smb_lgrp_is_member(&lgrp, user_sid)) { + ids->i_sid = smb_sid_dup(lgrp.sg_id.gs_sid); + if (ids->i_sid == NULL) { + smb_lgrp_free(&lgrp); + return (NT_STATUS_NO_MEMORY); + } + ids->i_attrs = lgrp.sg_attr; + gids->i_cnt++; + gcnt--; + ids++; + } + smb_lgrp_free(&lgrp); + } + smb_lgrp_iterclose(&gi); + + return (NT_STATUS_SUCCESS); +} + +/* + * Returns the number of built-in or local groups stored + * in /var/smb/smbgroup.db + */ +int +smb_sam_grp_cnt(nt_domain_type_t dtype) +{ + int grpcnt; + int rc; + + switch (dtype) { + case NT_DOMAIN_BUILTIN: + rc = smb_lgrp_numbydomain(SMB_LGRP_BUILTIN, &grpcnt); + break; + + case NT_DOMAIN_LOCAL: + rc = smb_lgrp_numbydomain(SMB_LGRP_LOCAL, &grpcnt); + break; + + default: + rc = SMB_LGRP_INVALID_ARG; + } + + return ((rc == SMB_LGRP_SUCCESS) ? grpcnt : 0); +} + +/* + * Determines whether the given SID is a member of the group + * specified by gname. + */ +boolean_t +smb_sam_grp_ismember(const char *gname, smb_sid_t *sid) +{ + smb_group_t grp; + boolean_t ismember = B_FALSE; + + if (smb_lgrp_getbyname((char *)gname, &grp) == SMB_LGRP_SUCCESS) { + ismember = smb_lgrp_is_member(&grp, sid); + smb_lgrp_free(&grp); + } + + return (ismember); +} + +/* + * Frees memories allocated for the passed account fields. + */ +void +smb_account_free(smb_account_t *account) +{ + free(account->a_name); + free(account->a_domain); + smb_sid_free(account->a_sid); + smb_sid_free(account->a_domsid); +} + +/* + * Validates the given account. + */ +boolean_t +smb_account_validate(smb_account_t *account) +{ + return ((account->a_name != NULL) && (account->a_sid != NULL) && + (account->a_domain != NULL) && (account->a_domsid != NULL)); +} + +/* + * Lookup local SMB user account database (/var/smb/smbpasswd) + * if there's a match query its SID from idmap service and make + * sure the SID is a local SID. + * + * The memory for the returned SID must be freed by the caller. + */ +static uint32_t +smb_sam_lookup_user(char *name, smb_sid_t **sid) +{ + smb_passwd_t smbpw; + + if (smb_pwd_getpwnam(name, &smbpw) == NULL) + return (NT_STATUS_NO_SUCH_USER); + + if (smb_idmap_getsid(smbpw.pw_uid, SMB_IDMAP_USER, sid) + != IDMAP_SUCCESS) + return (NT_STATUS_NONE_MAPPED); + + if (!smb_sid_islocal(*sid)) { + smb_sid_free(*sid); + return (NT_STATUS_NONE_MAPPED); + } + + return (NT_STATUS_SUCCESS); +} + +/* + * Lookup local SMB group account database (/var/smb/smbgroup.db) + * The memory for the returned SID must be freed by the caller. + */ +static uint32_t +smb_sam_lookup_group(char *name, smb_sid_t **sid) +{ + smb_group_t grp; + + if (smb_lgrp_getbyname(name, &grp) != SMB_LGRP_SUCCESS) + return (NT_STATUS_NO_SUCH_ALIAS); + + *sid = smb_sid_dup(grp.sg_id.gs_sid); + smb_lgrp_free(&grp); + + return ((*sid == NULL) ? NT_STATUS_NO_MEMORY : NT_STATUS_SUCCESS); +} diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_util.c b/usr/src/lib/smbsrv/libsmb/common/smb_util.c index d6eabf294b..e4b68dfb31 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_util.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_util.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -362,13 +362,17 @@ rand_hash( * not distinguished syntactically. We check for hosts first because * it's cheaper (just M*N strcmp()s), then try netgroups. * + * Currently this function always returns B_TRUE for ipv6 until + * the underlying functions support ipv6 + * * Function returns: * -1 for "all" * 0 not found * 1 found + * */ int -smb_chk_hostaccess(ipaddr_t ipaddr, char *access_list) +smb_chk_hostaccess(smb_inaddr_t *ipaddr, char *access_list) { int nentries; char *gr; @@ -384,7 +388,10 @@ smb_chk_hostaccess(ipaddr_t ipaddr, char *access_list) struct netbuf buf; struct netconfig *config; - inaddr.s_addr = (uint32_t)ipaddr; + if (ipaddr->a_family == AF_INET6) + return (B_TRUE); + + inaddr.s_addr = ipaddr->a_ipv4; /* * If no access list - then it's "all" @@ -395,8 +402,6 @@ smb_chk_hostaccess(ipaddr_t ipaddr, char *access_list) nentries = 0; - /* For now, only IPv4 */ - sa.sin_family = AF_INET; sa.sin_port = 0; sa.sin_addr = inaddr; diff --git a/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c b/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c index 7f1b4039dd..a814db6950 100644 --- a/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c +++ b/usr/src/lib/smbsrv/libsmb/common/smb_wksids.c @@ -130,67 +130,55 @@ static smb_wka_t wka_tbl[] = { #define SMB_WKA_NUM (sizeof (wka_tbl)/sizeof (wka_tbl[0])) /* - * smb_wka_lookup_sid - * - * Search the wka_tbl looking for a match on the specified SID. If the - * SID matches a builtin entry, the associated name is returned. - * Otherwise a null pointer is returned. + * Looks up well known accounts table for the given SID. + * Upon success returns a pointer to the account entry in + * the table, otherwise returns NULL. */ -char * -smb_wka_lookup_sid(smb_sid_t *sid, uint16_t *sid_name_use) +smb_wka_t * +smb_wka_lookup_sid(smb_sid_t *sid) { smb_wka_t *entry; int i; + (void) rw_rdlock(&wk_rwlock); + for (i = 0; i < SMB_WKA_NUM; ++i) { entry = &wka_tbl[i]; - if (smb_sid_cmp(sid, entry->wka_binsid)) { - if (sid_name_use) - *sid_name_use = entry->wka_type; - return (entry->wka_name); + (void) rw_unlock(&wk_rwlock); + return (entry); } } + (void) rw_unlock(&wk_rwlock); return (NULL); } /* - * smb_wka_lookup_name - * - * Search the wka_tbl looking for a match on the specified name. If the - * name matches a builtin entry, the associated SID (which is in - * malloc'd memory) is returned. Otherwise a null pointer is returned. + * Looks up well known accounts table for the given name. + * Upon success returns a pointer to the binary SID of the + * entry, otherwise returns NULL. */ smb_sid_t * -smb_wka_lookup_name(char *name, uint16_t *sid_name_use) +smb_wka_get_sid(char *name) { smb_wka_t *entry; - int i; + smb_sid_t *sid = NULL; - for (i = 0; i < SMB_WKA_NUM; ++i) { - entry = &wka_tbl[i]; + if ((entry = smb_wka_lookup_name(name)) != NULL) + sid = entry->wka_binsid; - if (!utf8_strcasecmp(name, entry->wka_name)) { - if (sid_name_use) - *sid_name_use = entry->wka_type; - return (smb_sid_dup(entry->wka_binsid)); - } - } - - return (NULL); + return (sid); } /* - * smb_wka_lookup - * - * Search the wka_tbl looking for a match on the specified name. If the - * name matches a builtin entry then pointer to that entry will be - * returned. Otherwise 0 is returned. + * Looks up well known accounts table for the given name. + * Upon success returns a pointer to the account entry in + * the table, otherwise returns NULL. */ smb_wka_t * -smb_wka_lookup(char *name) +smb_wka_lookup_name(char *name) { smb_wka_t *entry; int i; @@ -198,7 +186,6 @@ smb_wka_lookup(char *name) (void) rw_rdlock(&wk_rwlock); for (i = 0; i < SMB_WKA_NUM; ++i) { entry = &wka_tbl[i]; - if (!utf8_strcasecmp(name, entry->wka_name)) { (void) rw_unlock(&wk_rwlock); return (entry); @@ -209,47 +196,6 @@ smb_wka_lookup(char *name) return (NULL); } - -/* - * smb_wka_is_wellknown - * - * Search the wka_tbl looking for a match on the specified name. If the - * name matches a builtin entry returns 1. Otherwise returns 0. - */ -boolean_t -smb_wka_is_wellknown(char *name) -{ - int i; - - for (i = 0; i < SMB_WKA_NUM; ++i) { - if (utf8_strcasecmp(name, wka_tbl[i].wka_name) == 0) - return (B_TRUE); - } - - return (B_FALSE); -} - -/* - * smb_wka_lookup_domain - * - * Return the builtin domain name for the specified alias or group name. - */ -char * -smb_wka_lookup_domain(char *name) -{ - smb_wka_t *entry; - int i; - - for (i = 0; i < SMB_WKA_NUM; ++i) { - entry = &wka_tbl[i]; - - if (!utf8_strcasecmp(name, entry->wka_name)) - return (wka_nbdomain[entry->wka_domidx]); - } - - return (NULL); -} - /* * Returns the Netbios domain name for the given index */ @@ -262,6 +208,33 @@ smb_wka_get_domain(int idx) return (NULL); } +uint32_t +smb_wka_token_groups(boolean_t isadmin, smb_ids_t *gids) +{ + static char *grps[] = + {"Authenticated Users", "NETWORK", "Administrators"}; + smb_id_t *id; + int gcnt, i; + int total_cnt; + + gcnt = (isadmin) ? 3 : 2; + total_cnt = gids->i_cnt + gcnt; + + gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t)); + if (gids->i_ids == NULL) + return (NT_STATUS_NO_MEMORY); + + id = gids->i_ids + gids->i_cnt; + for (i = 0; i < gcnt; i++, gids->i_cnt++, id++) { + id->i_sid = smb_sid_dup(smb_wka_get_sid(grps[i])); + id->i_attrs = 0x7; + if (id->i_sid == NULL) + return (NT_STATUS_NO_MEMORY); + } + + return (NT_STATUS_SUCCESS); +} + /* * smb_wka_init * diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c index 834ea5b041..cc9c43b878 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -100,9 +100,17 @@ * Length of "dc=" prefix. */ #define SMB_ADS_DN_PREFIX_LEN 3 - #define SMB_ADS_MSDCS_SVC_CNT 2 +static char *smb_ads_computer_objcls[] = { + "top", "person", "organizationalPerson", + "user", "computer", NULL +}; + +static char *smb_ads_share_objcls[] = { + "top", "leaf", "connectionPoint", "volume", NULL +}; + /* Cached ADS server to communicate with */ static smb_ads_host_info_t *smb_ads_cached_host_info = NULL; static mutex_t smb_ads_cached_host_mtx; @@ -240,13 +248,10 @@ smb_ads_build_unc_name(char *unc_name, int maxlen, static int smb_ads_ldap_ping(smb_ads_host_info_t *ads_host) { - struct in_addr addr; int ldversion = LDAP_VERSION3, status, timeoutms = 5 * 1000; LDAP *ld = NULL; - addr.s_addr = ads_host->ip_addr; - - ld = ldap_init((char *)inet_ntoa(addr), ads_host->port); + ld = ldap_init(ads_host->name, ads_host->port); if (ld == NULL) return (-1); @@ -446,9 +451,10 @@ smb_ads_decode_host_ip(int addit_cnt, int ans_cnt, uchar_t **ptr, uchar_t *eom, uchar_t *buf, smb_ads_host_info_t *ads_host_list) { int i, j, len; - in_addr_t ipaddr; + smb_inaddr_t ipaddr; char hostname[MAXHOSTNAMELEN]; char *name; + uint16_t size = 0; for (i = 0; i < addit_cnt; i++) { @@ -460,10 +466,25 @@ smb_ads_decode_host_ip(int addit_cnt, int ans_cnt, uchar_t **ptr, *ptr += len; /* skip type, class, TTL, data len */ - *ptr += 10; - + *ptr += 8; /* LINTED: E_CONSTANT_CONDITION */ - NS_GET32(ipaddr, *ptr); + NS_GET16(size, *ptr); + + if (size == INADDRSZ) { + /* LINTED: E_CONSTANT_CONDITION */ + NS_GET32(ipaddr.a_ipv4, *ptr); + ipaddr.a_ipv4 = htonl(ipaddr.a_ipv4); + ipaddr.a_family = AF_INET; + } else if (size == IN6ADDRSZ) { +#ifdef BIG_ENDIAN + bcopy(*ptr, &ipaddr.a_ipv6, IN6ADDRSZ); +#else + for (i = 0; i < IN6ADDRSZ; i++) + (uint8_t *)(ipaddr.a_ipv6) + [IN6ADDRSZ-1-i] = *(*ptr+i); +#endif + ipaddr.a_family = AF_INET6; + } /* * find the host in the list of DC records from @@ -473,12 +494,11 @@ smb_ads_decode_host_ip(int addit_cnt, int ans_cnt, uchar_t **ptr, for (j = 0; j < ans_cnt; j++) { if ((name = ads_host_list[j].name) == NULL) continue; - - if (utf8_strcasecmp(name, hostname) == 0) - ads_host_list[j].ip_addr = htonl(ipaddr); + if (utf8_strcasecmp(name, hostname) == 0) { + ads_host_list[j].ipaddr = ipaddr; + } } } - return (0); } @@ -691,12 +711,25 @@ smb_ads_getipnodebyname(smb_ads_host_info_t *hentry) struct hostent *h; int error; - h = getipnodebyname(hentry->name, AF_INET, 0, &error); - if (h == NULL || h->h_addr == NULL) - return (-1); + switch (hentry->ipaddr.a_family) { + case AF_INET6: + h = getipnodebyname(hentry->name, hentry->ipaddr.a_family, + AI_DEFAULT, &error); + if (h == NULL || h->h_length != IPV6_ADDR_LEN) + return (-1); + break; - (void) memcpy(&hentry->ip_addr, h->h_addr, h->h_length); + case AF_INET: + h = getipnodebyname(hentry->name, hentry->ipaddr.a_family, + 0, &error); + if (h == NULL || h->h_length != INADDRSZ) + return (-1); + break; + default: + return (-1); + } + bcopy(*(h->h_addr_list), &hentry->ipaddr.a_ip, h->h_length); freehostent(h); return (0); } @@ -778,9 +811,8 @@ smb_ads_find_host(char *domain, char *sought) hlistp = hlist->ah_list; for (i = 0; i < hlist->ah_cnt; i++) { - /* Do a host lookup by hostname to get the IP address */ - if (hlistp[i].ip_addr == 0) { + if (smb_inet_iszero(&hlistp[i].ipaddr)) { if (smb_ads_getipnodebyname(&hlistp[i]) < 0) continue; } @@ -940,20 +972,17 @@ smb_ads_open_main(char *domain, char *user, char *password) LDAP *ld; int version = 3; smb_ads_host_info_t *ads_host = NULL; - struct in_addr addr; ads_host = smb_ads_find_host(domain, NULL); if (ads_host == NULL) return (NULL); - ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t)); if (ah == NULL) return (NULL); (void) memset(ah, 0, sizeof (smb_ads_handle_t)); - addr.s_addr = ads_host->ip_addr; - if ((ld = ldap_init((char *)inet_ntoa(addr), ads_host->port)) == NULL) { + if ((ld = ldap_init(ads_host->name, ads_host->port)) == NULL) { smb_ads_free_cached_host(); free(ah); return (NULL); @@ -1454,10 +1483,10 @@ smb_ads_add_share(smb_ads_handle_t *ah, const char *adsShareName, const char *unc_name, const char *adsContainer) { LDAPMod *attrs[SMB_ADS_SHARE_NUM_ATTR]; - char *tmp1[5], *tmp2[5]; int j = 0; char *share_dn; int len, ret; + char *unc_names[] = {(char *)unc_name, NULL}; len = 5 + strlen(adsShareName) + strlen(adsContainer) + strlen(ah->domain_dn) + 1; @@ -1476,18 +1505,11 @@ smb_ads_add_share(smb_ads_handle_t *ah, const char *adsShareName, attrs[j]->mod_op = LDAP_MOD_ADD; attrs[j]->mod_type = "objectClass"; - tmp1[0] = "top"; - tmp1[1] = "leaf"; - tmp1[2] = "connectionPoint"; - tmp1[3] = "volume"; - tmp1[4] = 0; - attrs[j]->mod_values = tmp1; + attrs[j]->mod_values = smb_ads_share_objcls; attrs[++j]->mod_op = LDAP_MOD_ADD; attrs[j]->mod_type = "uNCName"; - tmp2[0] = (char *)unc_name; - tmp2[1] = 0; - attrs[j]->mod_values = tmp2; + attrs[j]->mod_values = unc_names; if ((ret = ldap_add_s(ah->ld, share_dn, attrs)) != LDAP_SUCCESS) { smb_tracef("smbns_ads: %s: ldap_add error: %s", @@ -1890,7 +1912,7 @@ static int smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn) { LDAPMod *attrs[SMB_ADS_COMPUTER_NUM_ATTR]; - char *oc_vals[6], *sam_val[2], *usr_val[2]; + char *sam_val[2], *usr_val[2]; char *spn_set[SMBKRB5_SPN_IDX_MAX + 1], *ctl_val[2], *fqh_val[2]; char *encrypt_val[2]; int j = -1; @@ -1939,13 +1961,7 @@ smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn) if (op == LDAP_MOD_ADD) { attrs[++j]->mod_op = op; attrs[j]->mod_type = "objectClass"; - oc_vals[0] = "top"; - oc_vals[1] = "person"; - oc_vals[2] = "organizationalPerson"; - oc_vals[3] = "user"; - oc_vals[4] = "computer"; - oc_vals[5] = 0; - attrs[j]->mod_values = oc_vals; + attrs[j]->mod_values = smb_ads_computer_objcls; } attrs[++j]->mod_op = op; @@ -2226,38 +2242,29 @@ smb_ads_find_computer(smb_ads_handle_t *ah, char *dn) * Modify the user account control attribute of an existing computer * object on AD. * - * Returns 0 on success. Otherwise, returns -1. + * Returns LDAP error code. */ static int -smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int des_only, char *dn) +smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int flags, char *dn) { LDAPMod *attrs[2]; char *ctl_val[2]; - int ret, usrctl_flags = 0; + int ret = 0; char usrctl_buf[16]; if (smb_ads_alloc_attr(attrs, sizeof (attrs) / sizeof (LDAPMod *)) != 0) - return (-1); + return (LDAP_NO_MEMORY); attrs[0]->mod_op = LDAP_MOD_REPLACE; attrs[0]->mod_type = SMB_ADS_ATTR_CTL; - usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT | - SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION | - SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD); - - if (des_only) - usrctl_flags |= SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY; - - (void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags); + (void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", flags); ctl_val[0] = usrctl_buf; ctl_val[1] = 0; attrs[0]->mod_values = ctl_val; - if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) { smb_tracef("smbns_ads: ldap_modify error: %s", ldap_err2string(ret)); - ret = -1; } smb_ads_free_attr(attrs); @@ -2355,7 +2362,7 @@ smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd, boolean_t des_only, delete = B_TRUE; smb_adjoin_status_t rc = SMB_ADJOIN_SUCCESS; boolean_t new_acct; - int dclevel, num; + int dclevel, num, usrctl_flags = 0; smb_ads_qstat_t qstat; char dn[SMB_ADS_DN_MAX]; char *tmpfile; @@ -2448,7 +2455,31 @@ smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd, kvno = smb_ads_lookup_computer_attr_kvno(ah, dn); - if (smb_ads_update_computer_cntrl_attr(ah, des_only, dn) + /* + * Only members of Domain Admins and Enterprise Admins can set + * the TRUSTED_FOR_DELEGATION userAccountControl flag. + */ + if (smb_ads_update_computer_cntrl_attr(ah, + SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION, dn) + == LDAP_INSUFFICIENT_ACCESS) { + usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT | + SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD); + + syslog(LOG_NOTICE, "smbns_ads: Unable to set the " + "TRUSTED_FOR_DELEGATION userAccountControl flag on " + "the machine account in Active Directory. Please refer " + "to the Troubleshooting guide for more information."); + + } else { + usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT | + SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION | + SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD); + } + + if (des_only) + usrctl_flags |= SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY; + + if (smb_ads_update_computer_cntrl_attr(ah, usrctl_flags, dn) != 0) { rc = SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR; goto adjoin_cleanup; @@ -2524,30 +2555,6 @@ smb_adjoin_report_err(smb_adjoin_status_t status) } /* - * smb_ads_get_pdc_ip - * - * Check to see if there is any configured PDC. - * If there is then converts the string IP to - * integer format and returns it. - */ -static uint32_t -smb_ads_get_pdc_ip(void) -{ - char p[INET_ADDRSTRLEN]; - uint32_t ipaddr = 0; - int rc; - - rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, p, sizeof (p)); - if (rc == SMBD_SMF_OK) { - rc = inet_pton(AF_INET, p, &ipaddr); - if (rc == 0) - ipaddr = 0; - } - - return (ipaddr); -} - -/* * smb_ads_select_pdc * * This method walks the list of DCs and returns the first DC record that @@ -2561,17 +2568,17 @@ static smb_ads_host_info_t * smb_ads_select_pdc(smb_ads_host_list_t *hlist) { smb_ads_host_info_t *hentry; - uint32_t ip; + smb_inaddr_t ipaddr; size_t cnt; int i; - if ((ip = smb_ads_get_pdc_ip()) == 0) + if (smb_config_getip(SMB_CI_DOMAIN_SRV, &ipaddr) != SMBD_SMF_OK) return (NULL); cnt = hlist->ah_cnt; for (i = 0; i < cnt; i++) { hentry = &hlist->ah_list[i]; - if ((hentry->ip_addr == ip) && + if (smb_inet_equal(&hentry->ipaddr, &ipaddr, SMB_INET_NOMASK) && (smb_ads_ldap_ping(hentry) == 0)) return (hentry); } @@ -2605,10 +2612,15 @@ smb_ads_select_dcfromsubnet(smb_ads_host_list_t *hlist) for (i = 0; i < cnt; i++) { hentry = &hlist->ah_list[i]; - if ((hentry->ip_addr & lnic->nic_mask) == - (lnic->nic_ip & lnic->nic_mask)) - if (smb_ads_ldap_ping(hentry) == 0) - return (hentry); + if ((hentry->ipaddr.a_family == AF_INET) && + (lnic->nic_ip.a_family == AF_INET)) { + if ((hentry->ipaddr.a_ipv4 & + lnic->nic_mask) == + (lnic->nic_ip.a_ipv4 & + lnic->nic_mask)) + if (smb_ads_ldap_ping(hentry) == 0) + return (hentry); + } } } while (smb_nic_getnext(&ni) == 0); @@ -2735,8 +2747,8 @@ smb_ads_lookup_msdcs(char *fqdn, char *server, char *buf, uint32_t buflen) { smb_ads_host_info_t *hinfo = NULL; char *p; - struct in_addr addr; char *sought_host; + char ipstr[INET6_ADDRSTRLEN]; if (!fqdn || !buf) return (B_FALSE); @@ -2746,9 +2758,9 @@ smb_ads_lookup_msdcs(char *fqdn, char *server, char *buf, uint32_t buflen) if ((hinfo = smb_ads_find_host(fqdn, sought_host)) == NULL) return (B_FALSE); - addr.s_addr = hinfo->ip_addr; - syslog(LOG_DEBUG, "msdcsLookupADS: %s [%s]", hinfo->name, - inet_ntoa(addr)); + smb_tracef("msdcsLookupADS: %s [%s]", hinfo->name, + smb_inet_ntop(&hinfo->ipaddr, ipstr, + SMB_IPSTRLEN(hinfo->ipaddr.a_family))); (void) strlcpy(buf, hinfo->name, buflen); /* diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h index a8e8d331f8..0275fc5c41 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -71,7 +71,7 @@ typedef struct smb_ads_host_info { int port; /* ldap port */ int priority; /* DNS SRV record priority */ int weight; /* DNS SRV record weight */ - in_addr_t ip_addr; /* network byte order */ + smb_inaddr_t ipaddr; /* network byte order */ } smb_ads_host_info_t; typedef struct smb_ads_host_list { diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c index ce7555f225..2624a08e2a 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_browser.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -661,7 +661,7 @@ smb_browser_addr_of_subnet(struct name_entry *name, smb_hostinfo_t *hinfo, if (hinfo->hi_nic.nic_smbflags & SMB_NICF_ALIAS) return (-1); - ipaddr = hinfo->hi_nic.nic_ip; + ipaddr = hinfo->hi_nic.nic_ip.a_ipv4; mask = hinfo->hi_nic.nic_mask; *result = *name; @@ -869,7 +869,8 @@ smb_browser_process_AnnouncementRequest(struct datagram *datagram, (void) rw_rdlock(&smb_binfo.bi_hlist_rwl); hinfo = list_head(&smb_binfo.bi_hlist); while (hinfo) { - if ((hinfo->hi_nic.nic_ip & hinfo->hi_nic.nic_mask) == + if ((hinfo->hi_nic.nic_ip.a_ipv4 & + hinfo->hi_nic.nic_mask) == (datagram->src.addr_list.sin.sin_addr.s_addr & hinfo->hi_nic.nic_mask)) { h_found = B_TRUE; @@ -1072,8 +1073,9 @@ smb_browser_config(void) hinfo = list_head(&smb_binfo.bi_hlist); while (hinfo) { smb_init_name_struct((unsigned char *)resource_domain, 0x00, 0, - hinfo->hi_nic.nic_ip, htons(DGM_SRVC_UDP_PORT), - NAME_ATTR_GROUP, NAME_ATTR_LOCAL, &name); + hinfo->hi_nic.nic_ip.a_ipv4, + htons(DGM_SRVC_UDP_PORT), NAME_ATTR_GROUP, + NAME_ATTR_LOCAL, &name); (void) smb_name_add_name(&name); hinfo = list_next(&smb_binfo.bi_hlist, hinfo); @@ -1157,11 +1159,11 @@ smb_browser_init(void) (void) strlcpy(hinfo->hi_nbname, hinfo->hi_nic.nic_host, NETBIOS_NAME_SZ); (void) utf8_strupr(hinfo->hi_nbname); - /* 0x20: file server service */ smb_init_name_struct((unsigned char *)hinfo->hi_nbname, - 0x20, 0, hinfo->hi_nic.nic_ip, htons(DGM_SRVC_UDP_PORT), - NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &hinfo->hi_netname); + 0x20, 0, hinfo->hi_nic.nic_ip.a_ipv4, + htons(DGM_SRVC_UDP_PORT), NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, + &hinfo->hi_netname); list_insert_tail(&smb_binfo.bi_hlist, hinfo); smb_binfo.bi_hcnt++; diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c index 62ebedf522..2c3675ecd7 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_dyndns.c @@ -111,6 +111,7 @@ static int dyndns_clear_rev_zone(char *); static void dyndns_msgid_init(void); static int dyndns_get_msgid(void); static void dyndns_syslog(int, int, const char *); +static int dyndns_getnameinfo(smb_inaddr_t *, char *, int, int); int dyndns_start(void) @@ -500,6 +501,9 @@ dyndns_put_byte(char *buf, char val) return (buf); } + + + static char * dyndns_put_int(char *buf, int val) { @@ -508,6 +512,15 @@ dyndns_put_int(char *buf, int val) return (buf); } +static char * +dyndns_put_v6addr(char *buf, smb_inaddr_t *val) +{ + + val->a_family = AF_INET6; + (void) memcpy(buf, &val->a_ipv6, IN6ADDRSZ); + buf += IN6ADDRSZ; + return (buf); +} /* * dyndns_stuff_str * Converts a domain string by removing periods and replacing with a byte value @@ -663,22 +676,28 @@ dyndns_build_update(char **ptr, int buf_len, char *name, int type, int class, { char *namePtr; int rec_len, data_len; + smb_inaddr_t ipaddr; + int isv4 = 1; rec_len = strlen(name) + 10; + if (inet_pton(AF_INET, data, &ipaddr) == 1) + isv4 = 1; + else if (inet_pton(AF_INET6, data, &ipaddr) == 1) + isv4 = 0; + if (add_del == UPDATE_ADD) { if (forw_rev == UPDATE_FORW) - data_len = 4; + data_len = isv4 ? 4 : 16; else data_len = strlen(data) + 2; } else { if (del_type == DEL_ALL) data_len = 0; else if (forw_rev == UPDATE_FORW) - data_len = 4; + data_len = isv4 ? 4 : 16; else data_len = strlen(data) + 2; } - if (rec_len + data_len > buf_len) { syslog(LOG_ERR, "dyndns update section: buffer too small"); return (-1); @@ -687,7 +706,10 @@ dyndns_build_update(char **ptr, int buf_len, char *name, int type, int class, namePtr = *ptr; (void) dyndns_stuff_str(&namePtr, name); *ptr = namePtr; - *ptr = dyndns_put_nshort(*ptr, type); + if (isv4) + *ptr = dyndns_put_nshort(*ptr, type); + else + *ptr = dyndns_put_nshort(*ptr, ns_t_aaaa); *ptr = dyndns_put_nshort(*ptr, class); *ptr = dyndns_put_nlong(*ptr, ttl); @@ -697,8 +719,13 @@ dyndns_build_update(char **ptr, int buf_len, char *name, int type, int class, } if (forw_rev == UPDATE_FORW) { - *ptr = dyndns_put_nshort(*ptr, 4); - *ptr = dyndns_put_int(*ptr, inet_addr(data)); /* ip address */ + if (isv4) { + *ptr = dyndns_put_nshort(*ptr, 4); + *ptr = dyndns_put_int(*ptr, ipaddr.a_ipv4); + } else { + *ptr = dyndns_put_nshort(*ptr, 16); + *ptr = dyndns_put_v6addr(*ptr, &ipaddr); + } } else { *ptr = dyndns_put_nshort(*ptr, strlen(data)+2); namePtr = *ptr; @@ -848,44 +875,69 @@ dyndns_build_tsig(char **ptr, int buf_len, int msg_id, char *name, * descriptor: descriptor referencing the created socket * -1 : error */ + static int -dyndns_open_init_socket(int sock_type, unsigned long dest_addr, int port) +dyndns_open_init_socket(int sock_type, smb_inaddr_t *dest_addr, int port) { int s; struct sockaddr_in my_addr; + struct sockaddr_in6 my6_addr; struct sockaddr_in serv_addr; + struct sockaddr_in6 serv6_addr; + int family; - if ((s = socket(AF_INET, sock_type, 0)) == -1) { - syslog(LOG_ERR, "dyndns: socket error"); - return (-1); - } - - bzero(&my_addr, sizeof (my_addr)); - my_addr.sin_family = AF_INET; - my_addr.sin_port = htons(0); - my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + family = dest_addr->a_family; - if (bind(s, (struct sockaddr *)&my_addr, sizeof (my_addr)) < 0) { - syslog(LOG_ERR, "dyndns: client bind error"); - (void) close(s); + if ((s = socket(family, sock_type, 0)) == -1) { + syslog(LOG_ERR, "dyndns: socket error\n"); return (-1); } - - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(port); - serv_addr.sin_addr.s_addr = dest_addr; - - if (connect(s, (struct sockaddr *)&serv_addr, - sizeof (struct sockaddr_in)) < 0) { - syslog(LOG_ERR, "dyndns: client connect error (%s)", - strerror(errno)); - (void) close(s); - return (-1); + if (family == AF_INET) { + bzero(&my_addr, sizeof (my_addr)); + my_addr.sin_family = family; + my_addr.sin_port = htons(0); + my_addr.sin_addr.s_addr = htonl(INADDR_ANY); + if (bind(s, (struct sockaddr *)&my_addr, + sizeof (my_addr)) < 0) { + syslog(LOG_ERR, "dyndns: client bind err\n"); + (void) close(s); + return (-1); + } + serv_addr.sin_family = family; + serv_addr.sin_port = htons(port); + serv_addr.sin_addr.s_addr = dest_addr->a_ipv4; + if (connect(s, (struct sockaddr *)&serv_addr, + sizeof (struct sockaddr_in)) < 0) { + syslog(LOG_ERR, "dyndns: client connect (%s)\n", + strerror(errno)); + (void) close(s); + return (-1); + } + } else { + bzero(&my6_addr, sizeof (my6_addr)); + my6_addr.sin6_family = family; + my6_addr.sin6_port = htons(0); + bzero(&my6_addr.sin6_addr.s6_addr, IN6ADDRSZ); + if (bind(s, (struct sockaddr *)&my6_addr, + sizeof (my6_addr)) < 0) { + syslog(LOG_ERR, "dyndns: client bind err\n"); + (void) close(s); + return (-1); + } + serv6_addr.sin6_family = family; + serv6_addr.sin6_port = htons(port); + bcopy(&serv6_addr.sin6_addr.s6_addr, &dest_addr->a_ipv6, + IN6ADDRSZ); + if (connect(s, (struct sockaddr *)&serv6_addr, + sizeof (struct sockaddr_in6)) < 0) { + syslog(LOG_ERR, "dyndns: client connect err (%s)\n", + strerror(errno)); + (void) close(s); + return (-1); + } } - return (s); } - /* * dyndns_build_tkey_msg * This routine is used to build the TKEY message to transmit GSS tokens @@ -1106,27 +1158,24 @@ dyndns_establish_sec_ctx(gss_ctx_id_t *gss_context, gss_cred_id_t cred_handle, * -1: error * 0: success */ + static gss_ctx_id_t -dyndns_get_sec_context(const char *hostname, int dns_ip) +dyndns_get_sec_context(const char *hostname, smb_inaddr_t *dns_ip) { int s; gss_cred_id_t cred_handle; gss_ctx_id_t gss_context; gss_OID oid; - struct hostent *hentry; char *key_name, dns_hostname[MAXHOSTNAMELEN]; cred_handle = GSS_C_NO_CREDENTIAL; oid = GSS_C_NO_OID; key_name = (char *)hostname; - hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET); - if (hentry == NULL) { - syslog(LOG_ERR, "dyndns gethostbyaddr failed"); + if (dyndns_getnameinfo(dns_ip, dns_hostname, + sizeof (dns_hostname), 0)) { return (NULL); } - (void) strcpy(dns_hostname, hentry->h_name); - if ((s = dyndns_open_init_socket(SOCK_STREAM, dns_ip, 53)) < 0) { return (NULL); } @@ -1139,6 +1188,33 @@ dyndns_get_sec_context(const char *hostname, int dns_ip) return (gss_context); } +static int +dyndns_getnameinfo(smb_inaddr_t *dns_ip, char *dns_hostname, + int hostlen, int flags) +{ + socklen_t salen; + struct sockaddr_in6 sin6; + struct sockaddr_in sin; + void *sp; + + if (dns_ip->a_family == AF_INET) { + salen = sizeof (struct sockaddr_in); + sin.sin_family = dns_ip->a_family; + sin.sin_port = 0; + sin.sin_addr.s_addr = dns_ip->a_ipv4; + sp = &sin; + } else { + salen = sizeof (struct sockaddr_in6); + sin6.sin6_family = dns_ip->a_family; + sin6.sin6_port = 0; + (void) memcpy(&sin6.sin6_addr.s6_addr, &dns_ip->a_ipv6, + sizeof (sin6.sin6_addr.s6_addr)); + sp = &sin6; + } + return (getnameinfo((struct sockaddr *)sp, salen, + dns_hostname, hostlen, NULL, 0, flags)); +} + /* * dyndns_build_add_remove_msg * This routine builds the update request message for adding and removing DNS @@ -1185,6 +1261,9 @@ dyndns_build_add_remove_msg(char *buf, int update_zone, const char *hostname, char *zone, *resource, *data, zone_buf[100], resrc_buf[100]; int zoneType, zoneClass, type, class, ttl; char *p; + smb_inaddr_t tmp_addr; + int i, j, k; + int fourcnt; queryReq = REQ_UPDATE; zoneCount = 1; @@ -1220,26 +1299,54 @@ dyndns_build_add_remove_msg(char *buf, int update_zone, const char *hostname, resource = (char *)hostname; data = (char *)ip_addr; } else { - (void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d); - (void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa", c, b, a); - zone = p = zone_buf; - - /* Try higher domains according to the level requested */ - while (--level >= 0) { - /* domain */ - if ((zone = (char *)strchr(p, '.')) == NULL) { - return (-1); + if (inet_pton(AF_INET, ip_addr, &tmp_addr) == 1) { + (void) sscanf(ip_addr, "%d.%d.%d.%d", &a, &b, &c, &d); + (void) sprintf(zone_buf, "%d.%d.%d.in-addr.arpa", + c, b, a); + zone = p = zone_buf; + + /* Try higher domains based on level requested */ + while (--level >= 0) { + /* domain */ + if ((zone = (char *)strchr(p, '.')) == NULL) { + return (-1); + } + zone += 1; + p = zone; } - zone += 1; - p = zone; + (void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa", + d, c, b, a); + } else { + /* + * create reverse nibble ipv6 format + */ + bzero(resrc_buf, 100); + i = 0; + j = 0; + while (ip_addr[i] != 0) + i++; + i--; + while (i >= 0) { + fourcnt = 3; + while ((i >= 0) && (ip_addr[i] != ':')) { + resrc_buf[j++] = ip_addr[i]; + (void) strcat(&resrc_buf[j++], "."); + fourcnt --; + i--; + } + for (k = 0; k <= fourcnt; k++) { + resrc_buf[j++] = '0'; + (void) strcat(&resrc_buf[j++], "."); + } + i--; + } + (void) strcat(resrc_buf, "ip6.arpa"); + (void) strcpy(zone_buf, &resrc_buf[32]); + zone = zone_buf; } - - (void) sprintf(resrc_buf, "%d.%d.%d.%d.in-addr.arpa", - d, c, b, a); resource = resrc_buf; /* ip info */ data = (char *)hostname; } - if (dyndns_build_quest_zone(&bufptr, BUFLEN_UDP(bufptr, buf), zone, zoneType, zoneClass) == -1) { return (-1); @@ -1393,13 +1500,14 @@ dyndns_build_signed_tsig_msg(char *buf, int update_zone, const char *hostname, * rec_buf: reply dat * 0 : success */ + static int dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf) { int i, retval, addr_len; struct timeval tv, timeout; fd_set rfds; - struct sockaddr_in from_addr; + struct sockaddr_in6 from_addr; timeout.tv_usec = 0; timeout.tv_sec = DYNDNS_QUERY_TIMEOUT; @@ -1422,11 +1530,10 @@ dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf) return (-1); } else if (retval > 0) { bzero(rec_buf, NS_PACKETSZ); - /* required by recvfrom */ - addr_len = sizeof (struct sockaddr_in); + addr_len = sizeof (struct sockaddr_in6); if (recvfrom(s, rec_buf, NS_PACKETSZ, 0, (struct sockaddr *)&from_addr, &addr_len) == -1) { - syslog(LOG_ERR, "dyndns: UDP recv error"); + syslog(LOG_ERR, "dyndns: UDP recv error "); return (-1); } break; @@ -1441,7 +1548,6 @@ dyndns_udp_send_recv(int s, char *buf, int buf_sz, char *rec_buf) return (0); } - /* * dyndns_sec_add_remove_entry * Perform secure dynamic DNS update after getting security context. @@ -1484,7 +1590,7 @@ dyndns_sec_add_remove_entry(int update_zone, const char *hostname, OM_uint32 min, maj; gss_buffer_desc in_mic, out_mic; gss_ctx_id_t gss_context; - int dns_ip; + smb_inaddr_t dns_ip; char *key_name; int buf_sz; int level = 0; @@ -1492,18 +1598,21 @@ dyndns_sec_add_remove_entry(int update_zone, const char *hostname, assert(dns_str); assert(*dns_str); - dns_ip = inet_addr(dns_str); + if (inet_pton(AF_INET, dns_str, &dns_ip) == 1) + dns_ip.a_family = AF_INET; + else if (inet_pton(AF_INET6, dns_str, &dns_ip) == 1) + dns_ip.a_family = AF_INET6; sec_retry_higher: if ((gss_context = dyndns_get_sec_context(hostname, - dns_ip)) == NULL) { + &dns_ip)) == NULL) { return (-1); } key_name = (char *)hostname; - if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) { + if ((s2 = dyndns_open_init_socket(SOCK_DGRAM, &dns_ip, 53)) < 0) { if (gss_context != GSS_C_NO_CONTEXT) (void) gss_delete_sec_context(&min, &gss_context, NULL); return (-1); @@ -1598,40 +1707,71 @@ sec_retry_higher: * 0 : an entry does not exist */ /*ARGSUSED*/ + static int dyndns_search_entry(int update_zone, const char *hostname, const char *ip_addr, int update_type, struct timeval *time_out, int *is_match) { - struct hostent *hentry; - struct in_addr in; - in_addr_t ip; - int i; + smb_inaddr_t ipaddr, dnsip; + char dns_hostname[NI_MAXHOST]; + struct addrinfo hints, *res = NULL; + int salen; + int family; *is_match = 0; + if (inet_pton(AF_INET, ip_addr, &ipaddr) == 1) { + salen = sizeof (ipaddr.a_ipv4); + family = AF_INET; + } else if (inet_pton(AF_INET6, ip_addr, &ipaddr) == 1) { + salen = sizeof (ipaddr.a_ipv6); + family = AF_INET6; + } if (update_zone == UPDATE_FORW) { - hentry = gethostbyname(hostname); - if (hentry) { - ip = inet_addr(ip_addr); - for (i = 0; hentry->h_addr_list[i]; i++) { - (void) memcpy(&in.s_addr, - hentry->h_addr_list[i], sizeof (in.s_addr)); - if (ip == in.s_addr) { - *is_match = 1; - break; + bzero((char *)&hints, sizeof (hints)); + hints.ai_family = family; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(hostname, NULL, &hints, &res)) { + return (NULL); + } + if (res) { + /* + * if both ips aren't the same family skip to + * the next record + */ + do { + if ((res->ai_family == AF_INET) && + (family == AF_INET)) { + (void) memcpy(&dnsip, &res->ai_addr[0], + salen); + if (ipaddr.a_ipv4 == + dnsip.a_ipv4) { + *is_match = 1; + break; + } + } else if ((res->ai_family == AF_INET6) && + (family == AF_INET6)) { + (void) memcpy(&dnsip, &res->ai_addr[0], + salen); + /* need compare macro here */ + if (!memcmp(&ipaddr, &dnsip, + IN6ADDRSZ)) { + *is_match = 1; + break; + } } - } + } while (res->ai_next); + freeaddrinfo(res); return (1); } } else { - int dns_ip = inet_addr(ip_addr); - hentry = gethostbyaddr((char *)&dns_ip, 4, AF_INET); - if (hentry) { - if (strncasecmp(hentry->h_name, hostname, - strlen(hostname)) == 0) { - *is_match = 1; - } - return (1); + if (dyndns_getnameinfo(&ipaddr, dns_hostname, NI_MAXHOST, 0)) { + return (NULL); } + if (strncasecmp(dns_hostname, hostname, + strlen(hostname)) == 0) { + *is_match = 1; + } + return (1); } /* entry does not exist */ @@ -1679,17 +1819,16 @@ dyndns_add_remove_entry(int update_zone, const char *hostname, int s; uint16_t id, rid; char buf[NS_PACKETSZ], buf2[NS_PACKETSZ]; - int ret, dns_ip; + int ret; int is_exist, is_match; struct timeval timeout; int buf_sz; int level = 0; + smb_inaddr_t dns_ip; assert(dns_str); assert(*dns_str); - dns_ip = inet_addr(dns_str); - if (do_check == DNS_CHECK && del_type != DEL_ALL) { is_exist = dyndns_search_entry(update_zone, hostname, ip_addr, update_type, &timeout, &is_match); @@ -1701,10 +1840,14 @@ dyndns_add_remove_entry(int update_zone, const char *hostname, } } + if (inet_pton(AF_INET, dns_str, &dns_ip) == 1) + dns_ip.a_family = AF_INET; + else if (inet_pton(AF_INET6, dns_str, &dns_ip) == 1) + dns_ip.a_family = AF_INET6; + retry_higher: - if ((s = dyndns_open_init_socket(SOCK_DGRAM, dns_ip, 53)) < 0) { + if ((s = dyndns_open_init_socket(SOCK_DGRAM, &dns_ip, 53)) < 0) return (-1); - } id = 0; if ((buf_sz = dyndns_build_add_remove_msg(buf, update_zone, hostname, @@ -1775,37 +1918,32 @@ static int dyndns_add_entry(int update_zone, const char *hostname, const char *ip_addr, int life_time) { - char *dns_str; + const char *dns_str; char *which_zone; - struct in_addr ns_list[MAXNS]; + smb_inaddr_t ns_list[MAXNS]; + char dns_buf[INET6_ADDRSTRLEN]; int i, cnt; - int addr, rc = 0; - - if (hostname == NULL || ip_addr == NULL) - return (-1); + int rc = 0; - addr = (int)inet_addr(ip_addr); - if ((addr == -1) || (addr == 0)) + if (hostname == NULL || ip_addr == NULL) { return (-1); - - cnt = smb_get_nameservers(ns_list, MAXNS); + } + cnt = smb_get_nameservers(&ns_list[0], MAXNS); for (i = 0; i < cnt; i++) { - dns_str = inet_ntoa(ns_list[i]); - if ((dns_str == NULL) || - (strcmp(dns_str, "0.0.0.0") == 0)) { + dns_str = smb_inet_ntop(&ns_list[i], dns_buf, + SMB_IPSTRLEN(ns_list[i].a_family)); + if (dns_str == NULL) continue; - } which_zone = (update_zone == UPDATE_FORW) ? "forward" : "reverse"; - syslog(LOG_DEBUG, "dyndns %s lookup zone update %s (%s)", which_zone, hostname, ip_addr); if (dyndns_add_remove_entry(update_zone, hostname, ip_addr, life_time, - UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_str) != -1) { + UPDATE_ADD, DNS_NOCHECK, DEL_NONE, dns_buf) != -1) { rc = 1; break; } @@ -1835,46 +1973,44 @@ static int dyndns_remove_entry(int update_zone, const char *hostname, const char *ip_addr, int del_type) { - char *dns_str; - char *which_zone; - struct in_addr ns_list[MAXNS]; + const char *dns_str; + smb_inaddr_t ns_list[MAXNS]; + char dns_buf[INET6_ADDRSTRLEN]; int i, cnt, scnt; - int addr; if ((hostname == NULL || ip_addr == NULL)) { return (-1); } - - addr = (int)inet_addr(ip_addr); - if ((addr == -1) || (addr == 0)) { - return (-1); - } - cnt = smb_get_nameservers(ns_list, MAXNS); scnt = 0; - for (i = 0; i < cnt; i++) { - dns_str = inet_ntoa(ns_list[i]); - if ((dns_str == NULL) || - (strcmp(dns_str, "0.0.0.0") == 0)) { + dns_str = smb_inet_ntop(&ns_list[i], dns_buf, + SMB_IPSTRLEN(ns_list[i].a_family)); + if (dns_str == NULL) continue; - } - - which_zone = (update_zone == UPDATE_FORW) ? - "forward" : "reverse"; - - if (del_type == DEL_ONE) { - syslog(LOG_DEBUG, - "dyndns %s lookup zone remove %s (%s)", - which_zone, hostname, ip_addr); + if (update_zone == UPDATE_FORW) { + if (del_type == DEL_ONE) { + syslog(LOG_DEBUG, "Dynamic update " + "on forward lookup " + "zone for %s (%s)...\n", hostname, ip_addr); + } else { + syslog(LOG_DEBUG, "Removing all " + "entries of %s " + "in forward lookup zone...\n", hostname); + } } else { - syslog(LOG_DEBUG, - "dyndns %s lookup zone remove all %s", - which_zone, hostname); + if (del_type == DEL_ONE) { + syslog(LOG_DEBUG, "Dynamic update " + "on reverse lookup " + "zone for %s (%s)...\n", hostname, ip_addr); + } else { + syslog(LOG_DEBUG, "Removing all " + "entries of %s " + "in reverse lookup zone...\n", ip_addr); + } } - if (dyndns_add_remove_entry(update_zone, hostname, ip_addr, 0, - UPDATE_DEL, DNS_NOCHECK, del_type, dns_str) != -1) { + UPDATE_DEL, DNS_NOCHECK, del_type, dns_buf) != -1) { scnt++; break; } @@ -1900,12 +2036,12 @@ dyndns_remove_entry(int update_zone, const char *hostname, const char *ip_addr, * -1: some dynamic DNS updates errors * 0: successful or DDNS disabled. */ -static int +int dyndns_update_core(char *fqdn) { int forw_update_ok, error; - char *my_ip; - struct in_addr addr; + char my_ip[INET6_ADDRSTRLEN]; + const char *my_str; smb_niciter_t ni; int rc; char fqhn[MAXHOSTNAMELEN]; @@ -1938,32 +2074,31 @@ dyndns_update_core(char *fqdn) do { if (ni.ni_nic.nic_sysflags & IFF_PRIVATE) continue; - - addr.s_addr = ni.ni_nic.nic_ip; - my_ip = (char *)strdup(inet_ntoa(addr)); - if (my_ip == NULL) { + /* first try ipv4, then ipv6 */ + my_str = smb_inet_ntop(&ni.ni_nic.nic_ip, my_ip, + SMB_IPSTRLEN(ni.ni_nic.nic_ip.a_family)); + if (my_str == NULL) { error++; continue; } if (forw_update_ok) { - rc = dyndns_add_entry(UPDATE_FORW, fqhn, my_ip, + rc = dyndns_add_entry(UPDATE_FORW, fqhn, my_str, DDNS_TTL); if (rc == -1) error++; } - rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_ip, DEL_ALL); + rc = dyndns_remove_entry(UPDATE_REV, fqhn, my_str, DEL_ALL); if (rc == 0) { - rc = dyndns_add_entry(UPDATE_REV, fqhn, my_ip, + rc = dyndns_add_entry(UPDATE_REV, fqhn, my_str, DDNS_TTL); } if (rc == -1) error++; - (void) free(my_ip); } while (smb_nic_getnext(&ni) == 0); return ((error == 0) ? 0 : -1); @@ -1980,15 +2115,15 @@ dyndns_update_core(char *fqdn) * -1: some dynamic DNS updates errors * 0: successful or DDNS disabled. */ -static int +int dyndns_clear_rev_zone(char *fqdn) { int error; - char *my_ip; - struct in_addr addr; + char my_ip[INET6_ADDRSTRLEN]; smb_niciter_t ni; int rc; char fqhn[MAXHOSTNAMELEN]; + const char *my_str; if (!smb_config_getbool(SMB_CI_DYNDNS_ENABLE)) return (0); @@ -2005,10 +2140,9 @@ dyndns_clear_rev_zone(char *fqdn) do { if (ni.ni_nic.nic_sysflags & IFF_PRIVATE) continue; - - addr.s_addr = ni.ni_nic.nic_ip; - my_ip = (char *)strdup(inet_ntoa(addr)); - if (my_ip == NULL) { + my_str = smb_inet_ntop(&ni.ni_nic.nic_ip, my_ip, + SMB_IPSTRLEN(ni.ni_nic.nic_ip.a_family)); + if (my_str == NULL) { error++; continue; } @@ -2017,7 +2151,6 @@ dyndns_clear_rev_zone(char *fqdn) if (rc != 0) error++; - (void) free(my_ip); } while (smb_nic_getnext(&ni) == 0); return ((error == 0) ? 0 : -1); diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c index c280a89e28..fc03dc66c6 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_datagram.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Description: * @@ -316,7 +314,7 @@ int smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest, unsigned char *data, int length) { - uint32_t ipaddr; + smb_inaddr_t ipaddr; size_t count, srclen, destlen, sinlen; struct addr_entry *addr; struct sockaddr_in sin; @@ -375,12 +373,13 @@ smb_netbios_datagram_send(struct name_entry *src, struct name_entry *dest, sinlen = sizeof (sin); addr = &dest->addr_list; do { - ipaddr = addr->sin.sin_addr.s_addr; + ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; + ipaddr.a_family = AF_INET; /* Don't send anything to myself... */ - if (smb_nic_exists(ipaddr, B_FALSE)) + if (smb_nic_exists(&ipaddr, B_FALSE)) goto next; - sin.sin_addr.s_addr = ipaddr; + sin.sin_addr.s_addr = ipaddr.a_ipv4; sin.sin_port = addr->sin.sin_port; (void) sendto(datagram_sock, buffer, count, 0, (struct sockaddr *)&sin, sinlen); @@ -396,7 +395,7 @@ int smb_netbios_datagram_send_to_net(struct name_entry *src, struct name_entry *dest, char *data, int length) { - uint32_t ipaddr; + smb_inaddr_t ipaddr; size_t count, srclen, destlen, sinlen; struct addr_entry *addr; struct sockaddr_in sin; @@ -455,11 +454,12 @@ smb_netbios_datagram_send_to_net(struct name_entry *src, sinlen = sizeof (sin); addr = &dest->addr_list; do { - ipaddr = addr->sin.sin_addr.s_addr; - if (smb_nic_exists(ipaddr, B_FALSE)) + ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; + ipaddr.a_family = AF_INET; + if (smb_nic_exists(&ipaddr, B_FALSE)) goto next; - sin.sin_addr.s_addr = ipaddr; + sin.sin_addr.s_addr = ipaddr.a_ipv4; sin.sin_port = addr->sin.sin_port; (void) sendto(datagram_sock, buffer, count, 0, (struct sockaddr *)&sin, sinlen); @@ -951,6 +951,7 @@ smb_netbios_datagram_service_daemon(void *arg) struct sockaddr_in sin; struct datagram *datagram; int bytes, flag = 1; + smb_inaddr_t ipaddr; (void) mutex_lock(&smb_dgq_mtx); bzero(&smb_datagram_queue, sizeof (smb_datagram_queue)); @@ -1005,8 +1006,9 @@ ignore: bzero(&datagram->inaddr, sizeof (struct addr_entry)); } /* Ignore any incoming packets from myself... */ - if (smb_nic_exists(datagram->inaddr.sin.sin_addr.s_addr, - B_FALSE)) { + ipaddr.a_ipv4 = datagram->inaddr.sin.sin_addr.s_addr; + ipaddr.a_family = AF_INET; + if (smb_nic_exists(&ipaddr, B_FALSE)) { goto ignore; } diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c index fc92a5e36a..97436fc7ae 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netbios_name.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2134,6 +2134,7 @@ smb_send_node_status_response(struct addr_entry *addr, unsigned char *scan_end; unsigned char data[MAX_NETBIOS_REPLY_DATA_SIZE]; boolean_t scan_done = B_FALSE; + smb_inaddr_t ipaddr; bzero(&packet, sizeof (struct name_packet)); bzero(&answer, sizeof (struct resource_record)); @@ -2160,7 +2161,9 @@ smb_send_node_status_response(struct addr_entry *addr, scan_end = data + MAX_NETBIOS_REPLY_DATA_SIZE; - if (smb_nic_exists(addr->sin.sin_addr.s_addr, B_TRUE)) + ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; + ipaddr.a_family = AF_INET; + if (smb_nic_exists(&ipaddr, B_TRUE)) net_ipaddr = addr->sin.sin_addr.s_addr; else net_ipaddr = 0; @@ -4584,12 +4587,14 @@ smb_netbios_name_config(void) continue; smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host, - 0x00, 0, ni.ni_nic.nic_ip, htons(DGM_SRVC_UDP_PORT), + 0x00, 0, ni.ni_nic.nic_ip.a_ipv4, + htons(DGM_SRVC_UDP_PORT), NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name); (void) smb_netbios_cache_insert(&name); smb_init_name_struct((unsigned char *)ni.ni_nic.nic_host, - 0x20, 0, ni.ni_nic.nic_ip, htons(DGM_SRVC_UDP_PORT), + 0x20, 0, ni.ni_nic.nic_ip.a_ipv4, + htons(DGM_SRVC_UDP_PORT), NAME_ATTR_UNIQUE, NAME_ATTR_LOCAL, &name); (void) smb_netbios_cache_insert(&name); } while (smb_nic_getnext(&ni) == 0); @@ -4643,6 +4648,7 @@ smb_netbios_name_service_daemon(void *arg) int flag = 1; char *buf; worker_param_t *worker_param; + smb_inaddr_t ipaddr; /* * Initialize reply_queue @@ -4719,7 +4725,10 @@ ignore: bzero(addr, sizeof (struct addr_entry)); } /* Ignore any incoming packets from myself... */ - if (smb_nic_exists(addr->sin.sin_addr.s_addr, B_FALSE)) + + ipaddr.a_ipv4 = addr->sin.sin_addr.s_addr; + ipaddr.a_family = AF_INET; + if (smb_nic_exists(&ipaddr, B_FALSE)) goto ignore; /* diff --git a/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c index ab1bf3c29d..484b3ada97 100644 --- a/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c +++ b/usr/src/lib/smbsrv/libsmbns/common/smbns_netlogon.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -480,15 +480,14 @@ smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr) { static int initialized = 0; uint32_t ipaddr; - uint32_t prefer_ipaddr = 0; - char ipstr[16]; - char srcip[16]; + uint32_t prefer_ipaddr; + char ipstr[INET_ADDRSTRLEN]; + char srcip[INET_ADDRSTRLEN]; int rc; - (void) inet_ntop(AF_INET, (const void *)(&src_ipaddr), - srcip, sizeof (srcip)); + (void) inet_ntop(AF_INET, &src_ipaddr, srcip, INET_ADDRSTRLEN); - rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, ipstr, sizeof (ipstr)); + rc = smb_config_getstr(SMB_CI_DOMAIN_SRV, ipstr, INET_ADDRSTRLEN); if (rc == SMBD_SMF_OK) { rc = inet_pton(AF_INET, ipstr, &prefer_ipaddr); if (rc == 0) @@ -505,8 +504,8 @@ smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr) ntdomain_info.n_domain, src_name, srcip); if (ntdomain_info.n_ipaddr != 0) { - if (prefer_ipaddr != 0 && prefer_ipaddr == - ntdomain_info.n_ipaddr) { + if (prefer_ipaddr != 0 && + prefer_ipaddr == ntdomain_info.n_ipaddr) { syslog(LOG_DEBUG, "DC for %s: %s [%s]", ntdomain_info.n_domain, src_name, srcip); (void) mutex_unlock(&ntdomain_mtx); @@ -533,17 +532,24 @@ smb_netlogon_rdc_rsp(char *src_name, uint32_t src_ipaddr) static int smb_better_dc(uint32_t cur_ip, uint32_t new_ip) { + smb_inaddr_t ipaddr; + /* * If we don't have any current DC, * then use the new one of course. */ + if (cur_ip == 0) return (1); - if (smb_nic_exists(cur_ip, B_TRUE)) + ipaddr.a_family = AF_INET; + ipaddr.a_ipv4 = cur_ip; + if (smb_nic_exists(&ipaddr, B_TRUE)) return (0); - if (smb_nic_exists(new_ip, B_TRUE)) + ipaddr.a_family = AF_INET; + ipaddr.a_ipv4 = new_ip; + if (smb_nic_exists(&ipaddr, B_TRUE)) return (1); /* * Otherwise, just keep the old one. diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h index 7cf7c5b20d..9046cad16b 100644 --- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h +++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -110,7 +110,7 @@ typedef struct sdb_logon { struct sdb_session { char srv_name[MAXHOSTNAMELEN]; - uint32_t srv_ipaddr; + smb_inaddr_t srv_ipaddr; char domain[MAXHOSTNAMELEN]; char scope[SMB_PI_MAX_SCOPE]; char native_os[SMB_PI_MAX_NATIVE_OS]; diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c index 5f6531b8f1..c6612f71e1 100644 --- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c +++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_logon.c @@ -19,14 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -/* - * SMB session logon and logoff functions. See CIFS section 4.1. - */ - #include <pthread.h> #include <string.h> #include <strings.h> @@ -39,12 +35,13 @@ #include <arpa/inet.h> #include <smbsrv/wintypes.h> #include <smbsrv/libsmbrdr.h> -#include <smbsrv/libmlsvc.h> #include <smbsrv/ntstatus.h> #include <smbsrv/smb.h> #include <smbrdr_ipc_util.h> #include <smbrdr.h> +#define SMBRDR_ANON_USER "IPC$" + static int smbrdr_anonymous_logon(char *domain_controller, char *domain_name); static int smbrdr_auth_logon(char *domain_controller, char *domain_name, char *username); @@ -58,16 +55,16 @@ static int smbrdr_authenticate(char *, char *, char *, unsigned char *); /* * mlsvc_logon * - * If the username is MLSVC_ANON_USER, an anonymous session will be established. - * Otherwise, an authenticated session will be established based on the - * specified credentials. + * If the username is SMBRDR_ANON_USER, an anonymous session will be + * established. Otherwise, an authenticated session will be established + * based on the specified credentials. */ int mlsvc_logon(char *domain_controller, char *domain, char *username) { int rc; - if (strcmp(username, MLSVC_ANON_USER) == 0) + if (strcmp(username, SMBRDR_ANON_USER) == 0) rc = smbrdr_anonymous_logon(domain_controller, domain); else rc = smbrdr_auth_logon(domain_controller, domain, username); @@ -85,7 +82,7 @@ mlsvc_logon(char *domain_controller, char *domain, char *username) static int smbrdr_anonymous_logon(char *domain_controller, char *domain_name) { - if (smbrdr_logon_validate(domain_controller, MLSVC_ANON_USER)) + if (smbrdr_logon_validate(domain_controller, SMBRDR_ANON_USER)) return (0); if (smbrdr_negotiate(domain_controller, domain_name) != 0) { @@ -93,7 +90,7 @@ smbrdr_anonymous_logon(char *domain_controller, char *domain_name) return (-1); } - if (smbrdr_logon_user(domain_controller, MLSVC_ANON_USER, 0) < 0) { + if (smbrdr_logon_user(domain_controller, SMBRDR_ANON_USER, 0) < 0) { syslog(LOG_DEBUG, "smbrdr_anonymous_logon: logon failed"); return (-1); } @@ -207,7 +204,7 @@ smbrdr_logon_user(char *server, char *username, unsigned char *pwd) int ret; if ((server == NULL) || (username == NULL) || - ((strcmp(username, MLSVC_ANON_USER) != 0) && (pwd == NULL))) + ((strcmp(username, SMBRDR_ANON_USER) != 0) && (pwd == NULL))) return (-1); session = smbrdr_session_lock(server, 0, SDB_SLCK_WRITE); diff --git a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c index 19982ab8d9..9e8d60d38c 100644 --- a/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c +++ b/usr/src/lib/smbsrv/libsmbrdr/common/smbrdr_session.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,10 +46,10 @@ #include <smbsrv/netbios.h> #include <smbsrv/cifs.h> #include <smbsrv/ntstatus.h> -#include <smbsrv/libmlsvc.h> #include <smbrdr.h> #include <smbrdr_ipc_util.h> +#define SMBRDR_DOMAIN_MAX 32 static uint16_t smbrdr_ports[] = { SMB_SRVC_TCP_PORT, @@ -58,7 +58,7 @@ static uint16_t smbrdr_ports[] = { static int smbrdr_nports = sizeof (smbrdr_ports) / sizeof (smbrdr_ports[0]); -static struct sdb_session session_table[MLSVC_DOMAIN_MAX]; +static struct sdb_session session_table[SMBRDR_DOMAIN_MAX]; static mutex_t smbrdr_screate_mtx; static uint32_t session_id = 0; @@ -229,22 +229,35 @@ smbrdr_trnsprt_connect(struct sdb_session *sess, uint16_t port) { char hostname[MAXHOSTNAMELEN]; struct sockaddr_in sin; + struct sockaddr_in6 sin6; int sock, rc; mts_wchar_t unicode_server_name[SMB_PI_MAX_DOMAIN]; char server_name[SMB_PI_MAX_DOMAIN]; unsigned int cpid = oem_get_smb_cpid(); + char ipstr[INET6_ADDRSTRLEN]; - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) <= 0) { + if ((sock = socket(sess->srv_ipaddr.a_family, SOCK_STREAM, 0)) <= 0) { syslog(LOG_DEBUG, "smbrdr: socket failed: %s", strerror(errno)); return (-1); } + if (sess->srv_ipaddr.a_family == AF_INET) { + bzero(&sin, sizeof (struct sockaddr_in)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = sess->srv_ipaddr.a_ipv4; + sin.sin_port = htons(port); + rc = connect(sock, (struct sockaddr *)&sin, sizeof (sin)); + } else { + (void) smb_inet_ntop(&sess->srv_ipaddr, ipstr, + SMB_IPSTRLEN(sess->srv_ipaddr.a_family)); + bzero(&sin6, sizeof (struct sockaddr_in6)); + sin6.sin6_family = AF_INET6; + bcopy(&sess->srv_ipaddr.a_ipv6, &sin6.sin6_addr.s6_addr, + IPV6_ADDR_LEN); + sin6.sin6_port = htons(port); + rc = connect(sock, (struct sockaddr *)&sin6, sizeof (sin6)); + } - bzero(&sin, sizeof (struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = sess->srv_ipaddr; - sin.sin_port = htons(port); - - if ((rc = connect(sock, (struct sockaddr *)&sin, sizeof (sin))) < 0) { + if (rc < 0) { syslog(LOG_DEBUG, "smbrdr: connect failed: %s", strerror(errno)); if (sock != 0) @@ -391,7 +404,7 @@ static struct sdb_session * smbrdr_session_init(char *domain_controller, char *domain) { struct sdb_session *session = NULL; - uint32_t ipaddr; + smb_inaddr_t ipaddr; int i, rc; struct hostent *h; @@ -405,9 +418,10 @@ smbrdr_session_init(char *domain_controller, char *domain) } (void) memcpy(&ipaddr, h->h_addr, h->h_length); + ipaddr.a_family = h->h_addrtype; freehostent(h); - for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) { + for (i = 0; i < SMBRDR_DOMAIN_MAX; ++i) { session = &session_table[i]; (void) rw_wrlock(&session->rwl); @@ -526,7 +540,7 @@ smbrdr_session_lock(char *server, char *username, int lmode) if (server == NULL) return (NULL); - for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) { + for (i = 0; i < SMBRDR_DOMAIN_MAX; ++i) { session = &session_table[i]; (lmode == SDB_SLCK_READ) ? (void) rw_rdlock(&session->rwl) : @@ -594,18 +608,16 @@ smbrdr_dump_sessions(void) { struct sdb_session *session; struct sdb_logon *logon; - char ipstr[16]; + char ipstr[INET6_ADDRSTRLEN]; int i; - for (i = 0; i < MLSVC_DOMAIN_MAX; ++i) { + for (i = 0; i < SMBRDR_DOMAIN_MAX; ++i) { session = &session_table[i]; (void) rw_rdlock(&session->rwl); if (session->state != SDB_SSTATE_START) { - (void) inet_ntop(AF_INET, - (const void *)(&session->srv_ipaddr), - ipstr, sizeof (ipstr)); - + (void) smb_inet_ntop(&session->srv_ipaddr, ipstr, + SMB_IPSTRLEN(session->srv_ipaddr.a_family)); syslog(LOG_DEBUG, "session[%d]: state=%d", i, session->state); syslog(LOG_DEBUG, "session[%d]: %s %s (%s)", i, diff --git a/usr/src/pkgdefs/etc/exception_list_i386 b/usr/src/pkgdefs/etc/exception_list_i386 index e322e77cc3..a81a4443ad 100644 --- a/usr/src/pkgdefs/etc/exception_list_i386 +++ b/usr/src/pkgdefs/etc/exception_list_i386 @@ -1026,6 +1026,7 @@ usr/include/smbsrv/smb_fsops.h i386 usr/include/smbsrv/smb_i18n.h i386 usr/include/smbsrv/smb_idmap.h i386 usr/include/smbsrv/smb_incl.h i386 +usr/include/smbsrv/smb_inet.h i386 usr/include/smbsrv/smb_ioctl.h i386 usr/include/smbsrv/smb_kproto.h i386 usr/include/smbsrv/smb_kstat.h i386 @@ -1038,7 +1039,6 @@ usr/include/smbsrv/smb_vops.h i386 usr/include/smbsrv/smb_xdr.h i386 usr/include/smbsrv/smbfmt.h i386 usr/include/smbsrv/smbinfo.h i386 -usr/include/smbsrv/smbtrans.h i386 usr/include/smbsrv/string.h i386 usr/include/smbsrv/svrapi.h i386 usr/include/smbsrv/winioctl.h i386 diff --git a/usr/src/pkgdefs/etc/exception_list_sparc b/usr/src/pkgdefs/etc/exception_list_sparc index 8cf51d87dc..834b4c05b6 100644 --- a/usr/src/pkgdefs/etc/exception_list_sparc +++ b/usr/src/pkgdefs/etc/exception_list_sparc @@ -1124,6 +1124,7 @@ usr/include/smbsrv/smb_fsops.h sparc usr/include/smbsrv/smb_i18n.h sparc usr/include/smbsrv/smb_idmap.h sparc usr/include/smbsrv/smb_incl.h sparc +usr/include/smbsrv/smb_inet.h sparc usr/include/smbsrv/smb_ioctl.h sparc usr/include/smbsrv/smb_kproto.h sparc usr/include/smbsrv/smb_kstat.h sparc @@ -1136,7 +1137,6 @@ usr/include/smbsrv/smb_vops.h sparc usr/include/smbsrv/smb_xdr.h sparc usr/include/smbsrv/smbfmt.h sparc usr/include/smbsrv/smbinfo.h sparc -usr/include/smbsrv/smbtrans.h sparc usr/include/smbsrv/string.h sparc usr/include/smbsrv/svrapi.h sparc usr/include/smbsrv/winioctl.h sparc diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index bc0664cdca..ecefe16b9f 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1033,6 +1033,7 @@ NFSSRV_OBJS += nfs_server.o nfs_srv.o nfs3_srv.o \ nfs4_deleg_ops.o nfs4_srv_readdir.o nfs4_dispatch.o SMBSRV_SHARED_OBJS += \ + smb_inet.o \ smb_match.o \ smb_msgbuf.o \ smb_oem.o \ @@ -1056,7 +1057,6 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \ smb_check_directory.o \ smb_close.o \ smb_common_open.o \ - smb_common_search.o \ smb_common_transact.o \ smb_create.o \ smb_create_directory.o \ @@ -1066,7 +1066,6 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \ smb_echo.o \ smb_fem.o \ smb_find.o \ - smb_find_unique.o \ smb_flush.o \ smb_fsops.o \ smb_init.o \ @@ -1106,7 +1105,6 @@ SMBSRV_OBJS += $(SMBSRV_SHARED_OBJS) \ smb_read.o \ smb_rename.o \ smb_sd.o \ - smb_search.o \ smb_seek.o \ smb_server.o \ smb_session.o \ diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_open.c b/usr/src/uts/common/fs/smbsrv/smb_common_open.c index b7a085bb30..960b0d06a9 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_common_open.c +++ b/usr/src/uts/common/fs/smbsrv/smb_common_open.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -548,7 +548,8 @@ smb_open_subr(smb_request_t *sr) if ((!(op->desired_access & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA))) || - (!smb_sattr_check(&node->attr, NULL, op->dattr))) { + (!smb_sattr_check(node->attr.sa_dosattr, + op->dattr, NULL))) { rw_exit(&node->n_share_lock); smb_node_release(node); smb_node_release(dnode); diff --git a/usr/src/uts/common/fs/smbsrv/smb_common_search.c b/usr/src/uts/common/fs/smbsrv/smb_common_search.c deleted file mode 100644 index 474d40de95..0000000000 --- a/usr/src/uts/common/fs/smbsrv/smb_common_search.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -/* - * Implementation of smb_rdir_open, smb_rdir_next and smb_rdir_close. - */ - -#include <smbsrv/smb_incl.h> -#include <smbsrv/smb_fsops.h> - -/* - * smb_rdir_open - */ -int -smb_rdir_open(smb_request_t *sr, char *path, unsigned short sattr) -{ - smb_odir_t *od; - smb_node_t *node; - char *last_component; - int rc; - - last_component = kmem_alloc(MAXNAMELEN, KM_SLEEP); - - if ((rc = smb_pathname_reduce(sr, sr->user_cr, path, - sr->tid_tree->t_snode, sr->tid_tree->t_snode, - &node, last_component)) != 0) { - kmem_free(last_component, MAXNAMELEN); - smbsr_errno(sr, rc); - return (-1); - } - - if ((node->vp)->v_type != VDIR) { - smb_node_release(node); - kmem_free(last_component, MAXNAMELEN); - smbsr_error(sr, 0, ERRDOS, ERRbadpath); - return (-1); - } - - rc = smb_fsop_access(sr, sr->user_cr, node, FILE_LIST_DIRECTORY); - if (rc != 0) { - smb_node_release(node); - kmem_free(last_component, MAXNAMELEN); - - if (sr->smb_com == SMB_COM_SEARCH) { - smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, - ERRDOS, ERROR_NO_MORE_FILES); - return (-2); - } else { - smbsr_error(sr, NT_STATUS_ACCESS_DENIED, - ERRDOS, ERROR_ACCESS_DENIED); - return (-1); - } - } - - od = smb_odir_open(sr->tid_tree, node, last_component, sr->smb_pid, - sattr); - kmem_free(last_component, sizeof (od->d_pattern)); - if (od == NULL) { - smb_node_release(node); - smbsr_error(sr, 0, ERRDOS, ERROR_NO_MORE_FILES); - return (-1); - } - - sr->smb_sid = od->d_sid; - sr->sid_odir = od; - return (0); -} - - -/* - * smb_rdir_next - * - * Returns: - * 0 Found an entry - * ENOENT There is no (more) entry - * error code An error happened - */ -int -smb_rdir_next( - smb_request_t *sr, - smb_node_t **rnode, - smb_odir_context_t *pc) -{ - struct smb_odir *dir; - ino64_t fileid; - int rc, n_name; - char last_component[MAXNAMELEN]; - char namebuf[MAXNAMELEN]; - smb_node_t *tmp_snode; - smb_node_t *dnode; - smb_node_t *fnode; - smb_attr_t ret_attr; - - ASSERT(sr->sid_odir); - dir = sr->sid_odir; - - if (dir->d_state == SMB_ODIR_STATE_CLOSED) { - return (ENOENT); - } - - if (dir->d_wildcards == 0) { - /* There are no wildcards in pattern */ - if (pc->dc_cookie != 0) { - /* Already found entry... */ - return (ENOENT); - } - - pc->dc_name[0] = '\0'; - pc->dc_shortname[0] = '\0'; - pc->dc_name83[0] = '\0'; - - rc = smb_fsop_lookup(sr, sr->user_cr, 0, - sr->tid_tree->t_snode, dir->d_dir_snode, dir->d_pattern, - &fnode, &pc->dc_attr, pc->dc_shortname, pc->dc_name83); - - if (rc != 0) - return (rc); - - /* - * We are here if there was a successful lookup of the - * name. The name may be a mangled name. If it was, - * then shortname has the copy of it. So, we may - * not need to do mangling later. - * - * dir->name will contain the case-preserved name. - * If that name is not available (this should not - * happen), then copy dir->pattern into dir->name. - */ - - if (fnode->od_name) { - (void) strcpy(pc->dc_name, fnode->od_name); - } else { - (void) strcpy(pc->dc_name, dir->d_pattern); - } - - /* Root of file system? */ - if ((strcmp(dir->d_pattern, "..") == 0) && - (dir->d_dir_snode == sr->tid_tree->t_snode)) { - smb_node_release(fnode); - smb_node_ref(sr->tid_tree->t_snode); - fnode = sr->tid_tree->t_snode; - } else if (pc->dc_attr.sa_vattr.va_type == VLNK) { - (void) strcpy(namebuf, dir->d_pattern); - - tmp_snode = fnode; - rc = smb_pathname_reduce(sr, sr->user_cr, namebuf, - sr->tid_tree->t_snode, dir->d_dir_snode, - &dnode, last_component); - - if (rc != 0) { - fnode = tmp_snode; - } else { - rc = smb_fsop_lookup(sr, sr->user_cr, - SMB_FOLLOW_LINKS, sr->tid_tree->t_snode, - dnode, last_component, &fnode, &ret_attr, - 0, 0); - - smb_node_release(dnode); - if (rc != 0) { - fnode = tmp_snode; - } else { - pc->dc_attr = ret_attr; - smb_node_release(tmp_snode); - } - } - } - - pc->dc_dattr = smb_node_get_dosattr(fnode); - - /* Obey search attributes */ - if (!smb_sattr_check(&fnode->attr, pc->dc_name, dir->d_sattr)) { - smb_node_release(fnode); - return (ENOENT); - } - - /* - * If name not already mangled, do it. - * - * The name will only be mangled if smb_needs_mangle() - * determines that it is required. Mangling due to - * case-insensitive collisions is not necessary here. - */ - if (pc->dc_name83[0] == '\0') - (void) smb_mangle_name(fnode->attr.sa_vattr.va_nodeid, - pc->dc_name, pc->dc_shortname, pc->dc_name83, 0); - if (rnode) - *rnode = fnode; - else - smb_node_release(fnode); - - pc->dc_cookie = (uint32_t)-1; - return (0); - } - - /* There are wildcards in pattern */ - for (;;) { - if (dir->d_state == SMB_ODIR_STATE_CLOSED) { - return (ENOENT); - } - - /* sizeof dir->name == 256 */ - n_name = (sizeof (pc->dc_name)) - 1; - - rc = smb_fsop_readdir(sr, sr->user_cr, dir->d_dir_snode, - &pc->dc_cookie, pc->dc_name, &n_name, &fileid, NULL, - NULL, NULL); - if (rc != 0) { - return (rc); - } - - if (n_name == 0) /* EOF */ - break; - pc->dc_name[n_name] = '\0'; - - /* - * Don't return "." or ".." unless FILE_ATTRIBUTE_HIDDEN - * is set. We have to code this by hand because these are - * virtual directory entries and they are not hidden. - */ - if (((dir->d_sattr & FILE_ATTRIBUTE_HIDDEN) == 0) && - smb_is_dot_or_dotdot(pc->dc_name)) { - continue; - } - - /* may match a mangled name or "real" name */ - if (smb_component_match(sr, fileid, dir, pc) <= 0) - continue; - - /* Look up the "real" name */ - rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode, - dir->d_dir_snode, pc->dc_name, &fnode, &pc->dc_attr, 0, 0); - - if (rc != 0) { - if (rc != ENOENT) - return (rc); - - continue; - } - - /* Root of file system? */ - if ((strcmp(pc->dc_name, "..") == 0) && - (dir->d_dir_snode == sr->tid_tree->t_snode)) { - smb_node_release(fnode); - smb_node_ref(sr->tid_tree->t_snode); - fnode = sr->tid_tree->t_snode; - } else if (pc->dc_attr.sa_vattr.va_type == VLNK) { - (void) strcpy(namebuf, pc->dc_name); - - smb_node_release(fnode); - rc = smb_pathname_reduce(sr, sr->user_cr, namebuf, - sr->tid_tree->t_snode, dir->d_dir_snode, &dnode, - last_component); - - if (rc != 0) { - continue; - } - - rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, - sr->tid_tree->t_snode, dnode, last_component, - &fnode, &ret_attr, 0, 0); - - smb_node_release(dnode); - if (rc != 0) { - continue; - } - pc->dc_attr = ret_attr; - } - - pc->dc_dattr = smb_node_get_dosattr(fnode); - - /* Obey search attributes */ - if (!smb_sattr_check(&fnode->attr, NULL, dir->d_sattr)) { - smb_node_release(fnode); - continue; - } - - if (rnode) - *rnode = fnode; - else - smb_node_release(fnode); - - return (0); - } - - return (ENOENT); -} - -/* - * smb_rdir_close - */ -void -smb_rdir_close(struct smb_request *sr) -{ - smb_odir_t *od = sr->sid_odir; - - ASSERT(od); - ASSERT(od->d_magic == SMB_ODIR_MAGIC); - - smb_odir_close(od); - smb_odir_release(od); - sr->sid_odir = NULL; -} diff --git a/usr/src/uts/common/fs/smbsrv/smb_delete.c b/usr/src/uts/common/fs/smbsrv/smb_delete.c index baa4d80d34..213f04650e 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_delete.c +++ b/usr/src/uts/common/fs/smbsrv/smb_delete.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,7 +31,7 @@ static int smb_delete_check_path(smb_request_t *, boolean_t *); static int smb_delete_single_file(smb_request_t *, smb_error_t *); static int smb_delete_multiple_files(smb_request_t *, smb_error_t *); -static int smb_delete_find_fname(smb_request_t *, uint32_t *); +static int smb_delete_find_fname(smb_request_t *, smb_odir_t *); static int smb_delete_check_attr(smb_request_t *, smb_error_t *); static int smb_delete_remove_file(smb_request_t *, smb_error_t *); @@ -254,7 +254,7 @@ smb_delete_single_file(smb_request_t *sr, smb_error_t *err) /* * smb_delete_multiple_files * - * For each matching file found by smb_delete_find_name: + * For each matching file found by smb_delete_find_fname: * 1. lookup file * 2. check the file's attributes * - The search ends with an error if a readonly file @@ -273,14 +273,24 @@ static int smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err) { int rc, deleted = 0; - uint32_t cookie = 0; smb_fqi_t *fqi; smb_attr_t ret_attr; + uint16_t odid; + smb_odir_t *od; fqi = &sr->arg.dirop.fqi; + /* + * Specify all search attributes (SMB_SEARCH_ATTRIBUTES) so that + * delete-specific checking can be done (smb_delete_check_attr). + */ + if ((odid = smb_odir_open(sr, fqi->path, SMB_SEARCH_ATTRIBUTES)) == 0) + return (-1); + if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) + return (-1); + for (;;) { - rc = smb_delete_find_fname(sr, &cookie); + rc = smb_delete_find_fname(sr, od); if (rc != 0) break; @@ -293,6 +303,8 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err) if (smb_delete_check_attr(sr, err) != 0) { smb_node_release(fqi->last_snode); if (err->status == NT_STATUS_CANNOT_DELETE) { + smb_odir_release(od); + smb_odir_close(od); return (-1); } if ((err->status == NT_STATUS_FILE_IS_A_DIRECTORY) && @@ -311,10 +323,14 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err) continue; } + smb_odir_release(od); + smb_odir_close(od); smb_node_release(fqi->last_snode); return (-1); } + smb_odir_release(od); + smb_odir_close(od); if ((rc != 0) && (rc != ENOENT)) { smbsr_map_errno(rc, err); @@ -336,42 +352,52 @@ smb_delete_multiple_files(smb_request_t *sr, smb_error_t *err) * Find next filename that matches search pattern (fqi->last_comp) * and save it in fqi->last_comp_od. * + * Case insensitivity note: + * If the tree is case insensitive and there's a case conflict + * with the name returned from smb_odir_read, smb_delete_find_fname + * performs case conflict name mangling to produce a unique filename. + * This ensures that any subsequent smb_fsop_lookup, (which will + * find the first case insensitive match) will find the correct file. + * * Returns: 0 - success * errno */ static int -smb_delete_find_fname(smb_request_t *sr, uint32_t *cookie) +smb_delete_find_fname(smb_request_t *sr, smb_odir_t *od) { - int rc, n_name; - ino64_t fileid; - smb_fqi_t *fqi; - char name83[SMB_SHORTNAMELEN]; - char shortname[SMB_SHORTNAMELEN]; - boolean_t ignore_case; + int rc; + smb_odirent_t *odirent; + boolean_t eos; + char *name; + char shortname[SMB_SHORTNAMELEN]; + char name83[SMB_SHORTNAMELEN]; + smb_fqi_t *fqi; fqi = &sr->arg.dirop.fqi; + odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); - ignore_case = SMB_TREE_IS_CASEINSENSITIVE(sr); - - for (;;) { - n_name = sizeof (fqi->last_comp_od) - 1; - - rc = smb_fsop_readdir(sr, sr->user_cr, fqi->dir_snode, cookie, - fqi->last_comp_od, &n_name, &fileid, NULL, NULL, NULL); - - if (rc != 0) - return (rc); - - /* check for EOF */ - if (n_name == 0) - return (ENOENT); - - fqi->last_comp_od[n_name] = '\0'; + rc = smb_odir_read(sr, od, odirent, &eos); + if (rc != 0) { + kmem_free(odirent, sizeof (smb_odirent_t)); + return (rc); + } + if (eos) { + kmem_free(odirent, sizeof (smb_odirent_t)); + return (ENOENT); + } - if (smb_match_name(fileid, fqi->last_comp_od, shortname, name83, - fqi->last_comp, ignore_case)) - return (0); + /* if case conflict, force mangle and use shortname */ + if ((od->d_ignore_case) && (odirent->od_eflags & ED_CASE_CONFLICT)) { + (void) smb_mangle_name(odirent->od_ino, odirent->od_name, + shortname, name83, 1); + name = shortname; + } else { + name = odirent->od_name; } + (void) strlcpy(fqi->last_comp_od, name, sizeof (fqi->last_comp_od)); + + kmem_free(odirent, sizeof (smb_odirent_t)); + return (0); } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c index 04aecdbac1..c5461501c0 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_dispatch.c +++ b/usr/src/uts/common/fs/smbsrv/smb_dispatch.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * @@ -548,9 +548,6 @@ smbsr_cleanup(smb_request_t *sr) if (sr->fid_ofile) smbsr_disconnect_file(sr); - if (sr->sid_odir) - smbsr_disconnect_dir(sr); - if (sr->r_xa) { if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE) smb_xa_close(sr->r_xa); @@ -590,9 +587,7 @@ smb_dispatch_request(struct smb_request *sr) ASSERT(sr->tid_tree == 0); ASSERT(sr->uid_user == 0); ASSERT(sr->fid_ofile == 0); - ASSERT(sr->sid_odir == 0); sr->smb_fid = (uint16_t)-1; - sr->smb_sid = (uint16_t)-1; /* temporary until we identify a user */ sr->user_cr = kcred; @@ -1173,15 +1168,6 @@ smbsr_disconnect_file(smb_request_t *sr) (void) smb_ofile_release(of); } -void -smbsr_disconnect_dir(smb_request_t *sr) -{ - smb_odir_t *od = sr->sid_odir; - - sr->sid_odir = NULL; - smb_odir_release(od); -} - static int is_andx_com(unsigned char com) { diff --git a/usr/src/uts/common/fs/smbsrv/smb_find.c b/usr/src/uts/common/fs/smbsrv/smb_find.c index 3b23d1fccb..c6aae31f55 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_find.c +++ b/usr/src/uts/common/fs/smbsrv/smb_find.c @@ -19,196 +19,362 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)smb_find.c 1.7 08/07/30 SMI" - -#include <smbsrv/smb_incl.h> - /* + * smb_com_search + * smb_com_find, smb_com_find_close + * smb_find_unique + * + * These commands are used for directory searching. They share the same + * message formats, defined below: + * + * Client Request Description + * ---------------------------------- --------------------------------- + * + * UCHAR WordCount; Count of parameter words = 2 + * USHORT MaxCount; Number of dir. entries to return + * USHORT SearchAttributes; + * USHORT ByteCount; Count of data bytes; min = 5 + * UCHAR BufferFormat1; 0x04 -- ASCII + * UCHAR FileName[]; File name, may be null + * UCHAR BufferFormat2; 0x05 -- Variable block + * USHORT ResumeKeyLength; Length of resume key, may be 0 + * UCHAR ResumeKey[]; Resume key + * + * FileName specifies the file to be sought. SearchAttributes indicates + * the attributes that the file must have. If SearchAttributes is + * zero then only normal files are returned. If the system file, hidden or + * directory attributes are specified then the search is inclusive - both the + * specified type(s) of files and normal files are returned. If the volume + * label attribute is specified then the search is exclusive, and only the + * volume label entry is returned. + * + * MaxCount specifies the number of directory entries to be returned. + * + * Server Response Description + * ---------------------------------- --------------------------------- + * + * UCHAR WordCount; Count of parameter words = 1 + * USHORT Count; Number of entries returned + * USHORT ByteCount; Count of data bytes; min = 3 + * UCHAR BufferFormat; 0x05 -- Variable block + * USHORT DataLength; Length of data + * UCHAR DirectoryInformationData[]; Data + * + * The response will contain one or more directory entries as determined by + * the Count field. No more than MaxCount entries will be returned. Only + * entries that match the sought FileName and SearchAttributes combination + * will be returned. + * + * ResumeKey must be null (length = 0) on the initial search request. + * Subsequent search requests intended to continue a search must contain + * the ResumeKey field extracted from the last directory entry of the + * previous response. ResumeKey is self-contained, for calls containing + * a non-zero ResumeKey neither the SearchAttributes or FileName fields + * will be valid in the request. ResumeKey has the following format: + * + * Resume Key Field Description + * ---------------------------------- --------------------------------- + * + * UCHAR Reserved; bit 7 - consumer use + * bits 5,6 - system use (must preserve) + * bits 0-4 - server use (must preserve) + * UCHAR FileName[11]; Name of the returned file + * UCHAR ReservedForServer[5]; Client must not modify + * byte 0 - uniquely identifies find + * through find_close + * bytes 1-4 - available for server use + * (must be non-zero) + * UCHAR ReservedForConsumer[4]; Server must not modify + * + * FileName is 8.3 format, with the three character extension left + * justified into FileName[9-11]. + * + * There may be multiple matching entries in response to a single request + * as wildcards are supported in the last component of FileName of the + * initial request. + * + * Returned directory entries in the DirectoryInformationData field of the + * response each have the following format: + * + * Directory Information Field Description + * ---------------------------------- --------------------------------- + * + * SMB_RESUME_KEY ResumeKey; Described above + * UCHAR FileAttributes; Attributes of the found file + * SMB_TIME LastWriteTime; Time file was last written + * SMB_DATE LastWriteDate; Date file was last written + * ULONG FileSize; Size of the file + * UCHAR FileName[13]; ASCII, space-filled null terminated + * + * FileName must conform to 8.3 rules, and is padded after the extension + * with 0x20 characters if necessary. + * + * As can be seen from the above structure, these commands cannot return + * long filenames, and cannot return UNICODE filenames. + * + * Files which have a size greater than 2^32 bytes should have the least + * significant 32 bits of their size returned in FileSize. + * + * smb_com_search + * -------------- + * + * If the client is prior to the LANMAN1.0 dialect, the returned FileName + * should be uppercased. + * If the client has negotiated a dialect prior to the LANMAN1.0 dialect, + * or if bit0 of the Flags2 SMB header field of the request is clear, + * the returned FileName should be uppercased. + * + * SMB_COM_SEARCH terminates when either the requested maximum number of + * entries that match the named file are found, or the end of directory is + * reached without the maximum number of matches being found. A response + * containing no entries indicates that no matching entries were found + * between the starting point of the search and the end of directory. + * + * + * The find, find_close and find_unique protocols may be used in place of + * the core "search" protocol when LANMAN 1.0 dialect has been negotiated. + * * smb_com_find + * ------------ * - * Request Format: (same as core Search Protocol - "Find First" form) - * - * Client Request Description - * ================================== ================================= - * - * BYTE smb_wct; value = 2 - * WORD smb_count; max number of entries to find - * WORD smb_attr; search attribute - * WORD smb_bcc; minimum value = 5 - * BYTE smb_ident1; ASCII (04) - * BYTE smb_pathname[]; filename (may contain global characters) - * BYTE smb_ident2; Variable Block (05) - * WORD smb_keylen; resume key length (zero if "Find First") - * BYTE smb_resumekey[*]; "Find Next" key, * = value of smb_keylen - * - * Response Format: (same as core Search Protocol) - * - * Server Response Description - * ================================== ================================= - * BYTE smb_wct; value = 1 - * WORD smb_count; number of entries found - * WORD smb_bcc; minimum value = 3 - * BYTE smb_ident; Variable Block (05) - * WORD smb_datalen; data length - * BYTE smb_data[*]; directory entries - * - * Directory Information Entry (dir_info) Format: (same as core Search Protocol) - * - * BYTE find_buf_reserved[21]; reserved (resume_key) - * BYTE find_buf_attr; attribute - * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx) - * where 'xxxxx' is in 2 second increments - * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd) - * DWORD find_buf_size; file size - * STRING find_buf_pname[13]; file name -- ASCII (null terminated) - * - * The resume_key has the following format: - * - * BYTE sr_res; reserved: - * bit 7 - reserved for consumer use - * bit 5,6 - reserved for system use - * (must be preserved) - * bits 0-4 - reserved for server - * (must be preserved) - * BYTE sr_name[11]; pathname sought. - * Format: 1-8 character file name, - * left justified 0-3 character extension, - * BYTE sr_findid[1]; uniquely identifies find through - * find_close - * BYTE sr_server[4]; available for server use - * (must be non-zero) - * BYTE sr_res[4]; reserved for consumer use - * - * Service: - * - * The Find protocol finds the directory entry or group of entries matching the - * specified file pathname. The filename portion of the pathname may contain - * global (wild card) characters. - * - * The Find protocol is used to match the find OS/2 system call. The protocols - * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching) - * a directory. These protocols may be used in place of the core "Search" - * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases - * where the Search protocol will still be used. - * - * The format of the Find protocol is the same as the core "Search" protocol. - * The difference is that the directory is logically Opened with a Find protocol - * and logically closed with the Find Close protocol. This allows the Server to - * make better use of its resources. Search buffers are thus held (allowing - * search resumption via presenting a "resume_key") until a Find Close protocol - * is received. The sr_findid field of each resume key is a unique identifier - * (within the session) of the search from "Find" through "Find close". Thus if - * the consumer does "Find ahead", any find buffers containing resume keys with - * the matching find id may be released when the Find Close is requested. - * - * As is true of a failing open, if a Find request (Find "first" request where + * The find protocol is used to match the find OS/2 system call. + * + * The format of the find protocol is the same as the core "search" protocol. + * The difference is that the directory is logically Opened with a find protocol + * and logically closed with the find close protocol. + * As is true of a failing open, if a find request (find "first" request where * resume_key is null) fails (no entries are found), no find close protocol is * expected. * - * If no global characters are present, a "Find Unique" protocol should be used + * If no global characters are present, a "find unique" protocol should be used * (only one entry is expected and find close need not be sent). * - * The file path name in the request specifies the file to be sought. The - * attribute field indicates the attributes that the file must have. If the - * attribute is zero then only normal files are returned. If the system file, - * hidden or directory attributes are specified then the search is inclusive -- - * both the specified type(s) of files and normal files are returned. If the - * volume label attribute is specified then the search is exclusive, and only - * the volume label entry is returned - * - * The max-count field specifies the number of directory entries to be returned. - * The response will contain zero or more directory entries as determined by the - * count-returned field. No more than max-count entries will be returned. Only - * entries that match the sought filename/attribute will be returned. - * - * The resume_key field must be null (length = 0) on the initial ("Find First") - * find request. Subsequent find requests intended to continue a search must - * contain the resume_key field extracted from the last directory entry of the - * previous response. The resume_key field is self-contained, for on calls - * containing a resume_key neither the attribute or pathname fields will be - * valid in the request. A find request will terminate when either the - * requested maximum number of entries that match the named file are found, or - * the end of directory is reached without the maximum number of matches being - * found. A response containing no entries indicates that no matching entries - * were found between the starting point of the search and the end of directory. - * - * There may be multiple matching entries in response to a single request as - * Find supports "wild cards" in the file name (last component of the pathname). - * "?" is the wild single characters, "*" or "null" will match any number of - * filename characters within a single part of the filename component. The - * filename is divided into two parts -- an eight character name and a three - * character extension. The name and extension are divided by a ".". - * - * If a filename part commences with one or more "?"s then exactly that number - * of characters will be matched by the Wild Cards, e.g., "??x" will equal "abx" - * but not "abcx" or "ax". When a filename part has trailing "?"s then it will - * match the specified number of characters or less, e.g., "x??" will match - * "xab", "xa" and "x", but not "xabc". If only "?"s are present in the filename - * part, then it is handled as for trailing "?"s "*" or "null" match entire - * pathname parts, thus "*.abc" or ".abc" will match any file with an extension - * of "abc". "*.*", "*" or "null" will match all files in a directory. - * - * Unprotected servers require the requester to have read permission on the - * subtree containing the directory searched (the share specifies read - * permission). - * - * Protected servers require the requester to have permission to search the - * specified directory. - * - * If a Find requests more data than can be placed in a message of the + * A find request will terminate when either the requested maximum number of + * entries that match the named file are found, or the end of directory is + * reached without the maximum number of matches being found. A response + * containing no entries indicates that no matching entries were found between + * the starting point of the search and the end of directory. + * + * If a find requests more data than can be placed in a message of the * max-xmit-size for the TID specified, the server will return only the number * of entries which will fit. * - * The number of entries returned will be the minimum of: - * 1. The number of entries requested. - * 2. The number of (complete) entries that will fit in the negotiated SMB - * buffer. - * 3. The number of entries that match the requested name pattern and - * attributes. - * - * The error ERRnofiles set in smb_err field of the response header or a zero - * value in smb_count of the response indicates no matching entry was found. - * - * The resume search key returned along with each directory entry is a server - * defined key which when returned in the Find Next protocol, allows the - * directory search to be resumed at the directory entry fol lowing the one - * denoted by the resume search key. - * - * The date is in the following format: - * bits: - * 1 1 1 1 1 1 - * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * y y y y y y y m m m m d d d d d - * where: - * y - bit of year 0-119 (1980-2099) - * m - bit of month 1-12 - * d - bit of day 1-31 - * - * The time is in the following format: - * bits: - * 1 1 1 1 1 1 - * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * h h h h h m m m m m m x x x x x - * where: - * h - bit of hour (0-23) - * m - bit of minute (0-59) - * x - bit of 2 second increment - * - * Find may generate the following errors. - * ERRDOS/ERRnofiles - * ERRDOS/ERRbadpath - * ERRDOS/ERRnoaccess - * ERRDOS/ERRbadaccess - * ERRDOS/ERRbadshare - * ERRSRV/ERRerror - * ERRSRV/ERRaccess - * ERRSRV/ERRinvnid + * + * smb_com_find_close + * ------------------ + * + * The find close protocol is used to match the find close OS/2 system call. + * + * Whereas the first find protocol logically opens the directory, subsequent + * find protocols presenting a resume_key further "read" the directory, the + * find close protocol "closes" the directory allowing the server to free any + * resources held in support of the directory search. + * + * In our implementation this translates to closing the odir. + * + * + * smb_com_find_unique + * ------------------- + * + * The format of the find unique protocol is the same as the core "search" + * protocol. The difference is that the directory is logically opened, any + * matching entries returned, and then the directory is logically closed. + * + * The resume search key key will be returned as in the find protocol and + * search protocol however it may NOT be returned to continue the search. + * Only one buffer of entries is expected and find close need not be sent. + * + * If a find unique requests more data than can be placed in a message of the + * max-xmit-size for the TID specified, the server will abort the virtual + * circuit to the consumer. */ + +#include <smbsrv/smb_incl.h> + +/* *** smb_com_search *** */ + +smb_sdrc_t +smb_pre_search(smb_request_t *sr) +{ + DTRACE_SMB_1(op__Search__start, smb_request_t *, sr); + return (SDRC_SUCCESS); +} + +void +smb_post_search(smb_request_t *sr) +{ + DTRACE_SMB_1(op__Search__done, smb_request_t *, sr); +} + +smb_sdrc_t +smb_com_search(smb_request_t *sr) +{ + int rc; + uint16_t count, maxcount, index; + uint16_t sattr, odid; + uint16_t key_len; + uint32_t client_key; + char name[SMB_SHORTNAMELEN]; + char *path; + unsigned char resume_char; + unsigned char type; + boolean_t find_first, to_upper; + smb_tree_t *tree; + smb_odir_t *od; + smb_fileinfo_t fileinfo; + smb_odir_resume_t odir_resume; + boolean_t eos; + + to_upper = B_FALSE; + if ((sr->session->dialect <= LANMAN1_0) || + ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) { + to_upper = B_TRUE; + } + + /* We only handle 8.3 name here */ + sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES; + sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE; + + if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) + return (SDRC_ERROR); + + rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); + if ((rc != 0) || (type != 0x05)) + return (SDRC_ERROR); + + tree = sr->tid_tree; + + /* Volume information only */ + if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) { + (void) memset(name, ' ', sizeof (name)); + (void) strncpy(name, tree->t_volume, sizeof (name)); + + if (key_len >= 21) { + (void) smb_mbc_decodef(&sr->smb_data, "17.l", + &client_key); + } else { + client_key = 0; + } + + (void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c", + 1, 0, VAR_BCC, 5, 0, 0, path+1, + client_key, sattr, name); + + rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; + (void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", + 1, 1, rc+3, 5, rc); + + return (SDRC_SUCCESS); + } + + if ((key_len != 0) && (key_len != 21)) + return (SDRC_ERROR); + + find_first = (key_len == 0); + resume_char = 0; + client_key = 0; + + if (find_first) { + /* NT interprets NULL filename as "\" */ + if (strlen(path) == 0) + path = "\\"; + + odid = smb_odir_open(sr, path, sattr); + if (odid == 0) { + if (sr->smb_error.status == NT_STATUS_ACCESS_DENIED) + smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, + ERRDOS, ERROR_NO_MORE_FILES); + return (SDRC_ERROR); + } + } else { + if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", + &resume_char, &index, &odid, &client_key) != 0) { + return (SDRC_ERROR); + } + } + + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, + ERRDOS, ERROR_INVALID_HANDLE); + return (SDRC_ERROR); + } + + if (!find_first) { + odir_resume.or_type = SMB_ODIR_RESUME_IDX; + odir_resume.or_idx = index; + smb_odir_resume_at(od, &odir_resume); + } + + (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); + + rc = 0; + index = 0; + count = 0; + if (maxcount > SMB_MAX_SEARCH) + maxcount = SMB_MAX_SEARCH; + + while (count < maxcount) { + rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); + if ((rc != 0 || (eos == B_TRUE))) + break; + + if (smb_is_dot_or_dotdot(fileinfo.fi_name)) + continue; + + if (*fileinfo.fi_shortname == NULL) { + (void) strlcpy(fileinfo.fi_shortname, + fileinfo.fi_name, SMB_SHORTNAMELEN - 1); + if (to_upper) + (void) utf8_strupr(fileinfo.fi_shortname); + } + + (void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c", + resume_char, + fileinfo.fi_name83, fileinfo.fi_name83+9, + index, odid, client_key, + fileinfo.fi_dosattr & 0xff, + smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec), + (int32_t)fileinfo.fi_size, + fileinfo.fi_shortname); + + smb_odir_save_cookie(od, index, fileinfo.fi_cookie); + + count++; + index++; + } + smb_odir_release(od); + + if (rc != 0) { + smb_odir_close(od); + return (SDRC_ERROR); + } + + if (count == 0 && find_first) { + smb_odir_close(od); + smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, + ERRDOS, ERROR_NO_MORE_FILES); + return (SDRC_ERROR); + } + + rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; + if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", + 1, count, rc+3, 5, rc) < 0) { + smb_odir_close(od); + return (SDRC_ERROR); + } + + return (SDRC_SUCCESS); +} + + +/* *** smb_com_find *** */ + smb_sdrc_t smb_pre_find(smb_request_t *sr) { @@ -226,17 +392,19 @@ smb_sdrc_t smb_com_find(smb_request_t *sr) { int rc; - unsigned short sattr, count, maxcount; + uint16_t count, maxcount, index; + uint16_t sattr, odid; + uint16_t key_len; + uint32_t client_key; + smb_odir_t *od; + smb_fileinfo_t fileinfo; + boolean_t eos; + char *path; unsigned char resume_char; - uint32_t client_key; - uint16_t index; - uint32_t cookie; - struct smb_node *node; unsigned char type; - unsigned short key_len; - smb_odir_context_t *pc; boolean_t find_first = B_TRUE; + smb_odir_resume_t odir_resume; if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) return (SDRC_ERROR); @@ -245,78 +413,78 @@ smb_com_find(smb_request_t *sr) if ((rc != 0) || (type != 0x05)) return (SDRC_ERROR); - if (key_len == 0) { /* begin search */ - if (smb_rdir_open(sr, path, sattr) != 0) + if ((key_len != 0) && (key_len != 21)) + return (SDRC_ERROR); + + find_first = (key_len == 0); + resume_char = 0; + client_key = 0; + + if (find_first) { + odid = smb_odir_open(sr, path, sattr); + if (odid == 0) return (SDRC_ERROR); - cookie = 0; - } else if (key_len == 21) { - sr->smb_sid = 0; + } else { if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", - &resume_char, &index, &sr->smb_sid, &client_key) != 0) { - /* We don't know which rdir to close */ - return (SDRC_ERROR); - } - - sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, - sr->smb_sid); - if (sr->sid_odir == NULL) { - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, - ERRDOS, ERRbadfid); + &resume_char, &index, &odid, &client_key) != 0) { return (SDRC_ERROR); } + } - cookie = sr->sid_odir->d_cookies[index]; - if (cookie != 0) - find_first = B_FALSE; - } else { - /* We don't know which rdir to close */ + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, + ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } + if (!find_first) { + odir_resume.or_type = SMB_ODIR_RESUME_IDX; + odir_resume.or_idx = index; + smb_odir_resume_at(od, &odir_resume); + } + (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); - pc = kmem_zalloc(sizeof (smb_odir_context_t), KM_SLEEP); - pc->dc_cookie = cookie; + rc = 0; index = 0; count = 0; - node = NULL; - rc = 0; - if (maxcount > SMB_MAX_SEARCH) maxcount = SMB_MAX_SEARCH; while (count < maxcount) { - if ((rc = smb_rdir_next(sr, &node, pc)) != 0) + rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); + if ((rc != 0 || (eos == B_TRUE))) break; + if (*fileinfo.fi_shortname == NULL) { + (void) strlcpy(fileinfo.fi_shortname, + fileinfo.fi_name, SMB_SHORTNAMELEN - 1); + } + (void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c", resume_char, - pc->dc_name83, pc->dc_name83+9, - index, sr->smb_sid, client_key, - pc->dc_dattr & 0xff, - smb_gmt2local(sr, pc->dc_attr.sa_vattr.va_mtime.tv_sec), - (int32_t)smb_node_get_size(node, &pc->dc_attr), - (*pc->dc_shortname) ? pc->dc_shortname : - pc->dc_name); - - smb_node_release(node); - node = NULL; - sr->sid_odir->d_cookies[index] = pc->dc_cookie; + fileinfo.fi_name83, fileinfo.fi_name83+9, + index, odid, client_key, + fileinfo.fi_dosattr & 0xff, + smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec), + (int32_t)fileinfo.fi_size, + fileinfo.fi_shortname); + + smb_odir_save_cookie(od, index, fileinfo.fi_cookie); + count++; index++; } + smb_odir_release(od); - kmem_free(pc, sizeof (smb_odir_context_t)); - - if ((rc != 0) && (rc != ENOENT)) { - /* returned error by smb_rdir_next() */ - smb_rdir_close(sr); - smbsr_errno(sr, rc); + if (rc != 0) { + smb_odir_close(od); return (SDRC_ERROR); } if (count == 0 && find_first) { - smb_rdir_close(sr); + smb_odir_close(od); smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, ERRDOS, ERROR_NO_MORE_FILES); return (SDRC_ERROR); @@ -325,91 +493,16 @@ smb_com_find(smb_request_t *sr) rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", 1, count, rc+3, 5, rc) < 0) { - smb_rdir_close(sr); + smb_odir_close(od); return (SDRC_ERROR); } return (SDRC_SUCCESS); } -/* - * smb_com_find_close - * - * Request Format: (same as core Search Protocol - "Find Next" form) - * - * Client Request Description - * ================================== ================================= - * - * BYTE smb_wct; value = 2 - * WORD smb_count; max number of entries to find - * WORD smb_attr; search attribute - * WORD smb_bcc; minimum value = 5 - * BYTE smb_ident1; ASCII (04) - * BYTE smb_pathname[]; null (may contain only null) - * BYTE smb_ident2; Variable Block (05) - * WORD smb_keylen; resume (close) key length - * (may not be zero) - * BYTE smb_resumekey[*]; "Find Close" key - * (* = value of smb_keylen) - * - * Response Format: (same format as core Search Protocol) - * - * Server Response Description - * ================================== ================================= - * - * BYTE smb_wct; value = 1 - * WORD smb_reserved; reserved - * WORD smb_bcc; value = 3 - * BYTE smb_ident; Variable Block (05) - * WORD smb_datalen; data length (value = 0) - * - * The resume_key (or close key) has the following format: - * - * BYTE sr_res; reserved: - * bit 7 - reserved for consumer use - * bit 5,6 - reserved for system use - * (must be preserved) - * bits 0-4 - rsvd for server - * (must be preserved by consumer) - * BYTE sr_name[11]; pathname sought. - * Format: 1-8 character file name, - * left justified 0-3 character extension, - * left justified (in last 3 chars) - * BYTE sr_findid[1]; uniquely identifies find - * through find_close - * BYTE sr_server[4]; available for server use - * (must be non-zero) - * BYTE sr_res[4]; reserved for consumer use - * - * Service: - * - * The Find_Close protocol closes the association between a Find id - * returned (in the resume_key) by the Find protocol and the directory - * search. - * - * Whereas the First Find protocol logically opens the directory, - * subsequent find protocols presenting a resume_key further "read" the - * directory, the Find Close protocol "closes" the directory allowing the - * server to free any resources held in support of the directory search. - * - * The Find Close protocol is used to match the find Close OS/2 - * system call. The protocols "Find", "Find Unique" and "Find Close" are - * methods of reading (or searching) a directory. These protocols may - * be used in place of the core "Search" protocol when LANMAN 1.0 dialect has - * been negotiated. There may be cases where the Search protocol will still be - * used. - * - * Although only the find id portion the resume key should be - * required to identify the search being ter minated, the entire - * resume_key as returned in the previous Find, either a "Find First" or "Find - * Next" is sent to the server in this protocol. - * - * Find Close may generate the following errors: - * - * ERRDOS/ERRbadfid - * ERRSRV/ERRerror - * ERRSRV/ERRinvnid - */ + +/* *** smb_com_find_close *** */ + smb_sdrc_t smb_pre_find_close(smb_request_t *sr) { @@ -426,14 +519,15 @@ smb_post_find_close(smb_request_t *sr) smb_sdrc_t smb_com_find_close(smb_request_t *sr) { - unsigned short sattr, maxcount; - char *path; - unsigned char resume_char; - uint32_t resume_key; - uint16_t index; - unsigned char type; - unsigned short key_len; - int rc; + int rc; + uint16_t maxcount, index; + uint16_t sattr, odid; + uint16_t key_len; + uint32_t client_key; + char *path; + unsigned char resume_char; + unsigned char type; + smb_odir_t *od; if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) return (SDRC_ERROR); @@ -442,31 +536,132 @@ smb_com_find_close(smb_request_t *sr) if ((rc != 0) || (type != 0x05)) return (SDRC_ERROR); - if (key_len == 0) { /* begin search */ - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); + if (key_len == 0) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, + ERRDOS, ERROR_INVALID_HANDLE); + return (SDRC_ERROR); + } else if (key_len != 21) { return (SDRC_ERROR); } - if (key_len == 21) { - sr->smb_sid = 0; - if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", - &resume_char, &index, &sr->smb_sid, &resume_key) != 0) { - return (SDRC_ERROR); - } + odid = 0; + if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", + &resume_char, &index, &odid, &client_key) != 0) { + return (SDRC_ERROR); + } - sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, - sr->smb_sid); - if (sr->sid_odir == NULL) { - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, - ERRDOS, ERRbadfid); - return (SDRC_ERROR); - } - } else { + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, + ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } - smb_rdir_close(sr); + smb_odir_release(od); + smb_odir_close(od); + if (smbsr_encode_result(sr, 1, 3, "bwwbw", 1, 0, 3, 5, 0)) return (SDRC_ERROR); + + return (SDRC_SUCCESS); +} + + +/* *** smb_com_find_unique *** */ + +smb_sdrc_t +smb_pre_find_unique(smb_request_t *sr) +{ + DTRACE_SMB_1(op__FindUnique__start, smb_request_t *, sr); + return (SDRC_SUCCESS); +} + +void +smb_post_find_unique(smb_request_t *sr) +{ + DTRACE_SMB_1(op__FindUnique__done, smb_request_t *, sr); +} + +smb_sdrc_t +smb_com_find_unique(struct smb_request *sr) +{ + int rc; + uint16_t count, maxcount, index; + uint16_t sattr, odid; + char *path; + unsigned char resume_char = '\0'; + uint32_t client_key = 0; + smb_odir_t *od; + smb_fileinfo_t fileinfo; + boolean_t eos; + struct vardata_block *vdb; + + if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) + return (SDRC_ERROR); + + vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP); + if ((smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) || + (vdb->len != 0)) { + kmem_free(vdb, sizeof (struct vardata_block)); + return (SDRC_ERROR); + } + kmem_free(vdb, sizeof (struct vardata_block)); + + (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); + + odid = smb_odir_open(sr, path, sattr); + if (odid == 0) + return (SDRC_ERROR); + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) + return (SDRC_ERROR); + + rc = 0; + count = 0; + index = 0; + if (maxcount > SMB_MAX_SEARCH) + maxcount = SMB_MAX_SEARCH; + + while (count < maxcount) { + rc = smb_odir_read_fileinfo(sr, od, &fileinfo, &eos); + if ((rc != 0 || (eos == B_TRUE))) + break; + + if (*fileinfo.fi_shortname == NULL) { + (void) strlcpy(fileinfo.fi_shortname, + fileinfo.fi_name, SMB_SHORTNAMELEN - 1); + } + + (void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c", + resume_char, + fileinfo.fi_name83, fileinfo.fi_name83+9, + index, odid, client_key, + fileinfo.fi_dosattr & 0xff, + smb_gmt2local(sr, fileinfo.fi_mtime.tv_sec), + (int32_t)fileinfo.fi_size, + fileinfo.fi_shortname); + + count++; + index++; + } + + smb_odir_release(od); + smb_odir_close(od); + + if (rc != 0) + return (SDRC_ERROR); + + if (count == 0) { + smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, + ERRDOS, ERROR_NO_MORE_FILES); + return (SDRC_ERROR); + } + + rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; + if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, + "bwwbw", 1, count, rc+3, 5, rc) < 0) { + return (SDRC_ERROR); + } + return (SDRC_SUCCESS); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_find_unique.c b/usr/src/uts/common/fs/smbsrv/smb_find_unique.c deleted file mode 100644 index d9d48dcf5c..0000000000 --- a/usr/src/uts/common/fs/smbsrv/smb_find_unique.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "@(#)smb_find_unique.c 1.6 08/07/30 SMI" - -#include <smbsrv/smb_incl.h> - -/* - * Request Format: (same as core Search Protocol - "Find First" form) - * - * Client Request Description - * ================================== ================================= - * - * BYTE smb_wct; value = 2 - * WORD smb_count; max number of entries to find - * WORD smb_attr; search attribute - * WORD smb_bcc; minimum value = 5 - * BYTE smb_ident1; ASCII (04) - * BYTE smb_pathname[]; filename (may contain global characters) - * BYTE smb_ident2; Variable Block (05) - * WORD smb_keylen; must be zero ("Find First" only) - * - * Response Format: (same as core Search Protocol) - * - * Server Response Description - * ================================== ================================= - * BYTE smb_wct; value = 1 - * WORD smb_count; number of entries found - * WORD smb_bcc; minimum value = 3 - * BYTE smb_ident; Variable Block (05) - * WORD smb_datalen; data length - * BYTE smb_data[*]; directory entries - * - * Directory Information Entry (dir_info) Format: (same as core Search Protocol) - * - * BYTE find_buf_reserved[21]; reserved (resume_key) - * BYTE find_buf_attr; attribute - * WORD find_buf_time; modification time (hhhhh mmmmmm xxxxx) - * where 'xxxxx' is in 2 second increments - * WORD find_buf_date; modification date (yyyyyyy mmmm ddddd) - * DWORD find_buf_size; file size - * STRING find_buf_pname[13]; file name -- ASCII (null terminated) - * - * The resume_key has the following format: - * - * BYTE sr_res; reserved: - * bit 7 - reserved for consumer use - * bit 5,6 - reserved for system use - * (must be preserved) - * bits 0-4 - reserved for server - * (must be preserved) - * BYTE sr_name[11]; pathname sought. - * Format: 1-8 character file name, - * left justified 0-3 character extension, - * BYTE sr_findid[1]; uniquely identifies find through - * find_close - * BYTE sr_server[4]; available for server use - * (must be non-zero) - * BYTE sr_res[4]; reserved for consumer use - * - * Service: - * - * The Find protocol finds the directory entry or group of entries matching the - * specified file pathname. The filename portion of the pathname may contain - * global (wild card) characters. The search may not be resumed and no Find - * Close protocol is expected. - * - * The Find protocol is used to match the find OS/2 system call. The protocols - * "Find", "Find_Unique" and "Find_Close" are methods of reading (or searching) - * a directory. These protocols may be used in place of the core "Search" - * protocol when LANMAN 1.0 dialect has been negotiated. There may be cases - * where the Search protocol will still be used. - * - * The format of the Find Unique protocol is the same as the core "Search" - * protocol. The difference is that the directory is logically opened , - * any matching entries returned, and then the directory is logically - * closed. - * - * This allows the Server to make better use of its resources. No Search buffers - * are held (search resumption via presenting a "resume_key" will not be - * allowed). - * - * Only one buffer of entries is expected and find close need not be sent). - * - * The file path name in the request specifies the file to be - * sought. The attribute field indicates the attributes that the file - * must have. If the attribute is zero then only normal files are - * returned. If the system file, hidden or directory attributes are - * specified then the search is inclusive -- both the specified type(s) - * of files and normal files are returned. If the volume label attribute - * is specified then the search is exclusive, and only the volume label entry - * is returned - * - * The max-count field specifies the number of directory entries to be - * returned. The response will contain zero or more directory entries - * as determined by the count-returned field. No more than max-count - * entries will be returned. Only entries that match the sought - * filename/attribute will be returned. - * - * The resume_key field must be null (length = 0). - * - * A Find_Unique request will terminate when either the requested maximum - * number of entries that match the named file are found, or the end - * of directory is reached without the maximum number of matches being - * found. A response containing no entries indicates that no matching - * entries were found between the starting point of the search and the end of - * directory. - * - * There may be multiple matching entries in response to a single - * request as Find Unique supports "wild cards" in the file name (last - * component of the pathname). "?" is the wild card for single - * characters, "*" or "null" will match any number of filename characters - * within a single part of the filename component. The filename is - * divided into two parts -- an eight character name and a three - * character extension. The name and extension are divided by a ".". - * - * If a filename part commences with one or more "?"s then exactly - * that number of characters will be matched by the Wild Cards, e.g., - * "??x" will equal "abx" but not "abcx" or "ax". When a filename part has - * trailing "?"s then it will match the specified number of characters - * or less, e.g., "x??" will match "xab", "xa" and "x", but not "xabc". If - * only "?"s are present in the filename part, then it is handled as - * for trailing "?"s - * - * "*" or "null" match entire pathname parts, thus "*.abc" or ".abc" will - * match any file with an extension of "abc". "*.*", "*" or "null" will - * match all files in a directory. - * - * Unprotected servers require the requester to have read permission on the - * subtree containing the directory searched, the share specifies read - * permission. - * - * Protected servers require the requester to have permission to search the - * specified directory. - * - * If a Find Unique requests more data than can be placed in a - * message of the max-xmit-size for the TID specified, the server will - * abort the virtual circuit to the consumer. - * - * The number of entries returned will be the minimum of: - * - * 1. The number of entries requested. - * 2. The number of complete entries that will fit in the - * negotiated SMB buffer. - * 3. The number of entries that match the requested name pattern and - * attributes. - * - * The error ERRnofiles set in smb_err field of the response header or a zero - * value in smb_count of the response indicates no matching entry was found. - * - * The resume search key returned along with each directory entry is a server - * defined key. This key will be returned as in the Find protocol and Search - * protocol however it may NOT be returned to continue the search. - * - * The date is in the following format: - * bits: - * 1 1 1 1 1 1 - * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * y y y y y y y m m m m d d d d d - * where: - * y - bit of year 0-119 (1980-2099) - * m - bit of month 1-12 - * d - bit of day 1-31 - * - * The time is in the following format: - * bits: - * 1 1 1 1 1 1 - * 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - * h h h h h m m m m m m x x x x x - * where: - * h - bit of hour (0-23) - * m - bit of minute (0-59) - * x - bit of 2 second increment - * - * Find Unique may generate the following errors. - * ERRDOS/ERRnofiles - * ERRDOS/ERRbadpath - * ERRDOS/ERRnoaccess - * ERRDOS/ERRbadaccess - * ERRDOS/ERRbadshare - * ERRSRV/ERRerror - * ERRSRV/ERRaccess - * ERRSRV/ERRinvnid - */ -smb_sdrc_t -smb_pre_find_unique(smb_request_t *sr) -{ - DTRACE_SMB_1(op__FindUnique__start, smb_request_t *, sr); - return (SDRC_SUCCESS); -} - -void -smb_post_find_unique(smb_request_t *sr) -{ - DTRACE_SMB_1(op__FindUnique__done, smb_request_t *, sr); -} - -smb_sdrc_t -smb_com_find_unique(struct smb_request *sr) -{ - int rc; - unsigned short sattr, count, maxcount; - char *path; - struct vardata_block *vdb; - struct smb_node *node; - uint16_t index; - unsigned char resume_char = '\0'; - uint32_t client_key = 0; - smb_odir_context_t *pc; - - vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP); - if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) { - kmem_free(vdb, sizeof (struct vardata_block)); - return (SDRC_ERROR); - } - - if (smbsr_decode_data(sr, "%AV", sr, &path, vdb) != 0) { - kmem_free(vdb, sizeof (struct vardata_block)); - return (SDRC_ERROR); - } - - if (vdb->len != 0) { - kmem_free(vdb, sizeof (struct vardata_block)); - return (SDRC_ERROR); - } - - (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, VAR_BCC, 5, 0); - - /* begin search */ - if (smb_rdir_open(sr, path, sattr) != 0) { - kmem_free(vdb, sizeof (struct vardata_block)); - return (SDRC_ERROR); - } - - pc = kmem_zalloc(sizeof (*pc), KM_SLEEP); - pc->dc_cookie = 0; - count = 0; - index = 0; - node = (struct smb_node *)0; - rc = 0; - - if (maxcount > SMB_MAX_SEARCH) - maxcount = SMB_MAX_SEARCH; - - while (count < maxcount) { - if ((rc = smb_rdir_next(sr, &node, pc)) != 0) - break; - - (void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c", - resume_char, - pc->dc_name83, pc->dc_name83+9, - index, sr->smb_sid, client_key, - pc->dc_dattr & 0xff, - smb_gmt2local(sr, pc->dc_attr.sa_vattr.va_mtime.tv_sec), - (int32_t)smb_node_get_size(node, &pc->dc_attr), - (*pc->dc_shortname) ? pc->dc_shortname : pc->dc_name); - - smb_node_release(node); - node = (struct smb_node *)0; - count++; - index++; - } - kmem_free(pc, sizeof (*pc)); - - smb_rdir_close(sr); - - if ((rc != 0) && (rc != ENOENT)) { - /* returned error by smb_rdir_next() */ - kmem_free(vdb, sizeof (struct vardata_block)); - smbsr_errno(sr, rc); - return (SDRC_ERROR); - } - - if (count == 0) { - kmem_free(vdb, sizeof (struct vardata_block)); - smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, - ERRDOS, ERROR_NO_MORE_FILES); - return (SDRC_ERROR); - } - - rc = (MBC_LENGTH(&sr->reply) - sr->cur_reply_offset) - 8; - if (smb_mbc_poke(&sr->reply, sr->cur_reply_offset, - "bwwbw", 1, count, rc+3, 5, rc) < 0) { - kmem_free(vdb, sizeof (struct vardata_block)); - return (SDRC_ERROR); - } - - kmem_free(vdb, sizeof (struct vardata_block)); - return (SDRC_SUCCESS); -} diff --git a/usr/src/uts/common/fs/smbsrv/smb_fsops.c b/usr/src/uts/common/fs/smbsrv/smb_fsops.c index 663462b9b2..c0e8978acf 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_fsops.c +++ b/usr/src/uts/common/fs/smbsrv/smb_fsops.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -236,10 +236,10 @@ smb_fsop_create_with_sd( *ret_snode = smb_node_lookup(sr, &sr->arg.open, cr, vp, name, dir_snode, NULL, ret_attr); - if (*ret_snode == NULL) { - VN_RELE(vp); + if (*ret_snode == NULL) rc = ENOMEM; - } + + VN_RELE(vp); } } else { /* @@ -271,9 +271,10 @@ smb_fsop_create_with_sd( rc = smb_fsop_sdwrite(sr, kcred, *ret_snode, fs_sd, 1); } else { - VN_RELE(vp); rc = ENOMEM; } + + VN_RELE(vp); } if (rc != 0) { @@ -447,10 +448,10 @@ smb_fsop_create( vp, sname, ret_attr); smb_node_release(fnode); + VN_RELE(xattrdirvp); + VN_RELE(vp); if (*ret_snode == NULL) { - VN_RELE(xattrdirvp); - VN_RELE(vp); kmem_free(fname, MAXNAMELEN); kmem_free(sname, MAXNAMELEN); return (ENOMEM); @@ -498,10 +499,10 @@ smb_fsop_create( *ret_snode = smb_node_lookup(sr, op, cr, vp, name, dir_snode, NULL, ret_attr); - if (*ret_snode == NULL) { - VN_RELE(vp); + if (*ret_snode == NULL) rc = ENOMEM; - } + + VN_RELE(vp); } } @@ -628,10 +629,10 @@ smb_fsop_mkdir( *ret_snode = smb_node_lookup(sr, op, cr, vp, name, dir_snode, NULL, ret_attr); - if (*ret_snode == NULL) { - VN_RELE(vp); + if (*ret_snode == NULL) rc = ENOMEM; - } + + VN_RELE(vp); } } @@ -785,15 +786,16 @@ smb_fsop_remove( * This function removes a file's streams without removing the * file itself. * - * It is assumed that snode is not a link. + * It is assumed that fnode is not a link. */ int smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) { - struct fs_stream_info stream_info; - uint32_t cookie = 0; - int flags = 0; - int rc; + int rc, flags = 0; + uint16_t odid; + smb_odir_t *od; + smb_odirent_t *odirent; + boolean_t eos; ASSERT(sr); ASSERT(cr); @@ -810,16 +812,24 @@ smb_fsop_remove_streams(smb_request_t *sr, cred_t *cr, smb_node_t *fnode) if (SMB_TREE_IS_CASEINSENSITIVE(sr)) flags = SMB_IGNORE_CASE; - for (;;) { - rc = smb_vop_stream_readdir(fnode->vp, &cookie, &stream_info, - NULL, NULL, flags, cr); + /* TBD - error codes */ + if ((odid = smb_odir_openat(sr, fnode)) == 0) + return (ENOENT); + if ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL) + return (ENOENT); - if ((rc != 0) || (cookie == SMB_EOF)) + odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); + for (;;) { + rc = smb_odir_read(sr, od, odirent, &eos); + if ((rc != 0) || (eos)) break; - - (void) smb_vop_stream_remove(fnode->vp, stream_info.name, flags, - cr); + (void) smb_vop_remove(od->d_dnode->vp, odirent->od_name, + flags, cr); } + kmem_free(odirent, sizeof (smb_odirent_t)); + + smb_odir_release(od); + smb_odir_close(od); return (rc); } @@ -971,188 +981,6 @@ smb_fsop_getattr(smb_request_t *sr, cred_t *cr, smb_node_t *snode, } /* - * smb_fsop_readdir - * - * All SMB functions should use this smb_fsop_readdir wrapper to ensure that - * the smb_vop_readdir is performed with the appropriate credentials. - * Please document any direct call to smb_vop_readdir to explain the reason - * for avoiding this wrapper. - * - * It is assumed that a reference exists on snode coming into this routine. - */ -int -smb_fsop_readdir( - smb_request_t *sr, - cred_t *cr, - smb_node_t *dir_snode, - uint32_t *cookie, - char *name, - int *namelen, - ino64_t *fileid, - struct fs_stream_info *stream_info, - smb_node_t **ret_snode, - smb_attr_t *ret_attr) -{ - smb_node_t *ret_snodep; - smb_node_t *fnode; - smb_attr_t tmp_attr; - vnode_t *xattrdirvp; - vnode_t *fvp; - vnode_t *vp = NULL; - char *od_name; - int rc; - int flags = 0; - - ASSERT(cr); - ASSERT(dir_snode); - ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); - ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); - - if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) - return (EACCES); - - if (*cookie == SMB_EOF) { - *namelen = 0; - return (0); - } - - if (SMB_TREE_IS_CASEINSENSITIVE(sr)) - flags = SMB_IGNORE_CASE; - - od_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); - - if (stream_info) { - rc = smb_vop_lookup(dir_snode->vp, name, &fvp, od_name, - SMB_FOLLOW_LINKS, sr->tid_tree->t_snode->vp, cr); - - if (rc != 0) { - kmem_free(od_name, MAXNAMELEN); - return (rc); - } - - fnode = smb_node_lookup(sr, NULL, cr, fvp, od_name, dir_snode, - NULL, ret_attr); - - kmem_free(od_name, MAXNAMELEN); - - if (fnode == NULL) { - VN_RELE(fvp); - return (ENOMEM); - } - - /* - * XXX - * Need to find out what permission(s) NTFS requires for getting - * a file's streams list. - * - * Might have to use kcred. - */ - rc = smb_vop_stream_readdir(fvp, cookie, stream_info, &vp, - &xattrdirvp, flags, cr); - - if ((rc != 0) || (*cookie == SMB_EOF)) { - smb_node_release(fnode); - return (rc); - } - - ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, - vp, stream_info->name, &tmp_attr); - - smb_node_release(fnode); - - if (ret_snodep == NULL) { - VN_RELE(xattrdirvp); - VN_RELE(vp); - return (ENOMEM); - } - - stream_info->size = tmp_attr.sa_vattr.va_size; - - if (ret_attr) - *ret_attr = tmp_attr; - - if (ret_snode) - *ret_snode = ret_snodep; - else - smb_node_release(ret_snodep); - - } else { - rc = smb_vop_readdir(dir_snode->vp, cookie, name, namelen, - fileid, &vp, od_name, flags, cr); - - if (rc != 0) { - kmem_free(od_name, MAXNAMELEN); - return (rc); - } - - if (*namelen) { - ASSERT(vp); - if (ret_attr || ret_snode) { - ret_snodep = smb_node_lookup(sr, NULL, cr, vp, - od_name, dir_snode, NULL, &tmp_attr); - - if (ret_snodep == NULL) { - kmem_free(od_name, MAXNAMELEN); - VN_RELE(vp); - return (ENOMEM); - } - - if (ret_attr) - *ret_attr = tmp_attr; - - if (ret_snode) - *ret_snode = ret_snodep; - else - smb_node_release(ret_snodep); - } - } - - kmem_free(od_name, MAXNAMELEN); - } - - return (rc); -} - -/* - * smb_fsop_getdents - * - * All SMB functions should use this smb_vop_getdents wrapper to ensure that - * the smb_vop_getdents is performed with the appropriate credentials. - * Please document any direct call to smb_vop_getdents to explain the reason - * for avoiding this wrapper. - * - * It is assumed that a reference exists on snode coming into this routine. - */ -/*ARGSUSED*/ -int -smb_fsop_getdents( - struct smb_request *sr, - cred_t *cr, - smb_node_t *dir_snode, - uint32_t *cookie, - uint64_t *verifierp, - int32_t *maxcnt, - char *args, - char *pattern) -{ - int flags = 0; - - ASSERT(cr); - ASSERT(dir_snode); - ASSERT(dir_snode->n_magic == SMB_NODE_MAGIC); - ASSERT(dir_snode->n_state != SMB_NODE_STATE_DESTROYING); - - if (SMB_TREE_CONTAINS_NODE(sr, dir_snode) == 0) - return (EACCES); - - if (SMB_TREE_IS_CASEINSENSITIVE(sr)) - flags = SMB_IGNORE_CASE; - - return (smb_vop_getdents(dir_snode, cookie, 0, maxcnt, args, pattern, - flags, sr, cr)); -} - -/* * smb_fsop_rename * * All SMB functions should use this smb_vop_rename wrapper to ensure that @@ -1229,17 +1057,14 @@ smb_fsop_rename( from_dir_snode, NULL, &tmp_attr); if (from_snode == NULL) { - VN_RELE(from_vp); - return (ENOMEM); + rc = ENOMEM; + } else { + (void) smb_node_rename(from_dir_snode, from_snode, + to_dir_snode, to_name); + smb_node_release(from_snode); } - - (void) smb_node_rename(from_dir_snode, from_snode, to_dir_snode, - to_name); - - smb_node_release(from_snode); - } else { - VN_RELE(from_vp); } + VN_RELE(from_vp); /* XXX: unlock */ @@ -1749,10 +1574,10 @@ smb_fsop_lookup_name( kmem_free(od_name, MAXNAMELEN); smb_node_release(fnode); + VN_RELE(xattrdirvp); + VN_RELE(vp); if (*ret_snode == NULL) { - VN_RELE(xattrdirvp); - VN_RELE(vp); kmem_free(fname, MAXNAMELEN); kmem_free(sname, MAXNAMELEN); return (ENOMEM); @@ -1794,7 +1619,7 @@ smb_fsop_lookup_name( * taken if an error is returned. * * Note: The returned ret_snode may be in a child mount. This is ok for - * readdir and getdents. + * readdir. * * ret_shortname and ret_name83 must each point to buffers of at least * SMB_SHORTNAMELEN bytes. @@ -1927,11 +1752,10 @@ smb_fsop_lookup( *ret_snode = smb_node_lookup(sr, NULL, cr, vp, lnk_target_node->od_name, lnk_dnode, NULL, ret_attr); + VN_RELE(vp); - if (*ret_snode == NULL) { - VN_RELE(vp); + if (*ret_snode == NULL) rc = ENOMEM; - } smb_node_release(lnk_target_node); } @@ -1948,81 +1772,16 @@ smb_fsop_lookup( *ret_snode = smb_node_lookup(sr, NULL, cr, vp, od_name, dir_snode, NULL, ret_attr); + VN_RELE(vp); - if (*ret_snode == NULL) { - VN_RELE(vp); + if (*ret_snode == NULL) rc = ENOMEM; - } } kmem_free(od_name, MAXNAMELEN); return (rc); } -/* - * smb_fsop_stream_readdir() - * - * ret_snode and ret_attr are optional parameters (i.e. NULL may be passed in) - * - * This routine will return only NTFS streams. If an NTFS stream is not - * found at the offset specified, the directory will be read until an NTFS - * stream is found or until EOF. - * - * Note: Sanity checks done in caller - * (smb_fsop_readdir(), smb_fsop_remove_streams()) - */ - -int -smb_fsop_stream_readdir(smb_request_t *sr, cred_t *cr, smb_node_t *fnode, - uint32_t *cookiep, struct fs_stream_info *stream_info, - smb_node_t **ret_snode, smb_attr_t *ret_attr) -{ - smb_node_t *ret_snodep = NULL; - smb_attr_t tmp_attr; - vnode_t *xattrdirvp; - vnode_t *vp; - int rc = 0; - int flags = 0; - - /* - * XXX NTFS permission requirements if any? - */ - ASSERT(cr); - ASSERT(fnode); - ASSERT(fnode->n_magic == SMB_NODE_MAGIC); - ASSERT(fnode->n_state != SMB_NODE_STATE_DESTROYING); - - if (SMB_TREE_IS_CASEINSENSITIVE(sr)) - flags = SMB_IGNORE_CASE; - - rc = smb_vop_stream_readdir(fnode->vp, cookiep, stream_info, &vp, - &xattrdirvp, flags, cr); - - if ((rc != 0) || *cookiep == SMB_EOF) - return (rc); - - ret_snodep = smb_stream_node_lookup(sr, cr, fnode, xattrdirvp, vp, - stream_info->name, &tmp_attr); - - if (ret_snodep == NULL) { - VN_RELE(xattrdirvp); - VN_RELE(vp); - return (ENOMEM); - } - - stream_info->size = tmp_attr.sa_vattr.va_size; - - if (ret_attr) - *ret_attr = tmp_attr; - - if (ret_snode) - *ret_snode = ret_snodep; - else - smb_node_release(ret_snodep); - - return (rc); -} - int /*ARGSUSED*/ smb_fsop_commit(smb_request_t *sr, cred_t *cr, smb_node_t *snode) { diff --git a/usr/src/uts/common/fs/smbsrv/smb_kshare.c b/usr/src/uts/common/fs/smbsrv/smb_kshare.c index b2dc834b96..50a921ecbc 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_kshare.c +++ b/usr/src/uts/common/fs/smbsrv/smb_kshare.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -65,7 +65,7 @@ smb_kshare_fini(door_handle_t dhdl) uint32_t smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si, - uint32_t ipaddr) + smb_inaddr_t *ipaddr) { door_arg_t arg; char *buf; @@ -80,7 +80,7 @@ smb_kshare_getinfo(door_handle_t dhdl, char *share_name, smb_share_t *si, enc_ctx = smb_dr_encode_start(buf, SMB_SHARE_DSIZE); smb_dr_put_uint32(enc_ctx, opcode); smb_dr_put_string(enc_ctx, share_name); - smb_dr_put_uint32(enc_ctx, ipaddr); + smb_dr_put_buf(enc_ctx, (uchar_t *)ipaddr, sizeof (smb_inaddr_t)); if (smb_dr_encode_finish(enc_ctx, &used) != 0) { kmem_free(buf, SMB_SHARE_DSIZE); diff --git a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c index bdd7834de0..a6075186af 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c +++ b/usr/src/uts/common/fs/smbsrv/smb_mangle_name.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -52,11 +52,12 @@ static int smb_match_reserved(char *name, char *rsrv); * there is a match. */ int -smb_match_name(ino64_t fileid, char *name, char *shortname, - char *name83, char *pattern, boolean_t ignore_case) +smb_match_name(ino64_t fileid, char *name, char *pattern, boolean_t ignore_case) { int rc = 0; int force; + char name83[SMB_SHORTNAMELEN]; + char shortname[SMB_SHORTNAMELEN]; /* Leading or trailing dots are disallowed */ if (smb_is_reserved_dos_name(name)) @@ -670,19 +671,17 @@ int smb_mangle_name( int smb_unmangle_name(struct smb_request *sr, cred_t *cred, smb_node_t *dir_node, char *name, char *real_name, int realname_size, char *shortname, - char *name83, int od) + char *name83, int ondisk) { int err; - int len; - int force = 0; - ino64_t inode; - uint32_t cookie; struct smb_node *snode = NULL; smb_attr_t ret_attr; - char *dot_pos = NULL; - char *readdir_name; - char *shortp; char namebuf[SMB_SHORTNAMELEN]; + char *path; + uint16_t odid; + smb_odir_t *od; + smb_odirent_t *odirent; + boolean_t eos; if (dir_node == NULL || name == NULL || real_name == NULL || realname_size == 0) @@ -692,7 +691,7 @@ smb_unmangle_name(struct smb_request *sr, cred_t *cred, smb_node_t *dir_node, snode = NULL; if (smb_maybe_mangled_name(name) == 0) { - if (od == 0) { + if (ondisk == 0) { (void) strlcpy(real_name, name, realname_size); return (0); } @@ -713,65 +712,42 @@ smb_unmangle_name(struct smb_request *sr, cred_t *cred, smb_node_t *dir_node, if (name83 == 0) name83 = namebuf; - cookie = 0; - - readdir_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); - - snode = NULL; - while (cookie != 0x7FFFFFFF) { - - len = realname_size - 1; + /* determine the pathname and open an smb_odir_t */ + path = kmem_alloc(MAXNAMELEN, KM_SLEEP); + if ((err = vnodetopath(sr->tid_tree->t_snode->vp, dir_node->vp, path, + MAXNAMELEN, kcred)) != 0) + return (err); - err = smb_fsop_readdir(sr, cred, dir_node, &cookie, - readdir_name, &len, &inode, NULL, &snode, &ret_attr); - - if (err || (cookie == 0x7FFFFFFF)) + if ((strlcat(path, "/*", MAXNAMELEN) >= MAXNAMELEN) || + ((odid = smb_odir_open(sr, path, SMB_SEARCH_ATTRIBUTES)) == 0) || + ((od = smb_tree_lookup_odir(sr->tid_tree, odid)) == NULL)) { + err = ENOENT; + } + kmem_free(path, MAXNAMELEN); + if (err != 0) + return (err); + + odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); + for (;;) { + err = smb_odir_read(sr, od, odirent, &eos); + if ((err != 0) || (eos)) break; - readdir_name[len] = 0; + (void) smb_mangle_name(odirent->od_ino, odirent->od_name, + shortname, name83, 1); - /* - * smb_fsop_readdir() may return a mangled name if the - * name has a case collision. - * - * If readdir_name is not a mangled name, we mangle - * readdir_name to see if it will match the name the - * client passed in. - * - * If smb_needs_mangle() does not succeed, we try again - * using the force flag. It is possible that the client - * is using a mangled name that resulted from a prior - * case collision which no longer exists in the directory. - * smb_needs_mangle(), with the force flag, will produce - * a mangled name regardless of whether the name passed in - * meets standard DOS criteria for name mangling. - */ - - if (smb_maybe_mangled_name(readdir_name)) { - shortp = readdir_name; - } else { - if (smb_needs_mangle(readdir_name, &dot_pos) == 0) - force = 1; - (void) smb_mangle_name(inode, readdir_name, shortname, - name83, force); - shortp = shortname; - } - - if (utf8_strcasecmp(name, shortp) == 0) { - kmem_free(readdir_name, MAXNAMELEN); - (void) strlcpy(real_name, snode->od_name, + if (utf8_strcasecmp(name, shortname) == 0) { + (void) strlcpy(real_name, odirent->od_name, realname_size); - - smb_node_release(snode); - + kmem_free(odirent, sizeof (smb_odirent_t)); + smb_odir_release(od); + smb_odir_close(od); return (0); - } else { - smb_node_release(snode); - snode = NULL; } } - kmem_free(readdir_name, MAXNAMELEN); - + kmem_free(odirent, sizeof (smb_odirent_t)); + smb_odir_release(od); + smb_odir_close(od); return (ENOENT); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c index 48f6e53458..01fee7371e 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_negotiate.c +++ b/usr/src/uts/common/fs/smbsrv/smb_negotiate.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -197,7 +197,6 @@ #include <smbsrv/smbinfo.h> #include <smbsrv/smb_i18n.h> - /* * Maximum buffer size for DOS: chosen to be the same as NT. * Do not change this value, DOS is very sensitive to it. @@ -255,7 +254,7 @@ smb_com_negotiate(smb_request_t *sr) int rc; unsigned short max_mpx_count; int16_t tz_correction; - char ipaddr_buf[INET_ADDRSTRLEN]; + char ipaddr_buf[INET6_ADDRSTRLEN]; char *tmpbuf; int buflen; smb_msgbuf_t mb; @@ -394,9 +393,8 @@ smb_com_negotiate(smb_request_t *sr) sr->session->secmode = secmode; } - - (void) inet_ntop(AF_INET, (char *)&sr->session->ipaddr, - ipaddr_buf, sizeof (ipaddr_buf)); + (void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf, + SMB_IPSTRLEN(sr->session->ipaddr.a_family)); max_mpx_count = sr->sr_cfg->skc_maxworkers; diff --git a/usr/src/uts/common/fs/smbsrv/smb_node.c b/usr/src/uts/common/fs/smbsrv/smb_node.c index 5975724259..41808ad392 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_node.c +++ b/usr/src/uts/common/fs/smbsrv/smb_node.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -171,10 +171,9 @@ smb_node_fini(void) * * smb_node_lookup() is called upon successful lookup, mkdir, and create * (for both non-streams and streams). In each of these cases, a held vnode is - * passed into this routine. If an smb_node already exists for this vnode, - * the vp is released. Otherwise, a new smb_node will be created and the - * reference will be held until the refcnt on the node goes to 0 (see - * smb_node_release()). + * passed into this routine. If a new smb_node is created it will take its + * own hold on the vnode. The caller's hold therefore still belongs to, and + * should be released by, the caller. * * A reference is taken on the smb_node whether found in the hash table * or newly created. @@ -272,7 +271,6 @@ smb_node_lookup( smb_audit_node(node); smb_rwx_xexit(&node->n_lock); smb_llist_exit(node_hdr); - VN_RELE(vp); return (node); case SMB_NODE_STATE_DESTROYING: @@ -309,6 +307,7 @@ smb_node_lookup( node->n_hash_bucket = node_hdr; node->n_sr = sr; node->vp = vp; + VN_HOLD(node->vp); node->n_hashkey = hashkey; node->n_refcnt = 1; node->attr = *attr; @@ -381,15 +380,6 @@ smb_stream_node_lookup(struct smb_request *sr, cred_t *cr, smb_node_t *fnode, snode = smb_node_lookup(sr, NULL, cr, vp, stream_name, xattrdir_node, fnode, ret_attr); - /* - * The following VN_HOLD is necessary because the caller will VN_RELE - * xattrdirvp in the case of an error. (xattrdir_node has the original - * hold on the vnode, which the smb_node_release() call below will - * release.) - */ - if (snode == NULL) { - VN_HOLD(xattrdirvp); - } (void) smb_node_release(xattrdir_node); return (snode); } diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c index 92da78bf41..b49705efb8 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_cancel.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * SMB: nt_cancel * @@ -71,7 +69,6 @@ smb_com_nt_cancel(smb_request_t *sr) while (req) { ASSERT(req->sr_magic == SMB_REQ_MAGIC); if ((req != sr) && - (req->smb_sid == sr->smb_sid) && (req->smb_uid == sr->smb_uid) && (req->smb_pid == sr->smb_pid) && (req->smb_tid == sr->smb_tid) && diff --git a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c index 522a510a56..447eceedd1 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c +++ b/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "@(#)smb_nt_transact_notify_change.c 1.6 08/08/07 SMI" - /* * File Change Notification (FCN) */ @@ -495,7 +493,6 @@ smb_reply_specific_cancel_request(struct smb_request *zsr) ASSERT(sr->sr_magic == SMB_REQ_MAGIC); tmp = smb_slist_next(&smb_ncr_list, sr); if ((sr->session == zsr->session) && - (sr->smb_sid == zsr->smb_sid) && (sr->smb_uid == zsr->smb_uid) && (sr->smb_pid == zsr->smb_pid) && (sr->smb_tid == zsr->smb_tid) && diff --git a/usr/src/uts/common/fs/smbsrv/smb_odir.c b/usr/src/uts/common/fs/smbsrv/smb_odir.c index 3e5b3d32b1..c92159f3fa 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_odir.c +++ b/usr/src/uts/common/fs/smbsrv/smb_odir.c @@ -19,12 +19,10 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * General Structures Layout * ------------------------- @@ -70,64 +68,45 @@ * Odir State Machine * ------------------ * - * +-------------------------+ T0 - * | SMB_ODIR_STATE_OPEN |<----------- Creation/Allocation + * +-------------------------+ + * | SMB_ODIR_STATE_OPEN |<----------- open / creation * +-------------------------+ * | - * | T1 + * | close * | * v * +-------------------------+ - * | SMB_ODIR_STATE_CLOSING | + * | SMB_ODIR_STATE_CLOSING | * +-------------------------+ * | - * | T2 + * | last release * | * v - * +-------------------------+ T3 - * | SMB_ODIR_STATE_CLOSED |----------> Deletion/Free + * +-------------------------+ + * | SMB_ODIR_STATE_CLOSED |----------> deletion * +-------------------------+ * - * SMB_ODIR_STATE_OPEN * - * While in this state: - * - The odir is queued in the list of odirs of its tree. - * - References will be given out if the odir is looked up. + * SMB_ODIR_STATE_OPEN + * - the odir exists in the list of odirs of its tree. + * - references will be given out if the odir is looked up + * - if a close is received the odir will transition to + * SMB_ODIR_STATE_CLOSING. * * SMB_ODIR_STATE_CLOSING - * - * While in this state: - * - The odir is queued in the list of odirs of its tree. - * - References will not be given out if the odir is looked up. - * - The odir is closed. - * - The resources associated with the odir remain. + * - the odir exists in the list of odirs of its tree. + * - references will NOT be given out if the odir is looked up. + * - when the last reference is released (refcnt == 0) the + * odir will transition to SMB_ODIR_STATE_CLOSED. * * SMB_ODIR_STATE_CLOSED - * - * While in this state: - * - The odir is queued in the list of odirs of its tree. - * - References will not be given out if the odir is looked up. - * - The resources associated with the odir remain. - * - * Transition T0 - * - * This transition occurs in smb_odir_open(). A new odir is created and - * added to the list of odirs of a tree. - * - * Transition T1 - * - * This transition occurs in smb_odir_close(). - * - * Transition T2 - * - * This transition occurs in smb_odir_release(). The resources associated - * with the odir are freed as well as the odir structure. For the - * transition to occur, the odir must be in the SMB_ODIR_STATE_CLOSED - * state and the reference count be zero. + * - the odir exists in the list of odirs of its tree. + * - there are no users of the odir (refcnt == 0) + * - references will NOT be given out if the odir is looked up. + * - the odir is being removed from the tree's list and deleted. * * Comments * -------- - * * The state machine of the odir structures is controlled by 3 elements: * - The list of odirs of the tree it belongs to. * - The mutex embedded in the structure itself. @@ -139,319 +118,1008 @@ * To insert the odir into the list of odirs of the tree and to remove * the odir from it, the lock must be entered in RW_WRITER mode. * - * Rules of access to a odir structure: + * In order to avoid deadlocks, when both (mutex and lock of the odir + * list) have to be entered, the lock must be entered first. + * + * + * Odir Interface + * --------------- + * odid = smb_odir_open(pathname) + * Create an odir representing the directory specified in pathname and + * add it into the tree's list of odirs. + * Return an identifier (odid) uniquely identifying the created odir. + * + * smb_odir_openat(smb_node_t *unode) + * Create an odir representing the extended attribute directory + * associated with the file (or directory) represented by unode + * and add it into the tree's list of odirs. + * Return an identifier (odid) uniquely identifying the created odir. + * + * smb_odir_t *odir = smb_tree_lookup_odir(odid) + * Find the odir corresponding to the specified odid in the tree's + * list of odirs. + * + * smb_odir_read(..., smb_odirent_t *odirent) + * Find the next directory entry in the odir and return it in odirent. + * + * smb_odir_read_fileinfo(..., smb_fileinfo_t *) + * Find the next directory entry in the odir. Return the details of + * the directory entry in smb_fileinfo_t. (See odir internals below) * - * 1) In order to avoid deadlocks, when both (mutex and lock of the odir - * list) have to be entered, the lock must be entered first. + * smb_odir_read_stream_info(..., smb_streaminfo_t *) + * Find the next named stream entry in the odir. Return the details of + * the named stream in smb_streaminfo_t. * - * 2) All actions applied to an odir require a reference count. + * smb_odir_release(smb_odir_t *odir) + * Release the hold on the odir, obtained by lookup. * - * 3) There are 2 ways of getting a reference count. One is when the odir - * is opened. The other when the odir is looked up. This translates - * into 2 functions: smb_odir_open() and smb_odir_lookup_by_fid(). + * smb_odir_close(smb_odir_t *odir) + * Close the odir and remove it from the tree's list of odirs. * - * It should be noted that the reference count of an odir registers the - * number of references to the odir in other structures (such as an smb - * request). The reference count is not incremented in these 2 instances: * - * 1) The odir is open. An odir is anchored by his state. If there's - * no activity involving an odir currently open, the reference count - * of that odir is zero. + * Odir Internals + * -------------- + * The odir object represent an open directory search. Each read operation + * provides the caller with a structure containing information pertaining + * to the next directory entry that matches the search criteria, namely + * the filename or match pattern and, in the case of smb_odir_read_fileinfo(), + * the search attributes. * - * 2) The odir is queued in the list of odirs of its tree. The fact of - * being queued in that list is NOT registered by incrementing the - * reference count. + * The odir maintains a buffer (d_buf) of directory entries read from + * the filesystem via a vop_readdir. The buffer is populated when a read + * request (smb_odir_next_odirent) finds that the buffer is empty or that + * the end of the buffer has been reached, and also when a new client request + * (find next) begins. + * + * The data in d_buf (that which is returned from the file system) can + * be in one of two formats. If the file system supports extended directory + * entries we request that the data be returned as edirent_t structures. If + * it does not the data will be returned as dirent64_t structures. For + * convenience, when the next directory entry is read from d_buf by + * smb_odir_next_odirent it is translated into an smb_odirent_t. + * + * smb_odir_read_fileinfo + * The processing required to obtain the information to populate the caller's + * smb_fileinfo_t differs depending upon whether the directory search is for a + * single specified filename or for multiple files matching a search pattern. + * Thus smb_odir_read_fileinfo uses two static functions: + * smb_odir_single_fileinfo - obtains the smb_fileinfo_t info for the single + * filename as specified in smb_odir_open request. + * smb_odir_wildcard_fileinfo - obtains the smb_fileinfo_t info for the filename + * returned from the smb_odir_next_odirent. This is called in a loop until + * an entry matching the search criteria is found or no more entries exist. + * + * If a directory entry is a VLNK, the name returned in the smb_fileinfo_t + * is the name of the directory entry but the attributes are the attribites + * of the file that is the target of the link. If the link target cannot + * be found the attributes returned are the attributes of the link itself. + * + * smb_odir_read_stream_info + * In order for an odir to provide information about stream files it + * must be opened with smb_odir_openat(). smb_odir_read_streaminfo() can + * then be used to obtain the name and size of named stream files. + * + * Resuming a Search + * ----------------- + * A directory search often consists of multiple client requests: an initial + * find_first request followed by zero or more find_next requests and a + * find_close request. + * The find_first request will open and lookup the odir, read its desired + * number of entries from the odir, then release the odir and return. + * A find_next request will lookup the odir and read its desired number of + * entries from the odir, then release the odir and return. + * At the end of the search the find_close request will close the odir. + * + * In order to be able to resume a directory search (find_next) the odir + * provides the capability for the caller to save one or more resume points + * (cookies) at the end of a request, and to specify which resume point + * (cookie) to restart from at the beginning of the next search. + * smb_odir_save_cookie(..., cookie) + * smb_odir_resume_at(smb_odir_resume_t *resume) + * A search can be resumed at a specified resume point (cookie), the resume + * point (cookie) stored at a specified index in the d_cookies array, or + * a specified filename. The latter (specified filename) is not yet supported. + * + * See smb_search, smb_find, smb_find_unique, and smb_trans2_find for details */ + #include <smbsrv/smb_incl.h> #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_fsops.h> +#include <sys/extdirent.h> -/* Static functions defined further down this file. */ -static void smb_odir_delete(smb_odir_t *of); -static smb_odir_t *smb_odir_close_and_next(smb_odir_t *od); +/* static functions */ +static smb_odir_t *smb_odir_create(smb_request_t *, smb_node_t *, + char *, uint16_t); +static void smb_odir_delete(smb_odir_t *); +static int smb_odir_single_fileinfo(smb_request_t *, smb_odir_t *, + smb_fileinfo_t *); +static int smb_odir_wildcard_fileinfo(smb_request_t *, smb_odir_t *, + smb_odirent_t *, smb_fileinfo_t *); +static int smb_odir_next_odirent(smb_odir_t *, smb_odirent_t *); +static boolean_t smb_odir_lookup_link(smb_request_t *, smb_odir_t *, char *, + smb_node_t **, smb_attr_t *); -#include <smbsrv/smb_incl.h> -#include <smbsrv/smb_fsops.h> /* * smb_odir_open + * + * Create an odir representing the directory specified in pathname. + * + * Returns: + * odid - Unique identifier of newly created odir. + * 0 - error, error details set in sr. */ -smb_odir_t * -smb_odir_open( - smb_tree_t *tree, - smb_node_t *node, - char *pattern, - uint16_t pid, - unsigned short sattr) +uint16_t +smb_odir_open(smb_request_t *sr, char *path, uint16_t sattr) { - smb_odir_t *dir; + int rc; + smb_tree_t *tree; + smb_node_t *dnode; + char pattern[MAXNAMELEN]; + smb_odir_t *od; - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); - ASSERT(node); - ASSERT(node->n_magic == SMB_NODE_MAGIC); - ASSERT(pattern); + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(sr->tid_tree); + ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); - if (strlen(pattern) >= sizeof (dir->d_pattern)) { - return (NULL); + tree = sr->tid_tree; + + rc = smb_pathname_reduce(sr, sr->user_cr, path, + tree->t_snode, tree->t_snode, &dnode, pattern); + if (rc != 0) { + smbsr_errno(sr, rc); + return (0); } - dir = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP); - bzero(dir, sizeof (smb_odir_t)); - dir->d_refcnt = 1; - dir->d_session = tree->t_session; - dir->d_user = tree->t_user; - dir->d_tree = tree; - (void) strlcpy(dir->d_pattern, pattern, sizeof (dir->d_pattern)); - dir->d_wildcards = smb_convert_unicode_wildcards(pattern); - dir->d_state = SMB_ODIR_STATE_OPEN; - - if (smb_idpool_alloc(&dir->d_tree->t_sid_pool, &dir->d_sid)) { - kmem_cache_free(tree->t_server->si_cache_odir, dir); - return (NULL); + if (dnode->vp->v_type != VDIR) { + smbsr_error(sr, NT_STATUS_OBJECT_PATH_NOT_FOUND, + ERRDOS, ERROR_PATH_NOT_FOUND); + smb_node_release(dnode); + return (0); } - mutex_init(&dir->d_mutex, NULL, MUTEX_DEFAULT, NULL); - dir->d_sattr = sattr; - dir->d_opened_by_pid = pid; - dir->d_dir_snode = node; - dir->d_state = SMB_ODIR_STATE_OPEN; - dir->d_magic = SMB_ODIR_MAGIC; - smb_llist_enter(&tree->t_odir_list, RW_WRITER); - smb_llist_insert_tail(&tree->t_odir_list, dir); - smb_llist_exit(&tree->t_odir_list); + if (smb_fsop_access(sr, sr->user_cr, dnode, FILE_LIST_DIRECTORY) != 0) { + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + smb_node_release(dnode); + return (0); + } - atomic_inc_32(&tree->t_session->s_dir_cnt); - return (dir); + od = smb_odir_create(sr, dnode, pattern, sattr); + smb_node_release(dnode); + return (od ? od->d_odid : 0); } /* - * smb_odir_close + * smb_odir_openat + * + * Create an odir representing the extended attribute directory + * associated with the file (or directory) represented by unode. + * + * Returns: + * odid - Unique identifier of newly created odir. + * 0 - error, error details set in sr. + */ +uint16_t +smb_odir_openat(smb_request_t *sr, smb_node_t *unode) +{ + int rc; + vnode_t *xattr_dvp; + smb_odir_t *od; + cred_t *cr; + char pattern[SMB_STREAM_PREFIX_LEN + 2]; + + smb_node_t *xattr_dnode; + smb_attr_t tmp_attr; + + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(unode); + ASSERT(unode->n_magic == SMB_NODE_MAGIC); + + if (SMB_TREE_CONTAINS_NODE(sr, unode) == 0) { + smbsr_error(sr, NT_STATUS_ACCESS_DENIED, + ERRDOS, ERROR_ACCESS_DENIED); + return (0); + } + cr = sr->user_cr; + + /* find the xattrdir vnode */ + rc = smb_vop_lookup_xattrdir(unode->vp, &xattr_dvp, LOOKUP_XATTR, cr); + if (rc != 0) { + smbsr_errno(sr, rc); + return (0); + } + + /* lookup the xattrdir's smb_node */ + xattr_dnode = smb_node_lookup(sr, NULL, cr, xattr_dvp, XATTR_DIR, + unode, NULL, &tmp_attr); + VN_RELE(xattr_dvp); + if (xattr_dnode == NULL) { + smbsr_error(sr, NT_STATUS_NO_MEMORY, + ERRDOS, ERROR_NOT_ENOUGH_MEMORY); + return (0); + } + + (void) snprintf(pattern, sizeof (pattern), "%s*", SMB_STREAM_PREFIX); + od = smb_odir_create(sr, xattr_dnode, pattern, SMB_SEARCH_ATTRIBUTES); + smb_node_release(xattr_dnode); + if (od == NULL) + return (0); + + od->d_xat = B_TRUE; + return (od->d_odid); +} + +/* + * smb_odir_hold + */ +boolean_t +smb_odir_hold(smb_odir_t *od) +{ + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + + mutex_enter(&od->d_mutex); + if (od->d_state != SMB_ODIR_STATE_OPEN) { + mutex_exit(&od->d_mutex); + return (B_FALSE); + } + + od->d_refcnt++; + mutex_exit(&od->d_mutex); + return (B_TRUE); +} + +/* + * smb_odir_release + * + * If the odir is in SMB_ODIR_STATE_CLOSING and this release + * results in a refcnt of 0, the odir may be removed from + * the tree's list of odirs and deleted. The odir's state is + * set to SMB_ODIR_STATE_CLOSED prior to exiting the mutex and + * deleting it. This ensure that nobody else can ontain a reference + * to it while we are deleting it. */ void -smb_odir_close( - smb_odir_t *od) +smb_odir_release(smb_odir_t *od) { ASSERT(od); ASSERT(od->d_magic == SMB_ODIR_MAGIC); mutex_enter(&od->d_mutex); ASSERT(od->d_refcnt); + switch (od->d_state) { case SMB_ODIR_STATE_OPEN: - od->d_state = SMB_ODIR_STATE_CLOSED; + od->d_refcnt--; break; case SMB_ODIR_STATE_CLOSING: + od->d_refcnt--; + if (od->d_refcnt == 0) { + od->d_state = SMB_ODIR_STATE_CLOSED; + mutex_exit(&od->d_mutex); + smb_odir_delete(od); + return; + } + break; case SMB_ODIR_STATE_CLOSED: break; default: ASSERT(0); break; } + + mutex_exit(&od->d_mutex); +} + +/* + * smb_odir_close + */ +void +smb_odir_close(smb_odir_t *od) +{ + ASSERT(od); + ASSERT(od->d_refcnt); + + mutex_enter(&od->d_mutex); + if (od->d_state != SMB_ODIR_STATE_OPEN) { + mutex_exit(&od->d_mutex); + return; + } + od->d_state = SMB_ODIR_STATE_CLOSING; mutex_exit(&od->d_mutex); + + smb_odir_release(od); } /* - * smb_odir_close_all + * smb_odir_read * + * Find the next directory entry matching the search pattern. + * No search attribute matching is performed. * + * Returns: + * 0 - success. + * - If a matching entry was found eof will be B_FALSE and + * odirent will be populated. + * - If there are no matching entries eof will be B_TRUE. + * -1 - error, error details set in sr. */ -void -smb_odir_close_all( - smb_tree_t *tree) +int +smb_odir_read(smb_request_t *sr, smb_odir_t *od, + smb_odirent_t *odirent, boolean_t *eof) { - smb_odir_t *od; + int rc; - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(odirent); + + mutex_enter(&od->d_mutex); + + ASSERT(od->d_state == SMB_ODIR_STATE_OPEN); + if (od->d_state != SMB_ODIR_STATE_OPEN) { + mutex_exit(&od->d_mutex); + return (-1); + } - smb_llist_enter(&tree->t_odir_list, RW_READER); - od = smb_llist_head(&tree->t_odir_list); - while (od) { - ASSERT(od->d_magic == SMB_ODIR_MAGIC); - ASSERT(od->d_tree == tree); - od = smb_odir_close_and_next(od); + for (;;) { + if ((rc = smb_odir_next_odirent(od, odirent)) != 0) + break; + if (smb_match_name(odirent->od_ino, odirent->od_name, + od->d_pattern, od->d_ignore_case)) + break; + } + + mutex_exit(&od->d_mutex); + + switch (rc) { + case 0: + *eof = B_FALSE; + return (0); + case ENOENT: + *eof = B_TRUE; + return (0); + default: + smbsr_errno(sr, rc); + return (-1); } - smb_llist_exit(&tree->t_odir_list); } /* - * smb_odir_close_all_by_pid + * smb_odir_read_fileinfo * + * Find the next directory entry matching the search pattern + * and attributes: od->d_pattern and od->d_sattr. * + * If the search pattern specifies a single filename call + * smb_odir_single_fileinfo to get the file attributes and + * populate the caller's smb_fileinfo_t. + * + * If the search pattern contains wildcards call smb_odir_next_odirent + * to get the next directory entry then. Repeat until a matching + * filename is found. Call smb_odir_wildcard_fileinfo to get the + * file attributes and populate the caller's smb_fileinfo_t. + * This is repeated until a file matching the search criteria is found. + * + * Returns: + * 0 - success. + * - If a matching entry was found eof will be B_FALSE and + * fileinfo will be populated. + * - If there are no matching entries eof will be B_TRUE. + * -1 - error, error details set in sr. */ -void -smb_odir_close_all_by_pid( - smb_tree_t *tree, - uint16_t pid) +int +smb_odir_read_fileinfo(smb_request_t *sr, smb_odir_t *od, + smb_fileinfo_t *fileinfo, boolean_t *eof) { - smb_odir_t *od; + int rc; + smb_odirent_t *odirent; - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(fileinfo); - smb_llist_enter(&tree->t_odir_list, RW_READER); - od = smb_llist_head(&tree->t_odir_list); - while (od) { - ASSERT(od->d_magic == SMB_ODIR_MAGIC); - ASSERT(od->d_tree == tree); - if (od->d_opened_by_pid == pid) { - od = smb_odir_close_and_next(od); - } else { - od = smb_llist_next(&tree->t_odir_list, od); + mutex_enter(&od->d_mutex); + + ASSERT(od->d_state == SMB_ODIR_STATE_OPEN); + if (od->d_state != SMB_ODIR_STATE_OPEN) { + mutex_exit(&od->d_mutex); + return (-1); + } + + if (!od->d_wildcards) { + if (od->d_eof) + rc = ENOENT; + else + rc = smb_odir_single_fileinfo(sr, od, fileinfo); + od->d_eof = B_TRUE; + } else { + odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); + for (;;) { + bzero(fileinfo, sizeof (smb_fileinfo_t)); + if ((rc = smb_odir_next_odirent(od, odirent)) != 0) + break; + + if (!smb_match_name(odirent->od_ino, odirent->od_name, + od->d_pattern, od->d_ignore_case)) + continue; + + rc = smb_odir_wildcard_fileinfo(sr, od, odirent, + fileinfo); + if (rc == 0) + break; } + kmem_free(odirent, sizeof (smb_odirent_t)); + } + mutex_exit(&od->d_mutex); + + switch (rc) { + case 0: + *eof = B_FALSE; + return (0); + case ENOENT: + *eof = B_TRUE; + return (0); + default: + smbsr_errno(sr, rc); + return (-1); } - smb_llist_exit(&tree->t_odir_list); } + /* - * smb_odir_release + * smb_odir_read_streaminfo + * + * Find the next directory entry whose name begins with SMB_STREAM_PREFIX, + * and thus represents an NTFS named stream. + * No search attribute matching is performed. + * + * Returns: + * 0 - success. + * - If a matching entry was found eof will be B_FALSE and + * sinfo will be populated. + * - If there are no matching entries eof will be B_TRUE. + * -1 - error, error details set in sr. */ -void -smb_odir_release( - smb_odir_t *od) +int +smb_odir_read_streaminfo(smb_request_t *sr, smb_odir_t *od, + smb_streaminfo_t *sinfo, boolean_t *eof) { + int rc; + smb_odirent_t *odirent; + vnode_t *vp; + smb_attr_t attr; + + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); ASSERT(od); ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(sinfo); mutex_enter(&od->d_mutex); - ASSERT(od->d_refcnt); - od->d_refcnt--; - switch (od->d_state) { - case SMB_ODIR_STATE_CLOSING: - case SMB_ODIR_STATE_OPEN: - break; - case SMB_ODIR_STATE_CLOSED: - if (od->d_refcnt == 0) { - mutex_exit(&od->d_mutex); - smb_odir_delete(od); - return; + ASSERT(od->d_state == SMB_ODIR_STATE_OPEN); + if (od->d_state != SMB_ODIR_STATE_OPEN) { + mutex_exit(&od->d_mutex); + return (-1); + } + + /* Check that odir represents an xattr directory */ + if (!od->d_xat) { + *eof = B_TRUE; + mutex_exit(&od->d_mutex); + return (0); + } + + odirent = kmem_alloc(sizeof (smb_odirent_t), KM_SLEEP); + + for (;;) { + bzero(sinfo, sizeof (smb_streaminfo_t)); + if ((rc = smb_odir_next_odirent(od, odirent)) != 0) + break; + + if (strncmp(odirent->od_name, SMB_STREAM_PREFIX, + SMB_STREAM_PREFIX_LEN)) { + continue; } - break; + /* + * since we only care about the size attribute we don't need to + * pass the vp of the unnamed stream file to smb_vop_getattr + */ + rc = smb_vop_lookup(od->d_dnode->vp, odirent->od_name, &vp, + NULL, 0, od->d_tree->t_snode->vp, od->d_user->u_cred); + if (rc == 0) { + rc = smb_vop_getattr(vp, NULL, &attr, 0, + od->d_user->u_cred); + VN_RELE(vp); + } + + if (rc == 0) { + (void) strlcpy(sinfo->si_name, + odirent->od_name + SMB_STREAM_PREFIX_LEN, + sizeof (sinfo->si_name)); + sinfo->si_size = attr.sa_vattr.va_size; + break; + } + } + mutex_exit(&od->d_mutex); + + kmem_free(odirent, sizeof (smb_odirent_t)); + + switch (rc) { + case 0: + *eof = B_FALSE; + return (0); + case ENOENT: + *eof = B_TRUE; + return (0); default: - ASSERT(0); - break; + smbsr_errno(sr, rc); + return (-1); } +} + +/* + * smb_odir_save_cookie + * + * Callers can save up to SMB_MAX_SEARCH cookies in the odir + * to be used as resume points for a 'find next' request. + */ +void +smb_odir_save_cookie(smb_odir_t *od, int idx, uint32_t cookie) +{ + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(idx >= 0 && idx < SMB_MAX_SEARCH); + + mutex_enter(&od->d_mutex); + od->d_cookies[idx] = cookie; mutex_exit(&od->d_mutex); } /* - * smb_odir_lookup_by_sid + * smb_odir_resume_at + * + * Searching can be resumed from: + * - the cookie saved at a specified index (SMBsearch, SMBfind). + * - a specified cookie (SMB_trans2_find) + * - a specified filename (SMB_trans2_find) - NOT SUPPORTED. + * Defaults to continuing from where the last search ended. + * + * Continuation from where the last search ended (SMB_trans2_find) + * is implemented by saving the last cookie at a specific index (0) + * smb_odir_resume_at indicates a new request, so reset od->d_bufptr + * and d_eof to force a vop_readdir. */ -smb_odir_t * -smb_odir_lookup_by_sid( - smb_tree_t *tree, - uint16_t sid) +void +smb_odir_resume_at(smb_odir_t *od, smb_odir_resume_t *resume) { - smb_llist_t *od_list; - smb_odir_t *od; + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(resume); + + mutex_enter(&od->d_mutex); - ASSERT(tree); - ASSERT(tree->t_magic == SMB_TREE_MAGIC); - - od_list = &tree->t_odir_list; - - smb_llist_enter(od_list, RW_READER); - od = smb_llist_head(od_list); - while (od) { - ASSERT(od->d_magic == SMB_ODIR_MAGIC); - ASSERT(od->d_tree == tree); - if (od->d_sid == sid) { - mutex_enter(&od->d_mutex); - if (od->d_state != SMB_ODIR_STATE_OPEN) { - mutex_exit(&od->d_mutex); - smb_llist_exit(od_list); - return (NULL); + switch (resume->or_type) { + case SMB_ODIR_RESUME_IDX: + ASSERT(resume->or_idx >= 0); + ASSERT(resume->or_idx < SMB_MAX_SEARCH); + + if ((resume->or_idx < 0) || + (resume->or_idx >= SMB_MAX_SEARCH)) { + resume->or_idx = 0; } - od->d_refcnt++; - mutex_exit(&od->d_mutex); + od->d_offset = od->d_cookies[resume->or_idx]; + break; + case SMB_ODIR_RESUME_COOKIE: + od->d_offset = resume->or_cookie; + break; + case SMB_ODIR_RESUME_FNAME: + default: + od->d_offset = od->d_cookies[0]; break; - } - od = smb_llist_next(od_list, od); } - smb_llist_exit(od_list); - return (od); + + /* Force a vop_readdir to refresh d_buf */ + od->d_bufptr = NULL; + od->d_eof = B_FALSE; + + mutex_exit(&od->d_mutex); } -/* *************************** Static Functions ***************************** */ + +/* *** static functions *** */ /* - * smb_odir_close_and_next - * - * This function closes the directory passed in (if appropriate) and returns the - * next directory in the list of directories of the tree of the directory passed - * in. It requires that the list of directories of the tree be entered in - * RW_READER mode before being called. + * smb_odir_create + * Allocate and populate an odir obect and add it to the tree's list. */ static smb_odir_t * -smb_odir_close_and_next( - smb_odir_t *od) +smb_odir_create(smb_request_t *sr, smb_node_t *dnode, + char *pattern, uint16_t sattr) { - smb_odir_t *next_od; + smb_odir_t *od; smb_tree_t *tree; + uint16_t odid; - ASSERT(od); - ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(sr->tid_tree); + ASSERT(sr->tid_tree->t_magic == SMB_TREE_MAGIC); + ASSERT(dnode); + ASSERT(dnode->n_magic == SMB_NODE_MAGIC); - mutex_enter(&od->d_mutex); - switch (od->d_state) { - case SMB_ODIR_STATE_OPEN: - /* The directory is still opened. */ - od->d_refcnt++; - ASSERT(od->d_refcnt); - tree = od->d_tree; - mutex_exit(&od->d_mutex); - smb_llist_exit(&od->d_tree->t_odir_list); - smb_odir_close(od); - smb_odir_release(od); - smb_llist_enter(&tree->t_odir_list, RW_READER); - next_od = smb_llist_head(&tree->t_odir_list); - break; - case SMB_ODIR_STATE_CLOSING: - case SMB_ODIR_STATE_CLOSED: - /* - * The odir exists but is closed or is in the process - * of being closed. - */ - mutex_exit(&od->d_mutex); - next_od = smb_llist_next(&od->d_tree->t_odir_list, od); - break; - default: - ASSERT(0); - mutex_exit(&od->d_mutex); - next_od = smb_llist_next(&od->d_tree->t_odir_list, od); - break; + tree = sr->tid_tree; + + if (smb_idpool_alloc(&tree->t_odid_pool, &odid)) { + smbsr_error(sr, NT_STATUS_TOO_MANY_OPENED_FILES, + ERRDOS, ERROR_TOO_MANY_OPEN_FILES); + return (NULL); } - return (next_od); + + od = kmem_cache_alloc(tree->t_server->si_cache_odir, KM_SLEEP); + bzero(od, sizeof (smb_odir_t)); + + mutex_init(&od->d_mutex, NULL, MUTEX_DEFAULT, NULL); + od->d_refcnt = 1; + od->d_state = SMB_ODIR_STATE_OPEN; + od->d_magic = SMB_ODIR_MAGIC; + od->d_opened_by_pid = sr->smb_pid; + od->d_session = tree->t_session; + od->d_user = tree->t_user; + od->d_tree = tree; + od->d_dnode = dnode; + smb_node_ref(dnode); + od->d_odid = odid; + od->d_sattr = sattr; + (void) strlcpy(od->d_pattern, pattern, sizeof (od->d_pattern)); + od->d_wildcards = (smb_convert_unicode_wildcards(od->d_pattern) != 0); + od->d_is_edp = vfs_has_feature(dnode->vp->v_vfsp, VFSFT_DIRENTFLAGS); + od->d_ignore_case = + smb_tree_has_feature(tree, SMB_TREE_CASEINSENSITIVE); + od->d_eof = B_FALSE; + + smb_llist_enter(&tree->t_odir_list, RW_WRITER); + smb_llist_insert_tail(&tree->t_odir_list, od); + smb_llist_exit(&tree->t_odir_list); + + atomic_inc_32(&tree->t_session->s_dir_cnt); + return (od); } /* * smb_odir_delete + * + * Removal of the odir from the tree's list of odirs must be + * done before any resources associated with the odir are + * released. */ static void -smb_odir_delete( - smb_odir_t *od) +smb_odir_delete(smb_odir_t *od) { ASSERT(od); ASSERT(od->d_magic == SMB_ODIR_MAGIC); ASSERT(od->d_state == SMB_ODIR_STATE_CLOSED); ASSERT(od->d_refcnt == 0); - /* - * Let's remove the odir from the list of odirs of the tree. This has - * to be done before any resources associated with the odir are - * released. - */ smb_llist_enter(&od->d_tree->t_odir_list, RW_WRITER); smb_llist_remove(&od->d_tree->t_odir_list, od); smb_llist_exit(&od->d_tree->t_odir_list); - od->d_magic = 0; - smb_node_release(od->d_dir_snode); + od->d_magic = 0; atomic_dec_32(&od->d_tree->t_session->s_dir_cnt); - smb_idpool_free(&od->d_tree->t_sid_pool, od->d_sid); + smb_node_release(od->d_dnode); + smb_idpool_free(&od->d_tree->t_odid_pool, od->d_odid); mutex_destroy(&od->d_mutex); kmem_cache_free(od->d_tree->t_server->si_cache_odir, od); } + +/* + * smb_odir_next_odirent + * + * Find the next directory entry in d_buf. If d_bufptr is NULL (buffer + * is empty or we've reached the end of it), read the next set of + * entries from the file system (vop_readdir). + * + * File systems which support VFSFT_EDIRENT_FLAGS will return the + * directory entries as a buffer of edirent_t structure. Others will + * return a buffer of dirent64_t structures. For simplicity translate + * the data into an smb_odirent_t structure. + * The ed_name/d_name in d_buf is NULL terminated by the file system. + * + * Some file systems can have directories larger than SMB_MAXDIRSIZE. + * If the odirent offset >= SMB_MAXDIRSIZE return ENOENT. + * + * Returns: + * 0 - success. odirent is populated with the next directory entry + * ENOENT - no more directory entries + * errno - error + */ +static int +smb_odir_next_odirent(smb_odir_t *od, smb_odirent_t *odirent) +{ + int rc; + int reclen; + int eof; + dirent64_t *dp; + edirent_t *edp; + + ASSERT(MUTEX_HELD(&od->d_mutex)); + + if (od->d_bufptr != NULL) { + reclen = od->d_is_edp ? + od->d_edp->ed_reclen : od->d_dp->d_reclen; + + if (reclen == 0) { + od->d_bufptr = NULL; + } else { + od->d_bufptr += reclen; + if (od->d_bufptr >= od->d_buf + od->d_bufsize) + od->d_bufptr = NULL; + } + } + + if (od->d_bufptr == NULL) { + if (od->d_eof) + return (ENOENT); + + od->d_bufsize = sizeof (od->d_buf); + + rc = smb_vop_readdir(od->d_dnode->vp, od->d_offset, + od->d_buf, &od->d_bufsize, &eof, od->d_user->u_cred); + + if ((rc == 0) && (od->d_bufsize == 0)) + rc = ENOENT; + + if (rc != 0) { + od->d_bufptr = NULL; + od->d_bufsize = 0; + return (rc); + } + + od->d_eof = (eof != 0); + od->d_bufptr = od->d_buf; + } + + od->d_offset = (od->d_is_edp) ? od->d_edp->ed_off : od->d_dp->d_off; + if (od->d_offset >= SMB_MAXDIRSIZE) { + od->d_bufptr = NULL; + od->d_bufsize = 0; + return (ENOENT); + } + + if (od->d_is_edp) { + edp = od->d_edp; + odirent->od_ino = edp->ed_ino; + odirent->od_eflags = edp->ed_eflags; + (void) strlcpy(odirent->od_name, edp->ed_name, + sizeof (odirent->od_name)); + } else { + dp = od->d_dp; + odirent->od_ino = dp->d_ino; + odirent->od_eflags = 0; + (void) strlcpy(odirent->od_name, dp->d_name, + sizeof (odirent->od_name)); + } + + return (0); +} + +/* + * smb_odir_single_fileinfo + * + * Lookup the file identified by od->d_pattern. + * + * If the looked up file is a link, we attempt to lookup the link target + * to use its attributes in place of those of the files's. + * If we fail to lookup the target of the link we use the original + * file's attributes. + * Check if the attributes match the search attributes. + * + * Returns: 0 - success + * ENOENT - no match + * errno - error + */ +static int +smb_odir_single_fileinfo(smb_request_t *sr, smb_odir_t *od, + smb_fileinfo_t *fileinfo) +{ + int rc; + smb_node_t *fnode, *tgt_node; + smb_attr_t attr, tgt_attr, *fattr; + ino64_t ino; + char *name; + uint32_t dosattr; + + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + + ASSERT(MUTEX_HELD(&od->d_mutex)); + bzero(fileinfo, sizeof (smb_fileinfo_t)); + + rc = smb_fsop_lookup(sr, od->d_user->u_cred, 0, od->d_tree->t_snode, + od->d_dnode, od->d_pattern, &fnode, &attr, 0, 0); + if (rc != 0) + return (rc); + + name = fnode->od_name; + + (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); + ino = attr.sa_vattr.va_nodeid; + (void) smb_mangle_name(ino, name, + fileinfo->fi_shortname, fileinfo->fi_name83, 0); + + /* follow link to get target node & attr */ + if ((fnode->vp->v_type == VLNK) && + (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) { + smb_node_release(fnode); + fnode = tgt_node; + fattr = &tgt_attr; + } else { + fattr = &attr; + } + + /* check search attributes */ + dosattr = smb_node_get_dosattr(fnode); + if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) { + smb_node_release(fnode); + return (ENOENT); + } + + fileinfo->fi_dosattr = dosattr; + fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid; + fileinfo->fi_size = smb_node_get_size(fnode, fattr); + fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE; + fileinfo->fi_atime = fattr->sa_vattr.va_atime; + fileinfo->fi_mtime = fattr->sa_vattr.va_mtime; + fileinfo->fi_ctime = fattr->sa_vattr.va_ctime; + if (fattr->sa_crtime.tv_sec) + fileinfo->fi_crtime = fattr->sa_crtime; + else + fileinfo->fi_crtime = fattr->sa_vattr.va_mtime; + + smb_node_release(fnode); + return (0); +} + +/* + * smb_odir_wildcard_fileinfo + * + * odirent contains a directory entry, obtained from a vop_readdir. + * If a case conflict is identified the filename is mangled and the + * shortname is used as 'name', in place of odirent->od_name. This + * name will be used in the smb_fsop_lookup because smb_fsop_lookup + * performs a case insensitive lookup if the tree is case insesitive, + * so the mangled name is required in the case conflict scenario to + * ensure the correct match. + * + * If the looked up file is a link, we attempt to lookup the link target + * to use its attributes in place of those of the files's. + * If we fail to lookup the target of the link we use the original + * file's attributes. + * Check if the attributes match the search attributes. + * + * Although some file systems can have directories larger than + * SMB_MAXDIRSIZE smb_odir_next_odirent ensures that no offset larger + * than SMB_MAXDIRSIZE is returned. It is therefore safe to use the + * offset as the cookie (uint32_t). + * + * Returns: 0 - success + * ENOENT - no match, proceed to next entry + * errno - error + */ +static int +smb_odir_wildcard_fileinfo(smb_request_t *sr, smb_odir_t *od, + smb_odirent_t *odirent, smb_fileinfo_t *fileinfo) +{ + int rc; + smb_node_t *fnode, *tgt_node; + smb_attr_t attr, tgt_attr, *fattr; + char *name; + uint32_t dosattr; + boolean_t case_conflict; + + ASSERT(sr); + ASSERT(sr->sr_magic == SMB_REQ_MAGIC); + ASSERT(od); + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + + ASSERT(MUTEX_HELD(&od->d_mutex)); + bzero(fileinfo, sizeof (smb_fileinfo_t)); + + case_conflict = ((od->d_ignore_case) && + (odirent->od_eflags & ED_CASE_CONFLICT)); + (void) smb_mangle_name(odirent->od_ino, odirent->od_name, + fileinfo->fi_shortname, fileinfo->fi_name83, case_conflict); + name = (case_conflict) ? fileinfo->fi_shortname : odirent->od_name; + (void) strlcpy(fileinfo->fi_name, name, sizeof (fileinfo->fi_name)); + + rc = smb_fsop_lookup(sr, od->d_user->u_cred, 0, od->d_tree->t_snode, + od->d_dnode, name, &fnode, &attr, 0, 0); + if (rc != 0) + return (rc); + + /* follow link to get target node & attr */ + if ((fnode->vp->v_type == VLNK) && + (smb_odir_lookup_link(sr, od, name, &tgt_node, &tgt_attr))) { + smb_node_release(fnode); + fnode = tgt_node; + fattr = &tgt_attr; + } else { + fattr = &attr; + } + + /* check search attributes */ + dosattr = smb_node_get_dosattr(fnode); + if (!smb_sattr_check(dosattr, od->d_sattr, fileinfo->fi_name)) { + smb_node_release(fnode); + return (ENOENT); + } + + fileinfo->fi_cookie = (uint32_t)od->d_offset; + fileinfo->fi_dosattr = dosattr; + fileinfo->fi_nodeid = fattr->sa_vattr.va_nodeid; + fileinfo->fi_size = smb_node_get_size(fnode, fattr); + fileinfo->fi_alloc_size = fattr->sa_vattr.va_nblocks * DEV_BSIZE; + fileinfo->fi_atime = fattr->sa_vattr.va_atime; + fileinfo->fi_mtime = fattr->sa_vattr.va_mtime; + fileinfo->fi_ctime = fattr->sa_vattr.va_ctime; + if (fattr->sa_crtime.tv_sec) + fileinfo->fi_crtime = fattr->sa_crtime; + else + fileinfo->fi_crtime = fattr->sa_vattr.va_mtime; + + smb_node_release(fnode); + return (0); +} + +/* + * smb_odir_lookup_link + * + * If the file is a symlink we lookup the object to which the + * symlink refers so that we can return its attributes. + * This can cause a problem if a symlink in a sub-directory + * points to a parent directory (some UNIX GUI's create a symlink + * in $HOME/.desktop that points to the user's home directory). + * Some Windows applications (e.g. virus scanning) loop/hang + * trying to follow this recursive path and there is little + * we can do because the path is constructed on the client. + * smb_dirsymlink_enable allows an end-user to disable + * symlinks to directories. Symlinks to other object types + * should be unaffected. + * + * Returns: B_TRUE - followed link. tgt_node and tgt_attr set + * B_FALSE - link not followed + */ +static boolean_t +smb_odir_lookup_link(smb_request_t *sr, smb_odir_t *od, + char *fname, smb_node_t **tgt_node, smb_attr_t *tgt_attr) +{ + int rc; + + rc = smb_fsop_lookup(sr, od->d_user->u_cred, SMB_FOLLOW_LINKS, + od->d_tree->t_snode, od->d_dnode, fname, tgt_node, tgt_attr, 0, 0); + if (rc != 0) { + *tgt_node = NULL; + return (B_FALSE); + } + + if ((tgt_attr->sa_vattr.va_type == VDIR) && (!smb_dirsymlink_enable)) { + smb_node_release(*tgt_node); + *tgt_node = NULL; + return (B_FALSE); + } + + return (B_TRUE); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_oplock.c b/usr/src/uts/common/fs/smbsrv/smb_oplock.c index b389231973..3d5efdfb43 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_oplock.c +++ b/usr/src/uts/common/fs/smbsrv/smb_oplock.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,6 +31,7 @@ #include <smbsrv/smb_incl.h> #include <smbsrv/smb_fsops.h> +#include <inet/tcp.h> /* * Oplock functionality enable/disable @@ -338,7 +339,8 @@ smb_oplock_break(smb_node_t *node) node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING; node->n_oplock.op_ofile = NULL; - node->n_oplock.op_ipaddr = 0; + bzero(&node->n_oplock.op_ipaddr, + sizeof (node->n_oplock.op_ipaddr)); node->n_oplock.op_kid = 0; smb_rwx_rwexit(&node->n_lock); @@ -427,7 +429,7 @@ smb_oplock_release(smb_node_t *node, boolean_t have_rwx) node->flags &= ~NODE_OPLOCKS_IN_FORCE; node->n_oplock.op_flags &= ~OPLOCK_FLAG_BREAKING; node->n_oplock.op_ofile = NULL; - node->n_oplock.op_ipaddr = 0; + bzero(&node->n_oplock.op_ipaddr, sizeof (node->n_oplock.op_ipaddr)); node->n_oplock.op_kid = 0; if (!have_rwx) diff --git a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c index 9383d328b4..0b9eb8cba9 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c +++ b/usr/src/uts/common/fs/smbsrv/smb_path_name_reduction.c @@ -494,14 +494,16 @@ smb_pathname( if (++nlink > MAXSYMLINKS) { err = ELOOP; + VN_RELE(vp); break; } (void) pn_alloc(&link_pn); err = pn_getsymlink(vp, &link_pn, cred); + VN_RELE(vp); if (err) { - (void) pn_free(&link_pn); + pn_free(&link_pn); break; } @@ -537,6 +539,7 @@ smb_pathname( fnode = smb_node_lookup(sr, NULL, cred, vp, namep, dnode, NULL, &attr); + VN_RELE(vp); if (fnode == NULL) { err = ENOMEM; @@ -548,6 +551,7 @@ smb_pathname( upn.pn_path++; upn.pn_pathlen--; } + } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_search.c b/usr/src/uts/common/fs/smbsrv/smb_search.c deleted file mode 100644 index d4c752ab7a..0000000000 --- a/usr/src/uts/common/fs/smbsrv/smb_search.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#pragma ident "@(#)smb_search.c 1.9 08/08/07 SMI" - -/* - * SMB: search - * - * This command is used to search directories. - * - * Client Request Description - * ================================== ================================= - * - * UCHAR WordCount; Count of parameter words = 2 - * USHORT MaxCount; Number of dir. entries to return - * USHORT SearchAttributes; - * USHORT ByteCount; Count of data bytes; min = 5 - * UCHAR BufferFormat1; 0x04 -- ASCII - * UCHAR FileName[]; File name, may be null - * UCHAR BufferFormat2; 0x05 -- Variable block - * USHORT ResumeKeyLength; Length of resume key, may be 0 - * UCHAR ResumeKey[]; Resume key - * - * FileName specifies the file to be sought. SearchAttributes indicates - * the attributes that the file must have, and is described in the "File - * Attribute Encoding" section of this document. If SearchAttributes is - * zero then only normal files are returned. If the system file, hidden or - * directory attributes are specified then the search is inclusive@both the - * specified type(s) of files and normal files are returned. If the volume - * label attribute is specified then the search is exclusive, and only the - * volume label entry is returned. - * - * MaxCount specifies the number of directory entries to be returned. - * - * Server Response Description - * ================================== ================================= - * - * UCHAR WordCount; Count of parameter words = 1 - * USHORT Count; Number of entries returned - * USHORT ByteCount; Count of data bytes; min = 3 - * UCHAR BufferFormat; 0x05 -- Variable block - * USHORT DataLength; Length of data - * UCHAR DirectoryInformationData[]; Data - * - * The response will contain one or more directory entries as determined by - * the Count field. No more than MaxCount entries will be returned. Only - * entries that match the sought FileName and SearchAttributes combination - * will be returned. - * - * ResumeKey must be null (length = 0) on the initial search request. - * Subsequent search requests intended to continue a search must contain - * the ResumeKey field extracted from the last directory entry of the - * previous response. ResumeKey is self-contained, for on calls containing - * a non-zero ResumeKey neither the SearchAttributes or FileName fields - * will be valid in the request. ResumeKey has the following format: - * - * Resume Key Field Description - * ================================== ================================= - * - * UCHAR Reserved; bit 7 - consumer use - * bits 5,6 - system use (must - * preserve) - * bits 0-4 - server use (must - * preserve) - * UCHAR FileName[11]; Name of the returned file - * UCHAR ReservedForServer[5]; Client must not modify - * UCHAR ReservedForConsumer[4]; Server must not modify - * - * FileName is 8.3 format, with the three character extension left - * justified into FileName[9-11]. If the client is prior to the LANMAN1.0 - * dialect, the returned FileName should be uppercased. - * - * SMB_COM_SEARCH terminates when either the requested maximum number of - * entries that match the named file are found, or the end of directory is - * reached without the maximum number of matches being found. A response - * containing no entries indicates that no matching entries were found - * between the starting point of the search and the end of directory. - * - * There may be multiple matching entries in response to a single request - * as SMB_COM_SEARCH supports wildcards in the last component of FileName - * of the initial request. - * - * Returned directory entries in the DirectoryInformationData field of the - * response each have the following format: - * - * Directory Information Field Description - * ================================== ================================= - * - * SMB_RESUME_KEY ResumeKey; Described above - * UCHAR FileAttributes; Attributes of the found file - * SMB_TIME LastWriteTime; Time file was last written - * SMB_DATE LastWriteDate; Date file was last written - * ULONG FileSize; Size of the file - * UCHAR FileName[13]; ASCII, space-filled null - * terminated - * - * FileName must conform to 8.3 rules, and is padded after the extension - * with 0x20 characters if necessary. If the client has negotiated a - * dialect prior to the LANMAN1.0 dialect, or if bit0 of the Flags2 SMB - * header field of the request is clear, the returned FileName should be - * uppercased. - * - * As can be seen from the above structure, SMB_COM_SEARCH can not return - * long filenames, and can not return UNICODE filenames. Files which have - * a size greater than 2^32 bytes should have the least significant 32 bits - * of their size returned in FileSize. - */ - -#include <smbsrv/smb_incl.h> - -smb_sdrc_t -smb_pre_search(smb_request_t *sr) -{ - DTRACE_SMB_1(op__Search__start, smb_request_t *, sr); - return (SDRC_SUCCESS); -} - -void -smb_post_search(smb_request_t *sr) -{ - DTRACE_SMB_1(op__Search__done, smb_request_t *, sr); -} - -smb_sdrc_t -smb_com_search(smb_request_t *sr) -{ - int rc; - unsigned short sattr, count, maxcount; - char *path; - uint16_t index; - uint32_t cookie; - char name[SMB_SHORTNAMELEN]; - unsigned char resume_char; - uint32_t client_key; - smb_tree_t *tree; - smb_node_t *node; - unsigned char type; - unsigned short key_len; - smb_odir_context_t *pc; - boolean_t find_first = B_TRUE; - boolean_t to_upper = B_FALSE; - - if ((sr->session->dialect <= LANMAN1_0) || - ((sr->smb_flg2 & SMB_FLAGS2_KNOWS_LONG_NAMES) == 0)) { - to_upper = B_TRUE; - } - - /* We only handle 8.3 name here */ - sr->smb_flg2 &= ~SMB_FLAGS2_KNOWS_LONG_NAMES; - sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE; - - if (smbsr_decode_vwv(sr, "ww", &maxcount, &sattr) != 0) - return (SDRC_ERROR); - - rc = smbsr_decode_data(sr, "%Abw", sr, &path, &type, &key_len); - if ((rc != 0) || (type != 0x05)) - return (SDRC_ERROR); - - tree = sr->tid_tree; - count = 0; - - if ((sattr == FILE_ATTRIBUTE_VOLUME) && (key_len != 21)) { - (void) memset(name, ' ', sizeof (name)); - (void) strncpy(name, tree->t_volume, sizeof (name)); - - if (key_len >= 21) { - (void) smb_mbc_decodef(&sr->smb_data, "17.l", - &client_key); - } else { - client_key = 0; - } - - (void) smb_mbc_encodef(&sr->reply, "bwwbwb11c5.lb8.13c", - 1, 0, VAR_BCC, 5, 0, 0, path+1, - client_key, sattr, name); - count++; - } else { - index = 0; - cookie = 0; - - if (key_len == 0) { /* begin search */ - /* - * Some MS clients pass NULL file names - * NT interprets this as "\" - */ - if (strlen(path) == 0) path = "\\"; - - rc = smb_rdir_open(sr, path, sattr); - if (rc == -1) - return (SDRC_ERROR); - if (rc == -2) { - sr->reply.chain_offset = sr->cur_reply_offset; - (void) smb_mbc_encodef(&sr->reply, "bw", 0, 0); - return (SDRC_SUCCESS); - } - resume_char = 0; - client_key = 0; - } else if (key_len == 21) { - if (smb_mbc_decodef(&sr->smb_data, "b12.wwl", - &resume_char, &index, &sr->smb_sid, &client_key) - != 0) { - /* We don't know which search to close! */ - return (SDRC_ERROR); - } - - sr->sid_odir = smb_odir_lookup_by_sid(tree, - sr->smb_sid); - if (sr->sid_odir == NULL) { - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, - ERRDOS, ERRbadfid); - return (SDRC_ERROR); - } - cookie = sr->sid_odir->d_cookies[index]; - if (cookie != 0) - find_first = B_FALSE; - } else { - /* We don't know which search to close! */ - return (SDRC_ERROR); - } - - (void) smb_mbc_encodef(&sr->reply, "bwwbw", 1, 0, - VAR_BCC, 5, 0); - - pc = kmem_zalloc(sizeof (smb_odir_context_t), KM_SLEEP); - pc->dc_cookie = cookie; - node = NULL; - rc = 0; - index = 0; - - if (maxcount > SMB_MAX_SEARCH) - maxcount = SMB_MAX_SEARCH; - - while (count < maxcount) { - if ((rc = smb_rdir_next(sr, &node, pc)) != 0) - break; - - if (smb_is_dot_or_dotdot(pc->dc_name)) { - if (node) { - smb_node_release(node); - node = NULL; - } - continue; - } - - (void) memset(name, ' ', sizeof (name)); - if (*pc->dc_shortname) { - (void) strlcpy(name, pc->dc_shortname, - SMB_SHORTNAMELEN - 1); - } else { - (void) strlcpy(name, pc->dc_name, - SMB_SHORTNAMELEN - 1); - if (to_upper) - (void) utf8_strupr(name); - } - - (void) smb_mbc_encodef(&sr->reply, "b8c3c.wwlbYl13c", - resume_char, - pc->dc_name83, pc->dc_name83+9, - index, sr->smb_sid, client_key, - pc->dc_dattr & 0xff, - smb_gmt2local(sr, - pc->dc_attr.sa_vattr.va_mtime.tv_sec), - (int32_t)smb_node_get_size(node, &pc->dc_attr), - name); - smb_node_release(node); - node = NULL; - sr->sid_odir->d_cookies[index] = pc->dc_cookie; - count++; - index++; - } - - kmem_free(pc, sizeof (smb_odir_context_t)); - - if ((rc != 0) && (rc != ENOENT)) { - /* returned error by smb_rdir_next() */ - smb_rdir_close(sr); - smbsr_errno(sr, rc); - return (SDRC_ERROR); - } - - if (count == 0 && find_first) { - smb_rdir_close(sr); - smbsr_warn(sr, NT_STATUS_NO_MORE_FILES, - ERRDOS, ERROR_NO_MORE_FILES); - return (SDRC_ERROR); - } - } - - rc = (sr->reply.chain_offset - sr->cur_reply_offset) - 8; - (void) smb_mbc_poke(&sr->reply, sr->cur_reply_offset, "bwwbw", - 1, count, rc+3, 5, rc); - - return (SDRC_SUCCESS); -} diff --git a/usr/src/uts/common/fs/smbsrv/smb_server.c b/usr/src/uts/common/fs/smbsrv/smb_server.c index 9296f123be..5e7b0f50d3 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_server.c +++ b/usr/src/uts/common/fs/smbsrv/smb_server.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -233,7 +233,7 @@ static void smb_server_kstat_fini(smb_server_t *); static int smb_server_kstat_update_info(kstat_t *, int); static void smb_server_timers(smb_thread_t *, void *); static int smb_server_listen(smb_server_t *, smb_listener_daemon_t *, - in_port_t, int); + in_port_t, int, int); static int smb_server_lookup(smb_server_t **); static void smb_server_release(smb_server_t *); static int smb_server_ulist_geti(smb_session_list_t *, int, @@ -563,7 +563,7 @@ smb_server_start(struct smb_io_start *io_start) sv->sv_cfg.skc_maxworkers, INT_MAX, TASKQ_DYNAMIC|TASKQ_PREPOPULATE); - sv->sv_session = smb_session_create(NULL, 0, sv); + sv->sv_session = smb_session_create(NULL, 0, sv, 0); if (sv->sv_thread_pool == NULL || sv->sv_session == NULL) { rc = ENOMEM; @@ -666,8 +666,11 @@ smb_server_nbt_listen(int error) } mutex_exit(&sv->sv_mutex); + /* + * netbios must be ipv4 + */ rc = smb_server_listen(sv, &sv->sv_nbt_daemon, SSN_SRVC_TCP_PORT, - error); + AF_INET, error); if (rc) { mutex_enter(&sv->sv_mutex); @@ -711,9 +714,12 @@ smb_server_tcp_listen(int error) } mutex_exit(&sv->sv_mutex); - rc = smb_server_listen(sv, &sv->sv_tcp_daemon, SMB_SRVC_TCP_PORT, - error); - + if (sv->sv_cfg.skc_ipv6_enable) + rc = smb_server_listen(sv, &sv->sv_tcp_daemon, + SMB_SRVC_TCP_PORT, AF_INET6, error); + else + rc = smb_server_listen(sv, &sv->sv_tcp_daemon, + SMB_SRVC_TCP_PORT, AF_INET, error); if (rc) { mutex_enter(&sv->sv_mutex); sv->sv_tcp_daemon.ld_kth = NULL; @@ -1239,6 +1245,7 @@ smb_server_listen( smb_server_t *sv, smb_listener_daemon_t *ld, in_port_t port, + int family, int pthread_create_error) { int rc; @@ -1256,21 +1263,31 @@ smb_server_listen( if (ld->ld_so == NULL) { /* First time listener */ - ld->ld_sin.sin_family = AF_INET; - ld->ld_sin.sin_port = htons(port); - ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY); - ld->ld_so = smb_socreate(AF_INET, SOCK_STREAM, 0); - + if (family == AF_INET) { + ld->ld_sin.sin_family = (uint32_t)family; + ld->ld_sin.sin_port = htons(port); + ld->ld_sin.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + ld->ld_sin6.sin6_family = (uint32_t)family; + ld->ld_sin6.sin6_port = htons(port); + (void) memset(&ld->ld_sin6.sin6_addr.s6_addr, 0, + sizeof (ld->ld_sin6.sin6_addr.s6_addr)); + } + ld->ld_so = smb_socreate(family, SOCK_STREAM, 0); if (ld->ld_so) { (void) ksocket_setsockopt(ld->ld_so, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (on), CRED()); - - rc = ksocket_bind(ld->ld_so, - (struct sockaddr *)&ld->ld_sin, - sizeof (ld->ld_sin), CRED()); - + if (family == AF_INET) { + rc = ksocket_bind(ld->ld_so, + (struct sockaddr *)&ld->ld_sin, + sizeof (ld->ld_sin), CRED()); + } else { + rc = ksocket_bind(ld->ld_so, + (struct sockaddr *)&ld->ld_sin6, + sizeof (ld->ld_sin6), CRED()); + } if (rc == 0) { rc = ksocket_listen(ld->ld_so, 20, CRED()); if (rc < 0) { @@ -1318,7 +1335,7 @@ smb_server_listen( /* * Create a session for this connection. */ - session = smb_session_create(s_so, port, sv); + session = smb_session_create(s_so, port, sv, family); if (session) { smb_session_list_append(&ld->ld_session_list, session); diff --git a/usr/src/uts/common/fs/smbsrv/smb_session.c b/usr/src/uts/common/fs/smbsrv/smb_session.c index 571dee63c3..e88dedc9f0 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -32,6 +32,7 @@ #include <smbsrv/netbios.h> #include <smbsrv/smb_incl.h> #include <smbsrv/smb_i18n.h> +#include <inet/tcp.h> static volatile uint64_t smb_kids; @@ -42,7 +43,7 @@ static int smb_session_xprt_puthdr(smb_session_t *, smb_xprt_t *, uint8_t *, size_t); static smb_user_t *smb_session_lookup_user(smb_session_t *, char *, char *); static void smb_request_init_command_mbuf(smb_request_t *sr); - +void dump_smb_inaddr(smb_inaddr_t *ipaddr); void smb_session_timers(smb_session_list_t *se) @@ -120,7 +121,7 @@ smb_session_correct_keep_alive_values( * there is no NetBIOS name. See also Knowledge Base article Q301673. */ void -smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *session) +smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *sess) { smb_session_t *sn; @@ -128,12 +129,14 @@ smb_session_reconnection_check(smb_session_list_t *se, smb_session_t *session) sn = list_head(&se->se_act.lst); while (sn) { ASSERT(sn->s_magic == SMB_SESSION_MAGIC); - if ((sn != session) && - (sn->ipaddr == session->ipaddr) && - (sn->local_ipaddr == session->local_ipaddr) && - (strcasecmp(sn->workstation, session->workstation) == 0) && - (sn->opentime <= session->opentime) && - (sn->s_kid < session->s_kid)) { + if ((sn != sess) && + smb_inet_equal(&sn->ipaddr, &sess->ipaddr, + SMB_INET_NOMASK) && + smb_inet_equal(&sn->local_ipaddr, &sess->local_ipaddr, + SMB_INET_NOMASK) && + (strcasecmp(sn->workstation, sess->workstation) == 0) && + (sn->opentime <= sess->opentime) && + (sn->s_kid < sess->s_kid)) { tsignal(sn->s_thread, SIGINT); } sn = list_next(&se->se_act.lst, sn); @@ -323,8 +326,8 @@ smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr) ret_hdr->xh_type = buf[0]; if (ret_hdr->xh_type != 0) { - cmn_err(CE_WARN, "0x%08x: invalid type (%u)", - session->ipaddr, ret_hdr->xh_type); + cmn_err(CE_WARN, "invalid type (%u)", ret_hdr->xh_type); + dump_smb_inaddr(&session->ipaddr); return (EPROTO); } @@ -334,8 +337,8 @@ smb_session_xprt_gethdr(smb_session_t *session, smb_xprt_t *ret_hdr) break; default: - cmn_err(CE_WARN, "0x%08x: invalid port %u", - session->ipaddr, session->s_local_port); + cmn_err(CE_WARN, "invalid port %u", session->s_local_port); + dump_smb_inaddr(&session->ipaddr); return (EPROTO); } @@ -371,8 +374,8 @@ smb_session_xprt_puthdr(smb_session_t *session, smb_xprt_t *hdr, break; default: - cmn_err(CE_WARN, "0x%08x: invalid port (%u)", - session->ipaddr, session->s_local_port); + cmn_err(CE_WARN, "invalid port %u", session->s_local_port); + dump_smb_inaddr(&session->ipaddr); return (-1); } @@ -634,10 +637,12 @@ smb_session_message(smb_session_t *session) * Port will be SSN_SRVC_TCP_PORT or SMB_SRVC_TCP_PORT. */ smb_session_t * -smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv) +smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv, + int family) { struct sockaddr_in sin; socklen_t slen; + struct sockaddr_in6 sin6; smb_session_t *session; session = kmem_cache_alloc(sv->si_cache_session, KM_SLEEP); @@ -669,17 +674,25 @@ smb_session_create(ksocket_t new_so, uint16_t port, smb_server_t *sv) smb_rwx_init(&session->s_lock); if (new_so) { - slen = sizeof (sin); - - (void) ksocket_getsockname(new_so, (struct sockaddr *)&sin, - &slen, CRED()); - session->local_ipaddr = sin.sin_addr.s_addr; - - slen = sizeof (sin); - (void) ksocket_getpeername(new_so, (struct sockaddr *)&sin, - &slen, CRED()); - session->ipaddr = sin.sin_addr.s_addr; - + if (family == AF_INET) { + slen = sizeof (sin); + (void) ksocket_getsockname(new_so, + (struct sockaddr *)&sin, &slen, CRED()); + bcopy(&sin, &session->local_ipaddr.a_ip, slen); + (void) ksocket_getpeername(new_so, + (struct sockaddr *)&sin, &slen, CRED()); + bcopy(&sin6, &session->ipaddr.a_ip, slen); + } else { + slen = sizeof (sin6); + (void) ksocket_getsockname(new_so, + (struct sockaddr *)&sin6, &slen, CRED()); + bcopy(&sin, &session->local_ipaddr.a_ip, slen); + (void) ksocket_getpeername(new_so, + (struct sockaddr *)&sin6, &slen, CRED()); + bcopy(&sin6, &session->ipaddr.a_ip, slen); + } + session->ipaddr.a_family = family; + session->local_ipaddr.a_family = family; session->s_local_port = port; session->sock = new_so; } @@ -1105,7 +1118,6 @@ smb_request_free(smb_request_t *sr) ASSERT(sr->sr_magic == SMB_REQ_MAGIC); ASSERT(sr->session); ASSERT(sr->fid_ofile == NULL); - ASSERT(sr->sid_odir == NULL); ASSERT(sr->r_xa == NULL); if (sr->tid_tree) @@ -1134,3 +1146,14 @@ smb_request_free(smb_request_t *sr) mutex_destroy(&sr->sr_mutex); kmem_cache_free(sr->sr_cache, sr); } + +void +dump_smb_inaddr(smb_inaddr_t *ipaddr) +{ +char ipstr[INET6_ADDRSTRLEN]; + + if (smb_inet_ntop(ipaddr, ipstr, SMB_IPSTRLEN(ipaddr->a_family))) + cmn_err(CE_WARN, "error ipstr=%s", ipstr); + else + cmn_err(CE_WARN, "error converting ip address"); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c index 5665b6cd66..8a28585fd4 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c +++ b/usr/src/uts/common/fs/smbsrv/smb_session_setup_andx.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* @@ -226,6 +226,29 @@ #include <smbsrv/smb_token.h> #include <smbsrv/smb_door_svc.h> +typedef struct smb_sessionsetup_info { + char *ssi_user; + char *ssi_domain; + char *ssi_native_os; + char *ssi_native_lm; + uint16_t ssi_cipwlen; + uint8_t *ssi_cipwd; + uint16_t ssi_cspwlen; + uint8_t *ssi_cspwd; + uint16_t ssi_maxbufsize; + uint16_t ssi_maxmpxcount; + uint16_t ssi_vcnumber; + uint32_t ssi_capabilities; + uint32_t ssi_sesskey; +} smb_sessionsetup_info_t; + +#define SMB_AUTH_FAILED -1 +#define SMB_AUTH_USER 0 +#define SMB_AUTH_GUEST 1 + +static int smb_authenticate(smb_request_t *, smb_sessionsetup_info_t *, + smb_session_key_t **); + smb_sdrc_t smb_pre_session_setup_andx(smb_request_t *sr) { @@ -242,41 +265,26 @@ smb_post_session_setup_andx(smb_request_t *sr) smb_sdrc_t smb_com_session_setup_andx(smb_request_t *sr) { - uint16_t maxbufsize, maxmpxcount, vcnumber = 0; - uint32_t sesskey; - uint32_t capabilities = 0; - char *username = ""; - char *userdomain = ""; - char *native_os = ""; - char *native_lanman = ""; - char *hostname = sr->sr_cfg->skc_hostname; - char *nbdomain = sr->sr_cfg->skc_nbdomain; - char *fqdn = sr->sr_cfg->skc_fqdn; - smb_token_t *usr_token = NULL; - smb_user_t *user = NULL; - int security = sr->sr_cfg->skc_secmode; - - uint16_t ci_pwlen = 0; - unsigned char *ci_password = NULL; - uint16_t cs_pwlen = 0; - unsigned char *cs_password = NULL; - - netr_client_t clnt_info; + smb_sessionsetup_info_t sinfo; smb_session_key_t *session_key = NULL; - int rc; char ipaddr_buf[INET6_ADDRSTRLEN]; - boolean_t known_domain; + int auth_res; + int rc; + + bzero(&sinfo, sizeof (smb_sessionsetup_info_t)); if (sr->session->dialect >= NT_LM_0_12) { rc = smbsr_decode_vwv(sr, "b.wwwwlww4.l", &sr->andx_com, - &sr->andx_off, &maxbufsize, &maxmpxcount, &vcnumber, - &sesskey, &ci_pwlen, &cs_pwlen, &capabilities); + &sr->andx_off, &sinfo.ssi_maxbufsize, + &sinfo.ssi_maxmpxcount, &sinfo.ssi_vcnumber, + &sinfo.ssi_sesskey, &sinfo.ssi_cipwlen, + &sinfo.ssi_cspwlen, &sinfo.ssi_capabilities); if (rc != 0) return (SDRC_ERROR); - ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP); - cs_password = kmem_alloc(cs_pwlen + 1, KM_SLEEP); + sinfo.ssi_cipwd = kmem_alloc(sinfo.ssi_cipwlen + 1, KM_SLEEP); + sinfo.ssi_cspwd = kmem_alloc(sinfo.ssi_cspwlen + 1, KM_SLEEP); /* * The padding between the Native OS and Native LM is a @@ -293,27 +301,30 @@ smb_com_session_setup_andx(smb_request_t *sr) */ rc = smbsr_decode_data(sr, "%#c#cuuu", sr, - ci_pwlen, ci_password, - cs_pwlen, cs_password, - &username, - &userdomain, - &native_os); + sinfo.ssi_cipwlen, sinfo.ssi_cipwd, + sinfo.ssi_cspwlen, sinfo.ssi_cspwd, + &sinfo.ssi_user, + &sinfo.ssi_domain, + &sinfo.ssi_native_os); if (rc != 0) { - kmem_free(ci_password, ci_pwlen + 1); - kmem_free(cs_password, cs_pwlen + 1); + kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); + kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); return (SDRC_ERROR); } - ci_password[ci_pwlen] = 0; - cs_password[cs_pwlen] = 0; + sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0; + sinfo.ssi_cspwd[sinfo.ssi_cspwlen] = 0; - sr->session->native_os = smbnative_os_value(native_os); + sr->session->native_os = + smbnative_os_value(sinfo.ssi_native_os); if (sr->session->native_os == NATIVE_OS_WINNT) - rc = smbsr_decode_data(sr, "%,u", sr, &native_lanman); + rc = smbsr_decode_data(sr, "%,u", sr, + &sinfo.ssi_native_lm); else - rc = smbsr_decode_data(sr, "%u", sr, &native_lanman); + rc = smbsr_decode_data(sr, "%u", sr, + &sinfo.ssi_native_lm); /* * Native Lanman could be null so we really don't care @@ -321,24 +332,26 @@ smb_com_session_setup_andx(smb_request_t *sr) * the field we set it to Win NT. */ if (rc != 0) - native_lanman = "NT LAN Manager 4.0"; - + sinfo.ssi_native_lm = "NT LAN Manager 4.0"; } else { rc = smbsr_decode_vwv(sr, "b.wwwwlw4.", &sr->andx_com, - &sr->andx_off, &maxbufsize, &maxmpxcount, - &vcnumber, &sesskey, &ci_pwlen); + &sr->andx_off, &sinfo.ssi_maxbufsize, + &sinfo.ssi_maxmpxcount, + &sinfo.ssi_vcnumber, &sinfo.ssi_sesskey, + &sinfo.ssi_cipwlen); if (rc != 0) return (SDRC_ERROR); - ci_password = kmem_alloc(ci_pwlen + 1, KM_SLEEP); - rc = smbsr_decode_data(sr, "%#c", sr, ci_pwlen, ci_password); + sinfo.ssi_cipwd = kmem_alloc(sinfo.ssi_cipwlen + 1, KM_SLEEP); + rc = smbsr_decode_data(sr, "%#c", sr, sinfo.ssi_cipwlen, + sinfo.ssi_cipwd); if (rc != 0) { - kmem_free(ci_password, ci_pwlen + 1); + kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); return (SDRC_ERROR); } - ci_password[ci_pwlen] = 0; + sinfo.ssi_cipwd[sinfo.ssi_cipwlen] = 0; /* * Despite the CIFS/1.0 spec, the rest of this message is @@ -346,191 +359,50 @@ smb_com_session_setup_andx(smb_request_t *sr) * name and the primary domain but we don't care about the * the native OS or native LanMan fields. */ - if (smbsr_decode_data(sr, "%u", sr, &username) != 0) - username = ""; + if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_user) != 0) + sinfo.ssi_user = ""; - if (smbsr_decode_data(sr, "%u", sr, &userdomain) != 0) - userdomain = ""; + if (smbsr_decode_data(sr, "%u", sr, &sinfo.ssi_domain) != 0) + sinfo.ssi_domain = ""; sr->session->native_os = NATIVE_OS_UNKNOWN; } /* - * If the vcnumber is zero, we can discard any + * If the sinfo.ssi_vcnumber is zero, we can discard any * other connections associated with this client. */ - sr->session->vcnumber = vcnumber; - if (vcnumber == 0) + sr->session->vcnumber = sinfo.ssi_vcnumber; + if (sinfo.ssi_vcnumber == 0) smb_server_reconnection_check(sr->sr_server, sr->session); - sr->session->smb_msg_size = maxbufsize; - - bzero(&clnt_info, sizeof (netr_client_t)); - - /* - * Both local and domain users can be authenticated in - * domain mode. Whether a user is local or not is determined - * by given domain name in the request. If client does not - * specify the domain name, both local and domain - * authentications should be tried. The preferred order is to - * try the local authentication first. - */ - known_domain = B_TRUE; - if (*userdomain == 0) { - userdomain = hostname; - if (security == SMB_SECMODE_DOMAIN) - known_domain = B_FALSE; - } - - if ((cs_pwlen == 0) && - (ci_pwlen == 0 || (ci_pwlen == 1 && *ci_password == 0))) { - /* anonymous user */ - clnt_info.flags |= NETR_CFLG_ANON; - username = "nobody"; - } else if (*username == '\0') { - if (ci_password) - kmem_free(ci_password, ci_pwlen + 1); - if (cs_password) - kmem_free(cs_password, cs_pwlen + 1); + sr->session->smb_msg_size = sinfo.ssi_maxbufsize; + + if ((sinfo.ssi_cspwlen == 0) && + (sinfo.ssi_cipwlen == 0 || + (sinfo.ssi_cipwlen == 1 && *sinfo.ssi_cipwd == 0))) { + sinfo.ssi_user = "anonymous"; + } else if (*sinfo.ssi_user == '\0') { + if (sinfo.ssi_cipwd) + kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); + if (sinfo.ssi_cspwd) + kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); smbsr_error(sr, 0, ERRSRV, ERRaccess); return (SDRC_ERROR); - } else if (security == SMB_SECMODE_DOMAIN) { - /* - * If the system is running in domain mode, domain - * authentication will be performed only when the client - * sends the domain that matches either the NetBIOS name - * or FQDN of the domain. Otherwise, local authentication - * will be performed. - */ - if (utf8_strcasecmp(userdomain, nbdomain) == 0 || - utf8_strcasecmp(userdomain, fqdn) == 0) - clnt_info.flags |= NETR_CFLG_DOMAIN; - else - clnt_info.flags |= NETR_CFLG_LOCAL; - } else if (security == SMB_SECMODE_WORKGRP) { - clnt_info.flags |= NETR_CFLG_LOCAL; } - /* - * If the domain is unknown, we are unable to determine - * whether the specified user is local or domain until - * the authentication has taken place; thus, the user - * lookup will be postponed until the user is successfully - * authenticated. - */ - if (known_domain) - user = smb_session_dup_user(sr->session, - (clnt_info.flags & NETR_CFLG_LOCAL) ? - hostname : nbdomain, username); - - if (user == NULL) { - cred_t *cr; - uint32_t privileges; - - clnt_info.logon_level = NETR_NETWORK_LOGON; - clnt_info.domain = userdomain; - clnt_info.username = username; - clnt_info.workstation = sr->session->workstation; - clnt_info.ipaddr = sr->session->ipaddr; - clnt_info.local_ipaddr = sr->session->local_ipaddr; - clnt_info.challenge_key.challenge_key_val = - sr->session->challenge_key; - clnt_info.challenge_key.challenge_key_len = - sr->session->challenge_len; - clnt_info.nt_password.nt_password_val = cs_password; - clnt_info.nt_password.nt_password_len = cs_pwlen; - clnt_info.lm_password.lm_password_val = ci_password; - clnt_info.lm_password.lm_password_len = ci_pwlen; - clnt_info.native_os = sr->session->native_os; - clnt_info.native_lm = smbnative_lm_value(native_lanman); - clnt_info.local_port = sr->session->s_local_port; - - DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *, - &clnt_info); - - usr_token = smb_upcall_get_token(&clnt_info); - - /* - * If the domain is unknown and we fail to authenticate - * the user locally, pass-through authentication will be - * attempted. - */ - if (!known_domain) { - if (usr_token == NULL) { - clnt_info.domain = nbdomain; - clnt_info.flags &= ~NETR_CFLG_LOCAL; - clnt_info.flags |= NETR_CFLG_DOMAIN; - usr_token = smb_upcall_get_token(&clnt_info); - } - - /* - * Now that the user has successfully been - * authenticated, the clnt_info.domain is valid. - * Try to see if the user has already logged in from - * this session. - * - * If this is a subsequent login, a duplicate user - * instance will be returned. Otherwise, NULL is - * returned. - */ - if (usr_token != NULL) - user = smb_session_dup_user(sr->session, - clnt_info.domain, username); - } - - - /* authentication fails */ - if (usr_token == NULL) { - if (ci_password) - kmem_free(ci_password, ci_pwlen + 1); - if (cs_password) - kmem_free(cs_password, cs_pwlen + 1); - smbsr_error(sr, 0, ERRSRV, ERRbadpw); - return (SDRC_ERROR); - } - - if (usr_token->tkn_session_key) { - session_key = kmem_alloc(sizeof (smb_session_key_t), - KM_SLEEP); - (void) memcpy(session_key, usr_token->tkn_session_key, - sizeof (smb_session_key_t)); - } - - /* first login */ - if (user == NULL) { - cr = smb_cred_create(usr_token, &privileges); - if (cr != NULL) { - user = smb_user_login(sr->session, cr, - usr_token->tkn_domain_name, - usr_token->tkn_account_name, - usr_token->tkn_flags, - privileges, - usr_token->tkn_audit_sid); - smb_cred_rele(user->u_cred); - - if (user->u_privcred) - smb_cred_rele(user->u_privcred); - } - } - smb_token_free(usr_token); - } + auth_res = smb_authenticate(sr, &sinfo, &session_key); - if (ci_password) - kmem_free(ci_password, ci_pwlen + 1); + if (sinfo.ssi_cipwd) + kmem_free(sinfo.ssi_cipwd, sinfo.ssi_cipwlen + 1); - if (user == NULL) { - if (session_key) - kmem_free(session_key, sizeof (smb_session_key_t)); - if (cs_password) - kmem_free(cs_password, cs_pwlen + 1); - smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); + if (auth_res == SMB_AUTH_FAILED) { + if (sinfo.ssi_cspwd) + kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); return (SDRC_ERROR); } - sr->user_cr = user->u_cred; - sr->smb_uid = user->u_uid; - sr->uid_user = user; - sr->session->capabilities = capabilities; + sr->session->capabilities = sinfo.ssi_capabilities; /* * Check to see if SMB signing is enable, but if it is already turned @@ -543,18 +415,19 @@ smb_com_session_setup_andx(smb_request_t *sr) (sr->session->secmode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) && (sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) && session_key) - smb_sign_init(sr, session_key, (char *)cs_password, cs_pwlen); + smb_sign_init(sr, session_key, (char *)sinfo.ssi_cspwd, + sinfo.ssi_cspwlen); - if (cs_password) - kmem_free(cs_password, cs_pwlen + 1); + if (sinfo.ssi_cspwd) + kmem_free(sinfo.ssi_cspwd, sinfo.ssi_cspwlen + 1); if (session_key) kmem_free(session_key, sizeof (smb_session_key_t)); if (!(sr->smb_flg2 & SMB_FLAGS2_SMB_SECURITY_SIGNATURE) && (sr->sr_cfg->skc_signing_required)) { - (void) inet_ntop(AF_INET, (char *)&sr->session->ipaddr, - ipaddr_buf, sizeof (ipaddr_buf)); + (void) smb_inet_ntop(&sr->session->ipaddr, ipaddr_buf, + SMB_IPSTRLEN(sr->session->ipaddr.a_family)); cmn_err(CE_NOTE, "SmbSessonSetupX: client %s is not capable of signing", ipaddr_buf); @@ -580,12 +453,172 @@ smb_com_session_setup_andx(smb_request_t *sr) 3, sr->andx_com, -1, /* andx_off */ - ((user->u_flags & SMB_USER_FLAG_GUEST) ? 1 : 0), + (auth_res == SMB_AUTH_GUEST) ? 1 : 0, VAR_BCC, sr, "Windows NT 4.0", "NT LAN Manager 4.0", - nbdomain); + sr->sr_cfg->skc_nbdomain); return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); } + +/* + * Tries to authenticate the connected user. + * + * It first tries to see if the user has already been authenticated. + * If a match is found, the user structure in the session is duplicated + * and the function returns. Otherwise, user information is passed to + * smbd for authentication. If smbd can authenticate the user an access + * token structure is returned. A cred_t and user structure is created + * based on the returned access token. + */ +static int +smb_authenticate(smb_request_t *sr, smb_sessionsetup_info_t *sinfo, + smb_session_key_t **session_key) +{ + char *hostname = sr->sr_cfg->skc_hostname; + int security = sr->sr_cfg->skc_secmode; + smb_token_t *usr_token = NULL; + smb_user_t *user = NULL; + netr_client_t clnt_info; + boolean_t need_lookup = B_FALSE; + uint32_t privileges; + cred_t *cr; + char *buf; + size_t buflen = 0; + char *p; + + bzero(&clnt_info, sizeof (netr_client_t)); + + /* + * Handle user@domain format. + * + * We need to extract the user and domain names but + * should keep the request data as is. This is important + * for some forms of authentication. + */ + clnt_info.real_username = sinfo->ssi_user; + clnt_info.real_domain = sinfo->ssi_domain; + + if (*sinfo->ssi_domain == '\0') { + buflen = strlen(sinfo->ssi_user) + 1; + buf = smb_kstrdup(sinfo->ssi_user, buflen); + if ((p = strchr(buf, '@')) != NULL) { + *p = '\0'; + clnt_info.real_username = buf; + clnt_info.real_domain = p + 1; + } + } + + /* + * See if this user has already been authenticated. + * + * If no domain name is provided we cannot determine whether + * this is a local or domain user when server is operating + * in domain mode, so lookup will be done after authentication. + */ + if (security == SMB_SECMODE_WORKGRP) { + user = smb_session_dup_user(sr->session, hostname, + clnt_info.real_username); + } else if (*clnt_info.real_domain != '\0') { + user = smb_session_dup_user(sr->session, clnt_info.real_domain, + clnt_info.real_username); + } else { + need_lookup = B_TRUE; + } + + if (user != NULL) { + sr->user_cr = user->u_cred; + sr->smb_uid = user->u_uid; + sr->uid_user = user; + + if (buflen != 0) + kmem_free(buf, buflen); + + return ((user->u_flags & SMB_USER_FLAG_GUEST) + ? SMB_AUTH_GUEST : SMB_AUTH_USER); + } + + clnt_info.logon_level = NETR_NETWORK_LOGON; + clnt_info.domain = sinfo->ssi_domain; + clnt_info.username = sinfo->ssi_user; + clnt_info.workstation = sr->session->workstation; + clnt_info.ipaddr = sr->session->ipaddr; + clnt_info.local_ipaddr = sr->session->local_ipaddr; + clnt_info.challenge_key.challenge_key_val = + sr->session->challenge_key; + clnt_info.challenge_key.challenge_key_len = + sr->session->challenge_len; + clnt_info.nt_password.nt_password_val = sinfo->ssi_cspwd; + clnt_info.nt_password.nt_password_len = sinfo->ssi_cspwlen; + clnt_info.lm_password.lm_password_val = sinfo->ssi_cipwd; + clnt_info.lm_password.lm_password_len = sinfo->ssi_cipwlen; + clnt_info.native_os = sr->session->native_os; + clnt_info.native_lm = smbnative_lm_value(sinfo->ssi_native_lm); + clnt_info.local_port = sr->session->s_local_port; + + DTRACE_PROBE1(smb__sessionsetup__clntinfo, netr_client_t *, + &clnt_info); + + usr_token = smb_get_token(&clnt_info); + + if (buflen != 0) + kmem_free(buf, buflen); + + if (usr_token == NULL) { + smbsr_error(sr, 0, ERRSRV, ERRbadpw); + return (SMB_AUTH_FAILED); + } + + if (need_lookup) { + user = smb_session_dup_user(sr->session, + usr_token->tkn_domain_name, usr_token->tkn_account_name); + + if (user != NULL) { + sr->user_cr = user->u_cred; + sr->smb_uid = user->u_uid; + sr->uid_user = user; + + smb_token_free(usr_token); + return ((user->u_flags & SMB_USER_FLAG_GUEST) + ? SMB_AUTH_GUEST : SMB_AUTH_USER); + } + } + + if (usr_token->tkn_session_key) { + *session_key = kmem_alloc(sizeof (smb_session_key_t), + KM_SLEEP); + (void) memcpy(*session_key, usr_token->tkn_session_key, + sizeof (smb_session_key_t)); + } + + if ((cr = smb_cred_create(usr_token, &privileges)) != NULL) { + user = smb_user_login(sr->session, cr, + usr_token->tkn_domain_name, + usr_token->tkn_account_name, + usr_token->tkn_flags, + privileges, + usr_token->tkn_audit_sid); + + smb_cred_rele(user->u_cred); + if (user->u_privcred) + smb_cred_rele(user->u_privcred); + } + + smb_token_free(usr_token); + + if (user == NULL) { + if (*session_key) + kmem_free(*session_key, sizeof (smb_session_key_t)); + smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_HANDLE); + return (SMB_AUTH_FAILED); + } + + sr->user_cr = user->u_cred; + sr->smb_uid = user->u_uid; + sr->uid_user = user; + + return ((user->u_flags & SMB_USER_FLAG_GUEST) + ? SMB_AUTH_GUEST : SMB_AUTH_USER); +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c index e70b0d4fa0..7bd197c74f 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c +++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_find.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -204,47 +204,20 @@ #include <smbsrv/smb_incl.h> #include <smbsrv/msgbuf.h> -#include <smbsrv/smbtrans.h> #include <smbsrv/smb_fsops.h> -static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t); - -int smb_trans2_find_get_dents(smb_request_t *, smb_xa_t *, - uint16_t, uint16_t, int, smb_node_t *, - uint16_t, uint16_t, int, char *, uint32_t *, int *, int *); - -int smb_gather_dents_info(char *, ino_t, int, char *, uint32_t, int32_t *, - smb_attr_t *, smb_node_t *, char *, char *); +typedef struct smb_find_args { + uint16_t fa_infolev; + uint16_t fa_maxcount; + uint16_t fa_fflag; + uint32_t fa_maxdata; +} smb_find_args_t; -int smb_trans2_find_process_ients(smb_request_t *, smb_xa_t *, - smb_dent_info_hdr_t *, uint16_t, uint16_t, int, - smb_node_t *, int *, uint32_t *); - -int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *, - smb_dent_info_t *, int, uint16_t, uint16_t, - uint32_t, smb_node_t *, smb_node_t *); - -/* - * The UNIX characters below are considered illegal in Windows file names. - * The following character conversions are used to support sites in which - * Catia v4 is in use on UNIX and Catia v5 is in use on Windows. - * - * --------------------------- - * Unix-char | Windows-char - * --------------------------- - * " | (0x00a8) Diaeresis - * * | (0x00a4) Currency Sign - * : | (0x00f7) Division Sign - * < | (0x00ab) Left-Pointing Double Angle Quotation Mark - * > | (0x00bb) Right-Pointing Double Angle Quotation Mark - * ? | (0x00bf) Inverted Question mark - * \ | (0x00ff) Latin Small Letter Y with Diaeresis - * | | (0x00a6) Broken Bar - */ -static int (*catia_callback)(uint8_t *, uint8_t *, int) = NULL; -void smb_register_catia_callback( - int (*catia_v4tov5)(uint8_t *, uint8_t *, int)); -void smb_unregister_catia_callback(); +static int smb_trans2_find_entries(smb_request_t *, smb_xa_t *, + smb_odir_t *, smb_find_args_t *, boolean_t *); +static int smb_trans2_find_get_maxdata(smb_request_t *, uint16_t, uint16_t); +static int smb_trans2_find_mbc_encode(smb_request_t *, smb_xa_t *, + smb_fileinfo_t *, smb_find_args_t *); /* * Tunable parameter to limit the maximum @@ -253,32 +226,6 @@ void smb_unregister_catia_callback(); uint16_t smb_trans2_find_max = 128; /* - * smb_register_catia_callback - * - * This function will be invoked by the catia module to register its - * function that translates filename in version 4 to a format that is - * compatible to version 5. - */ -void -smb_register_catia_callback( - int (*catia_v4tov5)(uint8_t *, uint8_t *, int)) -{ - catia_callback = catia_v4tov5; -} - -/* - * smb_unregister_catia_callback - * - * This function will unregister the catia callback prior to the catia - * module gets unloaded. - */ -void -smb_unregister_catia_callback() -{ - catia_callback = 0; -} - -/* * smb_com_trans2_find_first2 * * Client Request Value @@ -324,16 +271,14 @@ smb_unregister_catia_callback() smb_sdrc_t smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) { - int more = 0, rc; - uint16_t sattr, fflag, infolev; - uint16_t maxcount = 0; - int maxdata; - int count, wildcards; - uint32_t cookie; + int count; + uint16_t sattr, odid; char *path; - smb_node_t *dir_snode; - char *pattern; - uint16_t sid; + smb_odir_t *od; + smb_find_args_t args; + boolean_t eos; + + bzero(&args, sizeof (smb_find_args_t)); if (!STYPE_ISDSK(sr->tid_tree->t_res_type)) { smbsr_error(sr, NT_STATUS_ACCESS_DENIED, @@ -341,94 +286,57 @@ smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) return (SDRC_ERROR); } - if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, - &sattr, &maxcount, &fflag, &infolev, &path) != 0) { + if (smb_mbc_decodef(&xa->req_param_mb, "%wwww4.u", sr, &sattr, + &args.fa_maxcount, &args.fa_fflag, &args.fa_infolev, &path) != 0) { return (SDRC_ERROR); } - /* - * stream files not allowed - */ if (smb_is_stream_name(path)) { smbsr_error(sr, NT_STATUS_OBJECT_NAME_INVALID, ERRDOS, ERROR_INVALID_NAME); return (SDRC_ERROR); } - if (fflag & SMB_FIND_WITH_BACKUP_INTENT) + if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) sr->user_cr = smb_user_getprivcred(sr->uid_user); - maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag); - if (maxdata == 0) { - smbsr_error(sr, NT_STATUS_INVALID_LEVEL, - ERRDOS, ERROR_INVALID_LEVEL); + args.fa_maxdata = + smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); + if (args.fa_maxdata == 0) return (SDRC_ERROR); - } - - /* - * When maxcount is zero Windows behaves as if it was 1. - */ - if (maxcount == 0) - maxcount = 1; - - if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) - maxcount = smb_trans2_find_max; if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) (void) smb_convert_unicode_wildcards(path); - if (smb_rdir_open(sr, path, sattr) != 0) + odid = smb_odir_open(sr, path, sattr); + if (odid == 0) return (SDRC_ERROR); - /* - * Get a copy of information - */ - dir_snode = sr->sid_odir->d_dir_snode; - pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP); - (void) strcpy(pattern, sr->sid_odir->d_pattern); - - if (strcmp(pattern, "*.*") == 0) - (void) strncpy(pattern, "*", sizeof (pattern)); - - wildcards = sr->sid_odir->d_wildcards; - sattr = sr->sid_odir->d_sattr; - cookie = 0; - - rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata, - dir_snode, sattr, maxcount, wildcards, - pattern, &cookie, &more, &count); - - if (!count) - rc = ENOENT; + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) + return (SDRC_ERROR); + count = smb_trans2_find_entries(sr, xa, od, &args, &eos); + smb_odir_release(od); - if (rc) { - smb_rdir_close(sr); - kmem_free(pattern, MAXNAMELEN); - smbsr_errno(sr, rc); + if (count == -1) { + smb_odir_close(od); return (SDRC_ERROR); } - /* - * Save the sid here in case the search is closed below, - * which will invalidate sr->smb_sid. We return the - * sid, even though the search has been closed, to be - * compatible with Windows. - */ - sid = sr->smb_sid; - - if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST || - (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) { - smb_rdir_close(sr); - } else { - mutex_enter(&sr->sid_odir->d_mutex); - sr->sid_odir->d_cookie = cookie; - mutex_exit(&sr->sid_odir->d_mutex); + if (count == 0) { + smb_odir_close(od); + smbsr_errno(sr, ENOENT); + return (SDRC_ERROR); } + if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || + (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { + smb_odir_close(od); + } /* else leave odir open for trans2_find_next2 */ + (void) smb_mbc_encodef(&xa->rep_param_mb, "wwwww", - sid, count, (more ? 0 : 1), 0, 0); + odid, count, (eos) ? 1 : 0, 0, 0); - kmem_free(pattern, MAXNAMELEN); return (SDRC_SUCCESS); } @@ -486,10 +394,10 @@ smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) * null-terminated unicode string. * * smb_mbc_decodef(&xa->req_param_mb, "%www lwu", sr, - * &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag, &fname) + * &odid, &fa_maxcount, &fa_infolev, &cookie, &fa_fflag, &fname) * - * The filename parameter is not currently decoded because we a - * expect 2-byte null but Mac OS 10 clients send a 1-byte null, + * The filename parameter is not currently decoded because we + * expect a 2-byte null but Mac OS 10 clients send a 1-byte null, * which leads to a decode error. * Thus, we do not support resume by filename. We treat a request * to resume by filename as SMB_FIND_CONTINUE_FROM_LAST. @@ -497,88 +405,118 @@ smb_com_trans2_find_first2(smb_request_t *sr, smb_xa_t *xa) smb_sdrc_t smb_com_trans2_find_next2(smb_request_t *sr, smb_xa_t *xa) { - uint16_t fflag, infolev; - int maxdata, count, wildcards, more = 0, rc; - uint32_t cookie; - uint16_t maxcount = 0; - smb_node_t *dir_snode; - char *pattern; - uint16_t sattr; - - if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, - &sr->smb_sid, &maxcount, &infolev, &cookie, &fflag) != 0) { + int count; + uint16_t odid; + uint32_t cookie; + smb_odir_t *od; + smb_find_args_t args; + boolean_t eos; + smb_odir_resume_t odir_resume; + + bzero(&args, sizeof (smb_find_args_t)); + + if (smb_mbc_decodef(&xa->req_param_mb, "%wwwlw", sr, &odid, + &args.fa_maxcount, &args.fa_infolev, &cookie, &args.fa_fflag) + != 0) { return (SDRC_ERROR); } /* continuation by filename not supported */ - if (cookie == 0) - fflag |= SMB_FIND_CONTINUE_FROM_LAST; + if ((args.fa_fflag & SMB_FIND_CONTINUE_FROM_LAST) || (cookie == 0)) { + odir_resume.or_type = SMB_ODIR_RESUME_IDX; + odir_resume.or_idx = 0; + } else { + odir_resume.or_type = SMB_ODIR_RESUME_COOKIE; + odir_resume.or_cookie = cookie; + } - if (fflag & SMB_FIND_WITH_BACKUP_INTENT) + if (args.fa_fflag & SMB_FIND_WITH_BACKUP_INTENT) sr->user_cr = smb_user_getprivcred(sr->uid_user); - sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid); - if (sr->sid_odir == NULL) { - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); + args.fa_maxdata = + smb_trans2_find_get_maxdata(sr, args.fa_infolev, args.fa_fflag); + if (args.fa_maxdata == 0) + return (SDRC_ERROR); + + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, + ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } + smb_odir_resume_at(od, &odir_resume); + count = smb_trans2_find_entries(sr, xa, od, &args, &eos); + smb_odir_release(od); - maxdata = smb_trans2_find_get_maxdata(sr, infolev, fflag); - if (maxdata == 0) { - smb_rdir_close(sr); - smbsr_error(sr, NT_STATUS_INVALID_LEVEL, - ERRDOS, ERROR_INVALID_LEVEL); + if (count == -1) { + smb_odir_close(od); return (SDRC_ERROR); } - /* - * When maxcount is zero Windows behaves as if it was 1. - */ - if (maxcount == 0) + if ((args.fa_fflag & SMB_FIND_CLOSE_AFTER_REQUEST) || + (eos && (args.fa_fflag & SMB_FIND_CLOSE_AT_EOS))) { + smb_odir_close(od); + } /* else leave odir open for trans2_find_next2 */ + + (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", + count, (eos) ? 1 : 0, 0, 0); + + return (SDRC_SUCCESS); +} + + +/* + * smb_trans2_find_entries + * + * Find and encode up to args->fa_maxcount directory entries. + * For compatibilty with Windows, if args->fa_maxcount is zero treat it as 1. + * + * Returns: + * count - count of entries encoded + * *eos = B_TRUE if no more directory entries + * -1 - error + */ +static int +smb_trans2_find_entries(smb_request_t *sr, smb_xa_t *xa, smb_odir_t *od, + smb_find_args_t *args, boolean_t *eos) +{ + int rc; + uint16_t count, maxcount; + uint32_t cookie; + smb_fileinfo_t fileinfo; + + if ((maxcount = args->fa_maxcount) == 0) maxcount = 1; if ((smb_trans2_find_max != 0) && (maxcount > smb_trans2_find_max)) maxcount = smb_trans2_find_max; - /* - * Get a copy of information - */ - dir_snode = sr->sid_odir->d_dir_snode; - pattern = kmem_alloc(MAXNAMELEN, KM_SLEEP); - (void) strcpy(pattern, sr->sid_odir->d_pattern); - wildcards = sr->sid_odir->d_wildcards; - sattr = sr->sid_odir->d_sattr; - if (fflag & SMB_FIND_CONTINUE_FROM_LAST) { - mutex_enter(&sr->sid_odir->d_mutex); - cookie = sr->sid_odir->d_cookie; - mutex_exit(&sr->sid_odir->d_mutex); - } + count = 0; + while (count < maxcount) { + if (smb_odir_read_fileinfo(sr, od, &fileinfo, eos) != 0) + return (-1); + if (*eos == B_TRUE) + break; - rc = smb_trans2_find_get_dents(sr, xa, fflag, infolev, maxdata, - dir_snode, sattr, maxcount, wildcards, pattern, &cookie, - &more, &count); + rc = smb_trans2_find_mbc_encode(sr, xa, &fileinfo, args); + if (rc == -1) + return (-1); + if (rc == 1) + break; - if (rc) { - smb_rdir_close(sr); - kmem_free(pattern, MAXNAMELEN); - smbsr_errno(sr, rc); - return (SDRC_ERROR); + cookie = fileinfo.fi_cookie; + ++count; } - if (fflag & SMB_FIND_CLOSE_AFTER_REQUEST || - (!more && fflag & SMB_FIND_CLOSE_AT_EOS)) - smb_rdir_close(sr); - else { - mutex_enter(&sr->sid_odir->d_mutex); - sr->sid_odir->d_cookie = cookie; - mutex_exit(&sr->sid_odir->d_mutex); - } + /* save the last cookie returned to client */ + if (count != 0) + smb_odir_save_cookie(od, 0, cookie); - (void) smb_mbc_encodef(&xa->rep_param_mb, "wwww", - count, (more ? 0 : 1), 0, 0); + /* if eos not already detected, check if more entries */ + if (!*eos) + (void) smb_odir_read_fileinfo(sr, od, &fileinfo, eos); - kmem_free(pattern, MAXNAMELEN); - return (SDRC_SUCCESS); + return (count); } /* @@ -642,341 +580,15 @@ smb_trans2_find_get_maxdata(smb_request_t *sr, uint16_t infolev, uint16_t fflag) default: maxdata = 0; + smbsr_error(sr, NT_STATUS_INVALID_LEVEL, + ERRDOS, ERROR_INVALID_LEVEL); } return (maxdata); } /* - * smb_trans2_find_get_dents - * - * This function will get all the directory entry information and mbc - * encode it in the xa. If there is an error, it will be returned; - * otherwise, 0 is returned. - * - * The more field will be updated. If the value returned is one, it means - * there are more entries; otherwise, the returned value will be zero. The - * cookie will also be updated to indicate the next start point for the - * search. The count value will also be updated to stores the total entries - * encoded. - */ -int smb_trans2_find_get_dents( - smb_request_t *sr, - smb_xa_t *xa, - uint16_t fflag, - uint16_t infolev, - int maxdata, - smb_node_t *dir_snode, - uint16_t sattr, - uint16_t maxcount, - int wildcards, - char *pattern, - uint32_t *cookie, - int *more, - int *count) -{ - smb_dent_info_hdr_t *ihdr; - smb_dent_info_t *ient; - int dent_buf_size; - int i; - int total; - int maxentries; - int rc; - - ihdr = kmem_zalloc(sizeof (smb_dent_info_hdr_t), KM_SLEEP); - *count = 0; - - if (!wildcards) - maxentries = maxcount = 1; - else { - maxentries = (xa->rep_data_mb.max_bytes - - xa->rep_data_mb.chain_offset) / maxdata; - if (maxcount > SMB_MAX_DENTS_IOVEC) - maxcount = SMB_MAX_DENTS_IOVEC; - if (maxentries > maxcount) - maxentries = maxcount; - } - - /* Each entry will need to be aligned so add _POINTER_ALIGNMENT */ - dent_buf_size = - maxentries * (SMB_MAX_DENT_INFO_SIZE + _POINTER_ALIGNMENT); - ihdr->iov->iov_base = kmem_alloc(dent_buf_size, KM_SLEEP); - - ihdr->sattr = sattr; - ihdr->pattern = pattern; - ihdr->sr = sr; - - ihdr->uio.uio_iovcnt = maxcount; - ihdr->uio.uio_resid = dent_buf_size; - ihdr->uio.uio_iov = ihdr->iov; - ihdr->uio.uio_loffset = 0; - - rc = smb_get_dents(sr, cookie, dir_snode, wildcards, ihdr, more); - if (rc != 0) { - goto out; - } - - if (ihdr->iov->iov_len == 0) - *count = 0; - else - *count = smb_trans2_find_process_ients(sr, xa, ihdr, fflag, - infolev, maxdata, dir_snode, more, cookie); - rc = 0; - -out: - - total = maxcount - ihdr->uio.uio_iovcnt; - ASSERT((total >= 0) && (total <= SMB_MAX_DENTS_IOVEC)); - for (i = 0; i < total; i++) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - ient = (smb_dent_info_t *)ihdr->iov[i].iov_base; - ASSERT(ient); - smb_node_release(ient->snode); - } - - kmem_free(ihdr->iov->iov_base, dent_buf_size); - kmem_free(ihdr, sizeof (smb_dent_info_hdr_t)); - return (0); -} - - -/* - * smb_get_dents - * - * This function utilizes "smb_fsop_getdents()" to get dir entries. - * The "smb_gather_dents_info()" is the call back function called - * inside the file system. It is very important that the function - * does not sleep or yield since it is processed inside a file - * system transaction. - * - * The function returns 0 when successful and error code when failed. - * If more is provided, the return value of 1 is returned indicating - * more entries; otherwise, 0 is returned. - */ -int smb_get_dents( - smb_request_t *sr, - uint32_t *cookie, - smb_node_t *dir_snode, - uint32_t wildcards, - smb_dent_info_hdr_t *ihdr, - int *more) -{ - int rc; - char *namebuf; - smb_node_t *snode; - smb_attr_t file_attr; - uint32_t maxcnt = ihdr->uio.uio_iovcnt; - char shortname[SMB_SHORTNAMELEN], name83[SMB_SHORTNAMELEN]; - - namebuf = kmem_zalloc(MAXNAMELEN, KM_SLEEP); - if (more) - *more = 0; - - if (!wildcards) { - /* Already found entry? */ - if (*cookie != 0) - return (0); - shortname[0] = '\0'; - - rc = smb_fsop_lookup(sr, sr->user_cr, 0, sr->tid_tree->t_snode, - dir_snode, ihdr->pattern, &snode, &file_attr, shortname, - name83); - - if (rc) { - kmem_free(namebuf, MAXNAMELEN); - return (rc); - } - - (void) strlcpy(namebuf, snode->od_name, MAXNAMELEN); - - /* - * It is not necessary to set the "force" flag (i.e. to - * take into account mangling for case-insensitive collisions) - */ - - if (shortname[0] == '\0') - (void) smb_mangle_name(snode->attr.sa_vattr.va_nodeid, - namebuf, shortname, name83, 0); - (void) smb_gather_dents_info((char *)ihdr, - snode->attr.sa_vattr.va_nodeid, - strlen(namebuf), namebuf, -1, (int *)&maxcnt, - &snode->attr, snode, shortname, name83); - kmem_free(namebuf, MAXNAMELEN); - return (0); - } - - if ((rc = smb_fsop_getdents(sr, sr->user_cr, dir_snode, cookie, - 0, (int *)&maxcnt, (char *)ihdr, ihdr->pattern)) != 0) { - if (rc == ENOENT) { - kmem_free(namebuf, MAXNAMELEN); - return (0); - } - kmem_free(namebuf, MAXNAMELEN); - return (rc); - } - - if (*cookie != 0x7FFFFFFF && more) - *more = 1; - - kmem_free(namebuf, MAXNAMELEN); - return (0); -} - - -/* - * smb_gather_dents_info - * - * The function will accept information of each directory entry and put - * the needed information in the buffer. It is passed as the call back - * function for smb_fsop_getdents() to gather trans2 find info. - * - * Only valid entry will be stored in the buffer. - * - * Returns: -1 - error, buffer too small - * n - number of valid entries (0 or 1) - */ -int /*ARGSUSED*/ -smb_gather_dents_info( - char *args, - ino_t fileid, - int namelen, - char *name, - uint32_t cookie, - int32_t *countp, - smb_attr_t *attr, - smb_node_t *snode, - char *shortname, - char *name83) -{ - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)args; - smb_dent_info_t *ient; - uint8_t *v5_name = NULL; - uint8_t *np = (uint8_t *)name; - int reclen = sizeof (smb_dent_info_t) + namelen; - - v5_name = kmem_alloc(MAXNAMELEN-1, KM_SLEEP); - - if (!ihdr->uio.uio_iovcnt || ihdr->uio.uio_resid < reclen) { - kmem_free(v5_name, MAXNAMELEN-1); - smb_node_release(snode); - return (-1); - } - - if (!smb_sattr_check(attr, name, ihdr->sattr)) { - kmem_free(v5_name, MAXNAMELEN-1); - smb_node_release(snode); - return (0); - } - - if (catia_callback) { - catia_callback(v5_name, (uint8_t *)name, MAXNAMELEN-1); - np = v5_name; - reclen = sizeof (smb_dent_info_t) + strlen((char *)v5_name); - } - - ASSERT(snode); - ASSERT(snode->n_magic == SMB_NODE_MAGIC); - ASSERT(snode->n_state != SMB_NODE_STATE_DESTROYING); - - /* - * Each entry needs to be properly aligned or we may get an alignment - * fault on sparc. - */ - ihdr->uio.uio_loffset = (offset_t)PTRALIGN(ihdr->uio.uio_loffset); - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - ient = (smb_dent_info_t *)&ihdr->iov->iov_base[ihdr->uio.uio_loffset]; - - ient->cookie = cookie; - ient->attr = *attr; - ient->snode = snode; - - (void) strcpy(ient->name, (char *)np); - (void) strcpy(ient->shortname, shortname); - (void) strcpy(ient->name83, name83); - ihdr->uio.uio_iov->iov_base = (char *)ient; - ihdr->uio.uio_iov->iov_len = reclen; - - ihdr->uio.uio_iov++; - ihdr->uio.uio_iovcnt--; - ihdr->uio.uio_resid -= reclen; - ihdr->uio.uio_loffset += reclen; - - kmem_free(v5_name, MAXNAMELEN-1); - return (1); -} - - - -/* - * smb_trans2_find_process_ients - * - * This function encodes the directory entry information store in - * the iov structure of the ihdr structure. - * - * The total entries encoded will be returned. If the entries encoded - * is less than the total entries in the iov, the more field will - * be updated to 1. Also, the next cookie wil be updated as well. - */ -int -smb_trans2_find_process_ients( - smb_request_t *sr, - smb_xa_t *xa, - smb_dent_info_hdr_t *ihdr, - uint16_t fflag, - uint16_t infolev, - int maxdata, - smb_node_t *dir_snode, - int *more, - uint32_t *cookie) -{ - int i, err = 0; - smb_dent_info_t *ient; - uint32_t mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) - ? SMB_MSGBUF_UNICODE : 0; - - for (i = 0; i < SMB_MAX_DENTS_IOVEC; i++) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - if ((ient = (smb_dent_info_t *)ihdr->iov[i].iov_base) == 0) - break; - - /* - * Observed differences between our response and Windows - * response, which hasn't caused a problem yet! - * - * 1. The NextEntryOffset field for the last entry should - * be 0. This code always calculate the record length - * and puts the result in the NextEntryOffset field. - * - * 2. The FileIndex field is always 0. This code puts - * the cookie in the FileIndex field. - */ - err = smb_trans2_find_mbc_encode(sr, xa, ient, maxdata, infolev, - fflag, mb_flags, dir_snode, NULL); - - if (err) - break; - } - - /* - * Not enough space to store all the entries returned, - * which is indicated by setting more. - */ - if (more && err < 0) { - *more = 1; - - /* - * Assume the space will be at least enough for 1 entry. - */ - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - ient = (smb_dent_info_t *)ihdr->iov[i-1].iov_base; - *cookie = ient->cookie; - } - return (i); -} - -/* - * smb_trans2_find_mbc_encode + * smb_trans2_mbc_encode * * This function encodes the mbc for one directory entry. * @@ -991,41 +603,31 @@ smb_trans2_find_process_ients( * filename is ascii the name length returned to the client should * include the null terminator. Otherwise the length returned to * the client should not include the terminator. + * + * Returns: 0 - data successfully encoded + * 1 - client request's maxdata limit reached + * -1 - error */ -int /*ARGSUSED*/ -smb_trans2_find_mbc_encode( - smb_request_t *sr, - smb_xa_t *xa, - smb_dent_info_t *ient, - int maxdata, - uint16_t infolev, - uint16_t fflag, - uint32_t mb_flags, - smb_node_t *dir_snode, - smb_node_t *sd_snode) +static int +smb_trans2_find_mbc_encode(smb_request_t *sr, smb_xa_t *xa, + smb_fileinfo_t *fileinfo, smb_find_args_t *args) { - int namelen, shortlen, buflen; - uint32_t next_entry_offset; - char buf83[26]; - char *tmpbuf; - smb_msgbuf_t mb; - uint32_t dattr = 0; - uint32_t dsize32 = 0; - uint32_t asize32 = 0; - u_offset_t datasz = 0; - u_offset_t allocsz = 0; - smb_node_t *lnk_snode; - smb_attr_t lnkattr; - int rc; - - namelen = smb_ascii_or_unicode_strlen(sr, ient->name); + int namelen, shortlen, buflen; + uint32_t next_entry_offset; + uint32_t dsize32, asize32; + uint32_t mb_flags = 0; + char buf83[26]; + char *tmpbuf; + smb_msgbuf_t mb; + + namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); if (namelen == -1) - return (1); + return (-1); - next_entry_offset = maxdata + namelen; + next_entry_offset = args->fa_maxdata + namelen; - if (MBC_ROOM_FOR(&xa->rep_data_mb, (maxdata + namelen)) == 0) - return (-1); + if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0) + return (1); /* * If ascii the filename length returned to the client should @@ -1033,77 +635,38 @@ smb_trans2_find_mbc_encode( * EASIZE. */ if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { - if ((infolev != SMB_INFO_STANDARD) && - (infolev != SMB_INFO_QUERY_EA_SIZE)) + if ((args->fa_infolev != SMB_INFO_STANDARD) && + (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) namelen += 1; } - if (ient->attr.sa_vattr.va_type == VLNK) { - rc = smb_fsop_lookup(sr, sr->user_cr, SMB_FOLLOW_LINKS, - sr->tid_tree->t_snode, dir_snode, ient->name, &lnk_snode, - &lnkattr, 0, 0); - - /* - * We normally want to resolve the object to which a symlink - * refers so that CIFS clients can access sub-directories and - * find the correct association for files. This causes a - * problem, however, if a symlink in a sub-directory points - * to a parent directory (some UNIX GUI's create a symlink in - * $HOME/.desktop that points to the user's home directory). - * Some Windows applications (i.e. virus scanning) loop/hang - * trying to follow this recursive path and there is little - * we can do because the path is constructed on the client. - * skc_dirsymlink_enable allows an end-user to disable - * symlinks to directories. Symlinks to other object types - * should be unaffected. - */ - if (rc == 0) { - if (smb_dirsymlink_enable || - (lnkattr.sa_vattr.va_type != VDIR)) { - smb_node_release(ient->snode); - ient->snode = lnk_snode; - ient->attr = lnkattr; - } else { - smb_node_release(lnk_snode); - } - } - } - - if (infolev != SMB_FIND_FILE_NAMES_INFO) { - /* data size */ - datasz = smb_node_get_size(ient->snode, &ient->attr); - dsize32 = (datasz > UINT_MAX) ? UINT_MAX : (uint32_t)datasz; + mb_flags = (sr->smb_flg2 & SMB_FLAGS2_UNICODE) ? SMB_MSGBUF_UNICODE : 0; + dsize32 = (fileinfo->fi_size > UINT_MAX) ? + UINT_MAX : (uint32_t)fileinfo->fi_size; + asize32 = (fileinfo->fi_alloc_size > UINT_MAX) ? + UINT_MAX : (uint32_t)fileinfo->fi_alloc_size; - /* allocation size */ - allocsz = ient->attr.sa_vattr.va_nblocks * DEV_BSIZE; - asize32 = (allocsz > UINT_MAX) ? UINT_MAX : (uint32_t)allocsz; - - dattr = smb_node_get_dosattr(ient->snode); - } - - switch (infolev) { + switch (args->fa_infolev) { case SMB_INFO_STANDARD: - if (fflag & SMB_FIND_RETURN_RESUME_KEYS) + if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) (void) smb_mbc_encodef(&xa->rep_data_mb, "l", - ient->cookie); + fileinfo->fi_cookie); (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr, - ient->attr.sa_crtime.tv_sec ? - smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) : - smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec), - smb_gmt2local(sr, ient->attr.sa_vattr.va_atime.tv_sec), - smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec), + smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec), + smb_gmt2local(sr, fileinfo->fi_atime.tv_sec), + smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec), dsize32, asize32, - dattr, + fileinfo->fi_dosattr, namelen, - ient->name); + fileinfo->fi_name); break; case SMB_INFO_QUERY_EA_SIZE: - if (fflag & SMB_FIND_RETURN_RESUME_KEYS) + if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) (void) smb_mbc_encodef(&xa->rep_data_mb, "l", - ient->cookie); + fileinfo->fi_cookie); /* * Unicode filename should NOT be aligned. Encode ('u') @@ -1115,7 +678,7 @@ smb_trans2_find_mbc_encode( buflen = namelen + sizeof (mts_wchar_t); tmpbuf = kmem_zalloc(buflen, KM_SLEEP); smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags); - if (smb_msgbuf_encode(&mb, "u", ient->name) < 0) { + if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) { smb_msgbuf_term(&mb); kmem_free(tmpbuf, buflen); return (-1); @@ -1123,14 +686,12 @@ smb_trans2_find_mbc_encode( tmpbuf[namelen] = '\0'; (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr, - ient->attr.sa_crtime.tv_sec ? - smb_gmt2local(sr, ient->attr.sa_crtime.tv_sec) : - smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec), - smb_gmt2local(sr, ient->attr.sa_vattr.va_atime.tv_sec), - smb_gmt2local(sr, ient->attr.sa_vattr.va_mtime.tv_sec), + smb_gmt2local(sr, fileinfo->fi_crtime.tv_sec), + smb_gmt2local(sr, fileinfo->fi_atime.tv_sec), + smb_gmt2local(sr, fileinfo->fi_mtime.tv_sec), dsize32, asize32, - dattr, + fileinfo->fi_dosattr, 0L, /* EA Size */ namelen, namelen + 1, @@ -1143,81 +704,77 @@ smb_trans2_find_mbc_encode( case SMB_FIND_FILE_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr, next_entry_offset, - ient->cookie, - ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_atime, - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_ctime, - (uint64_t)datasz, - (uint64_t)allocsz, - dattr, + fileinfo->fi_cookie, + &fileinfo->fi_crtime, + &fileinfo->fi_atime, + &fileinfo->fi_mtime, + &fileinfo->fi_ctime, + fileinfo->fi_size, + fileinfo->fi_alloc_size, + fileinfo->fi_dosattr, namelen, - ient->name); + fileinfo->fi_name); break; case SMB_FIND_FILE_FULL_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr, next_entry_offset, - ient->cookie, - ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_atime, - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_ctime, - (uint64_t)datasz, - (uint64_t)allocsz, - dattr, + fileinfo->fi_cookie, + &fileinfo->fi_crtime, + &fileinfo->fi_atime, + &fileinfo->fi_mtime, + &fileinfo->fi_ctime, + fileinfo->fi_size, + fileinfo->fi_alloc_size, + fileinfo->fi_dosattr, namelen, 0L, - ient->name); + fileinfo->fi_name); break; case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.qu", sr, next_entry_offset, - ient->cookie, - ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_atime, - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_ctime, - (uint64_t)datasz, - (uint64_t)allocsz, - dattr, + fileinfo->fi_cookie, + &fileinfo->fi_crtime, + &fileinfo->fi_atime, + &fileinfo->fi_mtime, + &fileinfo->fi_ctime, + fileinfo->fi_size, + fileinfo->fi_alloc_size, + fileinfo->fi_dosattr, namelen, 0L, - ient->attr.sa_vattr.va_nodeid, - ient->name); + fileinfo->fi_nodeid, + fileinfo->fi_name); break; case SMB_FIND_FILE_BOTH_DIRECTORY_INFO: bzero(buf83, sizeof (buf83)); smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), mb_flags); - if (smb_msgbuf_encode(&mb, "U", ient->shortname) < 0) { + if (smb_msgbuf_encode(&mb, "U", fileinfo->fi_shortname) < 0) { smb_msgbuf_term(&mb); return (-1); } - shortlen = mts_wcequiv_strlen(ient->shortname); + shortlen = mts_wcequiv_strlen(fileinfo->fi_shortname); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu", sr, next_entry_offset, - ient->cookie, - ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_atime, - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_ctime, - (uint64_t)datasz, - (uint64_t)allocsz, - dattr, + fileinfo->fi_cookie, + &fileinfo->fi_crtime, + &fileinfo->fi_atime, + &fileinfo->fi_mtime, + &fileinfo->fi_ctime, + fileinfo->fi_size, + fileinfo->fi_alloc_size, + fileinfo->fi_dosattr, namelen, 0L, shortlen, buf83, - ient->name); + fileinfo->fi_name); smb_msgbuf_term(&mb); break; @@ -1226,31 +783,31 @@ smb_trans2_find_mbc_encode( bzero(buf83, sizeof (buf83)); smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), mb_flags); - if (smb_msgbuf_encode(&mb, "u", ient->shortname) < 0) { + if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { smb_msgbuf_term(&mb); return (-1); } - shortlen = smb_ascii_or_unicode_strlen(sr, ient->shortname); + shortlen = smb_ascii_or_unicode_strlen(sr, + fileinfo->fi_shortname); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c2.qu", sr, next_entry_offset, - ient->cookie, - ient->attr.sa_crtime.tv_sec ? &ient->attr.sa_crtime : - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_atime, - &ient->attr.sa_vattr.va_mtime, - &ient->attr.sa_vattr.va_ctime, - (uint64_t)datasz, - (uint64_t)allocsz, - dattr, + fileinfo->fi_cookie, + &fileinfo->fi_crtime, + &fileinfo->fi_atime, + &fileinfo->fi_mtime, + &fileinfo->fi_ctime, + fileinfo->fi_size, + fileinfo->fi_alloc_size, + fileinfo->fi_dosattr, namelen, 0L, shortlen, buf83, - ient->attr.sa_vattr.va_nodeid, - ient->name); + fileinfo->fi_nodeid, + fileinfo->fi_name); smb_msgbuf_term(&mb); break; @@ -1258,9 +815,9 @@ smb_trans2_find_mbc_encode( case SMB_FIND_FILE_NAMES_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr, next_entry_offset, - ient->cookie, + fileinfo->fi_cookie, namelen, - ient->name); + fileinfo->fi_name); break; } @@ -1273,12 +830,8 @@ smb_trans2_find_mbc_encode( smb_sdrc_t smb_pre_find_close2(smb_request_t *sr) { - int rc; - - rc = smbsr_decode_vwv(sr, "w", &sr->smb_sid); - DTRACE_SMB_1(op__FindClose2__start, smb_request_t *, sr); - return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR); + return (SDRC_SUCCESS); } void @@ -1290,13 +843,21 @@ smb_post_find_close2(smb_request_t *sr) smb_sdrc_t smb_com_find_close2(smb_request_t *sr) { - sr->sid_odir = smb_odir_lookup_by_sid(sr->tid_tree, sr->smb_sid); - if (sr->sid_odir == NULL) { - smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid); + uint16_t odid; + smb_odir_t *od; + + if (smbsr_decode_vwv(sr, "w", &odid) != 0) + return (SDRC_ERROR); + + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od == NULL) { + smbsr_error(sr, NT_STATUS_INVALID_HANDLE, + ERRDOS, ERROR_INVALID_HANDLE); return (SDRC_ERROR); } - smb_rdir_close(sr); + smb_odir_close(od); + smb_odir_release(od); if (smbsr_encode_empty_result(sr)) return (SDRC_ERROR); diff --git a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c index f7a8e73a13..ae2012e6fd 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c +++ b/usr/src/uts/common/fs/smbsrv/smb_trans2_query_file_info.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -428,13 +428,15 @@ smb_com_trans2_query_file_information(struct smb_request *sr, struct smb_xa *xa) * entries (smb_fsop_stream_readdir) it is treated as if there are * no [more] directory entries. The entries that have been read so * far are returned and no error is reported. + * + * Offset calculation: + * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 */ - void smb_encode_stream_info( struct smb_request *sr, struct smb_xa *xa, - struct smb_node *snode, + struct smb_node *fnode, smb_attr_t *attr) { char *stream_name; @@ -442,76 +444,59 @@ smb_encode_stream_info( uint32_t stream_nlen; uint32_t pad; u_offset_t datasz; - int is_dir; - uint32_t cookie = 0; - struct fs_stream_info *stream_info; - struct fs_stream_info *stream_info_next; + boolean_t is_dir; + smb_streaminfo_t *sinfo, *sinfo_next; int rc = 0; - int done = 0; - - stream_info = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP); - stream_info_next = kmem_alloc(sizeof (struct fs_stream_info), KM_SLEEP); - is_dir = (attr->sa_vattr.va_type == VDIR) ? 1 : 0; + boolean_t done = B_FALSE; + boolean_t eos = B_FALSE; + uint16_t odid; + smb_odir_t *od = NULL; + + sinfo = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); + sinfo_next = kmem_alloc(sizeof (smb_streaminfo_t), KM_SLEEP); + is_dir = (attr->sa_vattr.va_type == VDIR); datasz = attr->sa_vattr.va_size; - rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie, stream_info, - NULL, NULL); + odid = smb_odir_openat(sr, fnode); + if (odid != 0) + od = smb_tree_lookup_odir(sr->tid_tree, odid); + if (od != NULL) + rc = smb_odir_read_streaminfo(sr, od, sinfo, &eos); - if ((cookie == 0x7FFFFFFF) || (rc != 0)) { - if (is_dir == 0) { - stream_name = "::$DATA"; - stream_nlen = - smb_ascii_or_unicode_strlen(sr, stream_name); - next_offset = 0; - - (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", - sr, next_offset, stream_nlen, datasz, datasz, - stream_name); - } - /* No named streams, we're done */ - kmem_free(stream_info, sizeof (struct fs_stream_info)); - kmem_free(stream_info_next, sizeof (struct fs_stream_info)); - return; - } + if ((od == NULL) || (rc != 0) || (eos)) + done = B_TRUE; - if (is_dir == 0) { + /* + * If not a directory, encode an entry for the unnamed stream. + */ + if (!is_dir) { stream_name = "::$DATA"; stream_nlen = smb_ascii_or_unicode_strlen(sr, stream_name); - /* - * Offset calculation: - * 2 dwords + 2 quadwords => 4 + 4 + 8 + 8 => 24 - */ - next_offset = 24 + stream_nlen + - smb_ascii_or_unicode_null_len(sr); + if (done) + next_offset = 0; + else + next_offset = 24 + stream_nlen + + smb_ascii_or_unicode_null_len(sr); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu", sr, next_offset, stream_nlen, datasz, datasz, stream_name); } + /* + * Since last packet does not have a pad we need to check + * for the next stream before we encode the current one + */ while (!done) { - /* - * Named streams. - */ - stream_nlen = smb_ascii_or_unicode_strlen(sr, - stream_info->name); - next_offset = 0; - pad = 0; + stream_nlen = smb_ascii_or_unicode_strlen(sr, sinfo->si_name); + sinfo_next->si_name[0] = 0; - /* - * this is a little kludgy, since we use a cookie now and last - * packet does not have a pad we need to check the next item - * before we encode the current one - */ - stream_info_next->name[0] = 0; - rc = smb_fsop_stream_readdir(sr, kcred, snode, &cookie, - stream_info_next, NULL, NULL); - if ((cookie == 0x7FFFFFFF) || (rc != 0)) { - done = 1; + rc = smb_odir_read_streaminfo(sr, od, sinfo_next, &eos); + if ((rc != 0) || (eos)) { + done = B_TRUE; + next_offset = 0; + pad = 0; } else { - if (cookie == 0) { - break; - } next_offset = 24 + stream_nlen + smb_ascii_or_unicode_null_len(sr); pad = smb_pad_align(next_offset, 8); @@ -519,14 +504,18 @@ smb_encode_stream_info( } (void) smb_mbc_encodef(&xa->rep_data_mb, "%llqqu#.", sr, next_offset, stream_nlen, - stream_info->size, stream_info->size, - stream_info->name, pad); + sinfo->si_size, sinfo->si_size, + sinfo->si_name, pad); + + (void) memcpy(sinfo, sinfo_next, sizeof (smb_streaminfo_t)); + } - (void) memcpy(stream_info, stream_info_next, - sizeof (struct fs_stream_info)); + kmem_free(sinfo, sizeof (smb_streaminfo_t)); + kmem_free(sinfo_next, sizeof (smb_streaminfo_t)); + if (od) { + smb_odir_release(od); + smb_odir_close(od); } - kmem_free(stream_info, sizeof (struct fs_stream_info)); - kmem_free(stream_info_next, sizeof (struct fs_stream_info)); } /* diff --git a/usr/src/uts/common/fs/smbsrv/smb_tree.c b/usr/src/uts/common/fs/smbsrv/smb_tree.c index f71e3eebce..1beea5004c 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_tree.c +++ b/usr/src/uts/common/fs/smbsrv/smb_tree.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -190,6 +190,8 @@ static int smb_tree_getattr(smb_node_t *, smb_tree_t *); static void smb_tree_get_volname(vfs_t *, smb_tree_t *); static void smb_tree_get_flags(vfs_t *, smb_tree_t *); static void smb_tree_log(smb_request_t *, const char *, const char *, ...); +static void smb_tree_close_odirs(smb_tree_t *, uint16_t); +static smb_odir_t *smb_tree_get_odir(smb_tree_t *, smb_odir_t *); /* * Extract the share name and share type and connect as appropriate. @@ -263,7 +265,7 @@ smb_tree_disconnect( /* * The directories opened under this tree are closed. */ - smb_odir_close_all(tree); + smb_tree_close_odirs(tree, 0); mutex_enter(&tree->t_mutex); tree->t_state = SMB_TREE_STATE_DISCONNECTED; } @@ -329,7 +331,7 @@ smb_tree_close_pid( ASSERT(tree->t_magic == SMB_TREE_MAGIC); smb_ofile_close_all_by_pid(tree, pid); - smb_odir_close_all_by_pid(tree, pid); + smb_tree_close_odirs(tree, pid); } /* @@ -377,7 +379,7 @@ smb_tree_connect_disk(smb_request_t *sr, const char *sharename) si = kmem_zalloc(sizeof (smb_share_t), KM_SLEEP); if (smb_kshare_getinfo(sr->sr_server->sv_lmshrd, (char *)sharename, si, - sr->session->ipaddr) != NERR_Success) { + &sr->session->ipaddr) != NERR_Success) { smb_tree_log(sr, sharename, "share not found"); smbsr_error(sr, 0, ERRSRV, ERRinvnetname); kmem_free(si, sizeof (smb_share_t)); @@ -532,7 +534,7 @@ smb_tree_alloc( return (NULL); } - if (smb_idpool_constructor(&tree->t_sid_pool)) { + if (smb_idpool_constructor(&tree->t_odid_pool)) { smb_idpool_destructor(&tree->t_fid_pool); smb_idpool_free(&user->u_tid_pool, tid); kmem_cache_free(user->u_server->si_cache_tree, tree); @@ -616,7 +618,7 @@ smb_tree_dealloc(smb_tree_t *tree) smb_llist_destructor(&tree->t_ofile_list); smb_llist_destructor(&tree->t_odir_list); smb_idpool_destructor(&tree->t_fid_pool); - smb_idpool_destructor(&tree->t_sid_pool); + smb_idpool_destructor(&tree->t_odid_pool); kmem_cache_free(tree->t_server->si_cache_tree, tree); } @@ -866,3 +868,105 @@ smb_tree_log(smb_request_t *sr, const char *sharename, const char *fmt, ...) cmn_err(CE_NOTE, "smbd[%s\\%s]: %s %s", user->u_domain, user->u_name, sharename, buf); } + +/* + * smb_tree_lookup_odir + * + * Find the specified odir in the tree's list of odirs, and + * attempt to obtain a hold on the odir. + * + * Returns NULL if odir not found or a hold cannot be obtained. + */ +smb_odir_t * +smb_tree_lookup_odir(smb_tree_t *tree, uint16_t odid) +{ + smb_odir_t *od; + smb_llist_t *od_list; + + ASSERT(tree); + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + od_list = &tree->t_odir_list; + smb_llist_enter(od_list, RW_READER); + + od = smb_llist_head(od_list); + while (od) { + if (od->d_odid == odid) { + if (!smb_odir_hold(od)) + od = NULL; + break; + } + od = smb_llist_next(od_list, od); + } + + smb_llist_exit(od_list); + return (od); +} + +/* + * smb_tree_get_odir + * + * Find the next open odir in the tree's list of odirs, and obtain + * a hold on it. (A hold can only be obtained on an open odir.) + * If the specified odir is NULL the search starts at the beginning + * of the tree's odir list, otherwise the search starts after the + * specified odir. + */ +static smb_odir_t * +smb_tree_get_odir(smb_tree_t *tree, smb_odir_t *od) +{ + smb_llist_t *od_list; + + ASSERT(tree); + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + od_list = &tree->t_odir_list; + smb_llist_enter(od_list, RW_READER); + + if (od) { + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + od = smb_llist_next(od_list, od); + } else { + od = smb_llist_head(od_list); + } + + while (od) { + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + + if (smb_odir_hold(od)) + break; + od = smb_llist_next(od_list, od); + } + + smb_llist_exit(od_list); + return (od); +} + +/* + * smb_tree_close_odirs + * + * Close all open odirs in the tree's list which were opened by + * the process identified by pid. + * If pid is zero, close all open odirs in the tree's list. + */ +static void +smb_tree_close_odirs(smb_tree_t *tree, uint16_t pid) +{ + smb_odir_t *od, *next_od; + + ASSERT(tree); + ASSERT(tree->t_magic == SMB_TREE_MAGIC); + + od = smb_tree_get_odir(tree, NULL); + while (od) { + ASSERT(od->d_magic == SMB_ODIR_MAGIC); + ASSERT(od->d_tree == tree); + + next_od = smb_tree_get_odir(tree, od); + if ((pid == 0) || (od->d_opened_by_pid == pid)) + smb_odir_close(od); + smb_odir_release(od); + + od = next_od; + } +} diff --git a/usr/src/uts/common/fs/smbsrv/smb_upcalls.c b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c index 100738bd03..cf2ce3fcdc 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_upcalls.c +++ b/usr/src/uts/common/fs/smbsrv/smb_upcalls.c @@ -63,7 +63,7 @@ smb_user_auth_logoff(uint32_t audit_sid) } smb_token_t * -smb_upcall_get_token(netr_client_t *clnt_info) +smb_get_token(netr_client_t *clnt_info) { char *arg, *rsp; size_t arg_size, rsp_size; diff --git a/usr/src/uts/common/fs/smbsrv/smb_util.c b/usr/src/uts/common/fs/smbsrv/smb_util.c index fe7bf9b546..b9bf87eae8 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_util.c +++ b/usr/src/uts/common/fs/smbsrv/smb_util.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -96,19 +96,6 @@ smb_ascii_or_unicode_null_len(struct smb_request *sr) } int -smb_component_match( - struct smb_request *sr, - ino64_t fileid, - struct smb_odir *od, - smb_odir_context_t *pc) -{ - boolean_t ignore_case = SMB_TREE_IS_CASEINSENSITIVE(sr); - - return (smb_match_name(fileid, pc->dc_name, pc->dc_shortname, - pc->dc_name83, od->d_pattern, ignore_case)); -} - -int smb_convert_unicode_wildcards(char *path) { int wildcards = 0; @@ -208,7 +195,7 @@ smb_is_dot_or_dotdot(const char *name) * Returns true if the file and sattr match; otherwise, returns false. */ boolean_t -smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr) +smb_sattr_check(uint16_t dosattr, uint16_t sattr, char *name) { if (name) { if (smb_is_dot_or_dotdot(name) && @@ -216,15 +203,15 @@ smb_sattr_check(smb_attr_t *ap, char *name, unsigned short sattr) return (B_FALSE); } - if ((ap->sa_vattr.va_type == VDIR) && + if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) && !(sattr & FILE_ATTRIBUTE_DIRECTORY)) return (B_FALSE); - if ((ap->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) && + if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && !(sattr & FILE_ATTRIBUTE_HIDDEN)) return (B_FALSE); - if ((ap->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) && + if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && !(sattr & FILE_ATTRIBUTE_SYSTEM)) return (B_FALSE); @@ -1850,14 +1837,14 @@ smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) int rc; ASSERT(id); - ASSERT(id->i_sidattr.sid); + ASSERT(id->i_sid); ksid->ks_id = id->i_id; - smb_sid_tostr(id->i_sidattr.sid, sidstr); + smb_sid_tostr(id->i_sid, sidstr); rc = smb_sid_splitstr(sidstr, &ksid->ks_rid); ASSERT(rc == 0); - ksid->ks_attr = id->i_sidattr.attrs; + ksid->ks_attr = id->i_attrs; ksid->ks_domain = ksid_lookupdomain(sidstr); } @@ -1868,19 +1855,18 @@ smb_cred_set_sid(smb_id_t *id, ksid_t *ksid) * access token. */ static ksidlist_t * -smb_cred_set_sidlist(smb_win_grps_t *token_grps) +smb_cred_set_sidlist(smb_ids_t *token_grps) { int i; ksidlist_t *lp; - lp = kmem_zalloc(KSIDLIST_MEM(token_grps->wg_count), KM_SLEEP); + lp = kmem_zalloc(KSIDLIST_MEM(token_grps->i_cnt), KM_SLEEP); lp->ksl_ref = 1; - lp->ksl_nsid = token_grps->wg_count; + lp->ksl_nsid = token_grps->i_cnt; lp->ksl_neid = 0; for (i = 0; i < lp->ksl_nsid; i++) { - smb_cred_set_sid(&token_grps->wg_groups[i], - &lp->ksl_sids[i]); + smb_cred_set_sid(&token_grps->i_ids[i], &lp->ksl_sids[i]); if (lp->ksl_sids[i].ks_id > IDMAP_WK__MAX_GID) lp->ksl_neid++; } @@ -1910,8 +1896,8 @@ smb_cred_create(smb_token_t *token, uint32_t *privileges) ASSERT(cr != NULL); posix_grps = token->tkn_posix_grps; - if (crsetugid(cr, token->tkn_user->i_id, - token->tkn_primary_grp->i_id) != 0) { + if (crsetugid(cr, token->tkn_user.i_id, + token->tkn_primary_grp.i_id) != 0) { crfree(cr); return (NULL); } @@ -1921,13 +1907,13 @@ smb_cred_create(smb_token_t *token, uint32_t *privileges) return (NULL); } - smb_cred_set_sid(token->tkn_user, &ksid); + smb_cred_set_sid(&token->tkn_user, &ksid); crsetsid(cr, &ksid, KSID_USER); - smb_cred_set_sid(token->tkn_primary_grp, &ksid); + smb_cred_set_sid(&token->tkn_primary_grp, &ksid); crsetsid(cr, &ksid, KSID_GROUP); - smb_cred_set_sid(token->tkn_owner, &ksid); + smb_cred_set_sid(&token->tkn_owner, &ksid); crsetsid(cr, &ksid, KSID_OWNER); - ksidlist = smb_cred_set_sidlist(token->tkn_win_grps); + ksidlist = smb_cred_set_sidlist(&token->tkn_win_grps); crsetsidlist(cr, ksidlist); *privileges = 0; @@ -1982,7 +1968,7 @@ smb_cred_is_member(cred_t *cr, smb_sid_t *sid) ASSERT(cr); bzero(&id, sizeof (smb_id_t)); - id.i_sidattr.sid = sid; + id.i_sid = sid; smb_cred_set_sid(&id, &ksid1); ksidlist = crgetsidlist(cr); diff --git a/usr/src/uts/common/fs/smbsrv/smb_vops.c b/usr/src/uts/common/fs/smbsrv/smb_vops.c index 5ebb2d6a3f..84643568f8 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_vops.c +++ b/usr/src/uts/common/fs/smbsrv/smb_vops.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,36 +40,13 @@ #include <smbsrv/smb_vops.h> #include <smbsrv/string.h> -#include <smbsrv/smbtrans.h> #include <smbsrv/smb_fsops.h> #include <smbsrv/smb_kproto.h> #include <smbsrv/smb_incl.h> -void -smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); - -static int -smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *); - -static int -smb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *, - ino64_t *, vnode_t **, char *, int, cred_t *, char *, int); - -static int -smb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t, - smb_request_t *, cred_t *, char *, int *, int, char *); - -extern int -smb_gather_dents_info(char *args, ino_t fileid, int namelen, - char *name, uint32_t cookie, int32_t *countp, - smb_attr_t *attr, struct smb_node *snode, - char *shortname, char *name83); - -static void -smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); - -static -callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); +static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); +static void smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); +static callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); extern sysid_t lm_alloc_sysidt(); @@ -235,6 +212,8 @@ smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount, * * File systems without VFSFT_XVATTR do not support DOS attributes or create * time (crtime). In this case the mtime is used as the crtime. + * Likewise if VOP_GETATTR doesn't return any system attributes the dosattr + * is 0 and the mtime is used as the crtime. */ int smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, @@ -273,69 +252,50 @@ smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, ret_attr->sa_vattr = tmp_xvattr.xva_vattr; ret_attr->sa_dosattr = 0; - ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); + if (tmp_xvattr.xva_vattr.va_mask & AT_XVATTR) { + xoap = xva_getxoptattr(&tmp_xvattr); + ASSERT(xoap); - xoap = xva_getxoptattr(&tmp_xvattr); - ASSERT(xoap); - - if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { - if (xoap->xoa_readonly) + if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) && + (xoap->xoa_readonly)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; - } + } - if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { - if (xoap->xoa_hidden) + if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) && + (xoap->xoa_hidden)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; - } + } - if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { - if (xoap->xoa_system) + if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) && + (xoap->xoa_system)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; - } + } - if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { - if (xoap->xoa_archive) + if ((XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) && + (xoap->xoa_archive)) { ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; - } - - ret_attr->sa_crtime = xoap->xoa_createtime; - - if (unnamed_vp) { - ret_attr->sa_vattr.va_type = VREG; - - if (ret_attr->sa_mask & SMB_AT_SIZE) { - tmp_xvattr.xva_vattr.va_mask = AT_SIZE; - - error = VOP_GETATTR(vp, &tmp_xvattr.xva_vattr, - flags, cr, &smb_ct); - if (error != 0) - return (error); - - ret_attr->sa_vattr.va_size = - tmp_xvattr.xva_vattr.va_size; - } + + ret_attr->sa_crtime = xoap->xoa_createtime; + } else { + ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; } + } else { + /* + * Support for file systems without VFSFT_XVATTR + */ + smb_sa_to_va_mask(ret_attr->sa_mask, + &ret_attr->sa_vattr.va_mask); - if (ret_attr->sa_vattr.va_type == VDIR) - ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; + error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, + flags, cr, &smb_ct); + if (error != 0) + return (error); - return (error); + ret_attr->sa_dosattr = 0; + ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; } - /* - * Support for file systems without VFSFT_XVATTR - */ - smb_sa_to_va_mask(ret_attr->sa_mask, - &ret_attr->sa_vattr.va_mask); - - error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); - if (error != 0) - return (error); - - ret_attr->sa_dosattr = 0; - ret_attr->sa_crtime = ret_attr->sa_vattr.va_mtime; - if (unnamed_vp) { ret_attr->sa_vattr.va_type = VREG; @@ -676,7 +636,7 @@ smb_vop_commit(vnode_t *vp, cred_t *cr) return (VOP_FSYNC(vp, 1, cr, &smb_ct)); } -void +static void smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) { xoptattr_t *xoap = NULL; @@ -753,116 +713,27 @@ smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) } } - /* * smb_vop_readdir() * - * Upon return, the "name" field will contain either the on-disk name or, if - * it needs mangling or has a case-insensitive collision, the mangled - * "shortname." - * - * vpp is an optional parameter. If non-NULL, it will contain a pointer to - * the vnode for the name that is looked up (the vnode will be returned held). - * - * od_name is an optional parameter (NULL can be passed if the on-disk name - * is not needed by the caller). - */ - -int -smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, - ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr) -{ - int num_bytes; - int error = 0; - char *dirbuf = NULL; - - ASSERT(dvp); - ASSERT(cookiep); - ASSERT(name); - ASSERT(namelen); - ASSERT(inop); - ASSERT(cr); - - if (dvp->v_type != VDIR) { - *namelen = 0; - return (ENOTDIR); - } - - if (vpp) - *vpp = NULL; - - dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); - num_bytes = SMB_MINLEN_RDDIR_BUF; - - /* - * The goal is to retrieve the first valid entry from *cookiep - * forward. smb_vop_readdir_readpage() collects an - * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. - * smb_vop_readdir_entry() attempts to find the first valid entry - * in that page. - */ - - while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, - &num_bytes, cr)) == 0) { - - if (num_bytes <= 0) - break; - - name[0] = '\0'; - - error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, - inop, vpp, od_name, flags, cr, dirbuf, num_bytes); - - if (error) - break; - - if (*name) - break; - - bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); - num_bytes = SMB_MINLEN_RDDIR_BUF; - } - - - if (error) { - kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); - *namelen = 0; - return (error); - } - - if (num_bytes == 0) { /* EOF */ - kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); - *cookiep = SMB_EOF; - *namelen = 0; - return (0); - } - - kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); - return (0); -} - -/* - * smb_vop_readdir_readpage() - * - * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The - * directory entries are returned in an fs-independent format by the + * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. + * The directory entries are returned in an fs-independent format by the * underlying file system. That is, the "page" of information returned is - * not literally stored on-disk in the format returned.) - * - * Much of the following is borrowed from getdents64() + * not literally stored on-disk in the format returned. + * If the file system supports extended directory entries (has features + * VFSFT_DIRENTFLAGS), set V_RDDIR_ENTFLAGS to cause the buffer to be + * filled with edirent_t structures, instead of dirent64_t structures. * - * MAXGETDENTS_SIZE is defined in getdents.c + * Some file systems can have directories larger than SMB_MAXDIRSIZE. + * After VOP_READDIR, if offset is larger than SMB_MAXDIRSIZE treat as EOF. */ - -#define MAXGETDENTS_SIZE (64 * 1024) - -static int -smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, - cred_t *cr) +int +smb_vop_readdir(vnode_t *vp, uint32_t offset, + void *buf, int *count, int *eof, cred_t *cr) { int error = 0; int rdirent_flags = 0; - int sink; + int rdirent_size; struct uio auio; struct iovec aiov; @@ -870,22 +741,14 @@ smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, return (ENOTDIR); if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) { - /* - * Setting V_RDDIR_ENTFLAGS will cause the buffer to - * be filled with edirent_t structures (instead of - * dirent64_t structures). - */ rdirent_flags = V_RDDIR_ENTFLAGS; - - if (*count < sizeof (edirent_t)) - return (EINVAL); + rdirent_size = sizeof (edirent_t); } else { - if (*count < sizeof (dirent64_t)) - return (EINVAL); + rdirent_size = sizeof (dirent64_t); } - if (*count > MAXGETDENTS_SIZE) - *count = MAXGETDENTS_SIZE; + if (*count < rdirent_size) + return (EINVAL); aiov.iov_base = buf; aiov.iov_len = *count; @@ -897,183 +760,14 @@ smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, auio.uio_fmode = 0; (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); - error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags); + error = VOP_READDIR(vp, &auio, cr, eof, &smb_ct, rdirent_flags); VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); - if (error) { - if (error == ENOENT) { - /* Fake EOF if offset is bad due to dropping of lock */ - *count = 0; - return (0); - } else { - return (error); - } - } - - /* - * Windows cannot handle an offset > SMB_EOF. - * Pretend we are at EOF. - */ - - if (auio.uio_loffset > SMB_EOF) { - *count = 0; - return (0); - } - - *count = *count - auio.uio_resid; - return (0); -} - -/* - * smb_vop_readdir_entry() - * - * This function retrieves the first valid entry from the - * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() - * to smb_vop_readdir(). - * - * Both dirent64_t and edirent_t structures need to be handled. The former is - * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter - * is required for proper handling of case collisions on file systems that - * support case-insensitivity. edirent_t structures are also used for - * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. - */ - -static int -smb_vop_readdir_entry( - vnode_t *dvp, - uint32_t *cookiep, - char *name, - int *namelen, - ino64_t *inop, - vnode_t **vpp, - char *od_name, - int flags, - cred_t *cr, - char *dirbuf, - int num_bytes) -{ - uint32_t next_cookie; - int ebufsize; - int error = 0; - int len; - int rc; - char shortname[SMB_SHORTNAMELEN]; - char name83[SMB_SHORTNAMELEN]; - char *ebuf = NULL; - edirent_t *edp; - dirent64_t *dp = NULL; - vnode_t *vp = NULL; - - ASSERT(dirbuf); - - /* - * Use edirent_t structure for both - */ - if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - edp = (edirent_t *)dirbuf; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - dp = (dirent64_t *)dirbuf; - ebufsize = EDIRENT_RECLEN(MAXNAMELEN); - ebuf = kmem_zalloc(ebufsize, KM_SLEEP); - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - edp = (edirent_t *)ebuf; - } - - while (edp) { - if (dp) - DP_TO_EDP(dp, edp); - - next_cookie = (uint32_t)edp->ed_off; - if (edp->ed_ino == 0) { - *cookiep = next_cookie; - - if (dp) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - DP_ADVANCE(dp, dirbuf, num_bytes); - if (dp == NULL) - edp = NULL; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - EDP_ADVANCE(edp, dirbuf, num_bytes); - } - continue; - } - - len = strlen(edp->ed_name); - - if (*namelen < len) { - *namelen = 0; + if (auio.uio_loffset > SMB_MAXDIRSIZE) + *eof = 1; - if (ebuf) - kmem_free(ebuf, ebufsize); - - return (EOVERFLOW); - } - - /* - * Do not pass SMB_IGNORE_CASE to smb_vop_lookup - */ - - error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, - od_name, 0, NULL, cr); - - if (error) { - if (error == ENOENT) { - *cookiep = (uint32_t)next_cookie; - - if (dp) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - DP_ADVANCE(dp, dirbuf, num_bytes); - if (dp == NULL) - edp = NULL; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - EDP_ADVANCE(edp, dirbuf, num_bytes); - } - continue; - } - - - *namelen = 0; - - if (ebuf) - kmem_free(ebuf, ebufsize); - - return (error); - } - - if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { - rc = smb_mangle_name(edp->ed_ino, edp->ed_name, - shortname, name83, 1); - - if (rc == 1) { /* success */ - (void) strlcpy(name, shortname, *namelen + 1); - *namelen = strlen(shortname); - } else { - (void) strlcpy(name, edp->ed_name, - *namelen + 1); - name[*namelen] = '\0'; - } - - } else { - (void) strlcpy(name, edp->ed_name, *namelen + 1); - *namelen = len; - } - - if (vpp == NULL) - VN_RELE(vp); - - if (inop) - *inop = edp->ed_ino; - - *cookiep = (uint32_t)next_cookie; - break; - } - - if (ebuf) - kmem_free(ebuf, ebufsize); + if (error == 0) + *count = *count - auio.uio_resid; return (error); } @@ -1102,266 +796,6 @@ smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) } /* - * smb_vop_getdents() - * - * Upon success, the smb_node corresponding to each entry returned will - * have a reference taken on it. These will be released in - * smb_trans2_find_get_dents(). - * - * If an error is returned from this routine, a list of already processed - * entries will be returned. The smb_nodes corresponding to these entries - * will be referenced, and will be released in smb_trans2_find_get_dents(). - * - * The returned dp->d_name field will contain either the on-disk name or, if - * it needs mangling or has a case-insensitive collision, the mangled - * "shortname." In this case, the on-disk name can be retrieved from the - * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). - */ - -int /*ARGSUSED*/ -smb_vop_getdents( - smb_node_t *dir_snode, - uint32_t *cookiep, - uint64_t *verifierp, - int32_t *dircountp, - char *arg, - char *pattern, - uint32_t flags, - smb_request_t *sr, - cred_t *cr) -{ - int error = 0; - int maxentries; - int num_bytes; - int resid; - char *dirbuf = NULL; - vnode_t *dvp; - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; - - dvp = dir_snode->vp; - - resid = ihdr->uio.uio_resid; - maxentries = resid / SMB_MAX_DENT_INFO_SIZE; - - bzero(ihdr->iov->iov_base, resid); - - dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); - - while (maxentries) { - - bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); - - num_bytes = SMB_MINLEN_RDDIR_BUF; - error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, - &num_bytes, cr); - - if (error || (num_bytes <= 0)) - break; - - error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, - arg, flags, sr, cr, dirbuf, &maxentries, num_bytes, - pattern); - - if (error) - goto out; - } - - if (num_bytes < 0) { - error = -1; - } else if (num_bytes == 0) { - *cookiep = SMB_EOF; - error = 0; - } else { - error = 0; - } - -out: - if (dirbuf) - kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); - - return (error); -} - -/* - * smb_vop_getdents_entries() - * - * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer - * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). - * - * Both dirent64_t and edirent_t structures need to be handled. The former is - * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter - * is required for properly handling case collisions on file systems that - * support case-insensitivity. edirent_t is also used on case-sensitive - * file systems where VFSFT_DIRENTFLAGS is available. - */ - -static int -smb_vop_getdents_entries( - smb_node_t *dir_snode, - uint32_t *cookiep, - int32_t *dircountp, - char *arg, - uint32_t flags, - smb_request_t *sr, - cred_t *cr, - char *dirbuf, - int *maxentries, - int num_bytes, - char *pattern) -{ - uint32_t next_cookie; - int ebufsize; - char *tmp_name; - int rc; - char shortname[SMB_SHORTNAMELEN]; - char name83[SMB_SHORTNAMELEN]; - char *ebuf = NULL; - dirent64_t *dp = NULL; - edirent_t *edp; - smb_node_t *ret_snode; - smb_attr_t ret_attr; - vnode_t *dvp; - vnode_t *fvp; - - ASSERT(dirbuf); - - dvp = dir_snode->vp; - - if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - edp = (edirent_t *)dirbuf; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - dp = (dirent64_t *)dirbuf; - ebufsize = EDIRENT_RECLEN(MAXNAMELEN); - ebuf = kmem_zalloc(ebufsize, KM_SLEEP); - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - edp = (edirent_t *)ebuf; - } - - while (edp) { - if (dp) - DP_TO_EDP(dp, edp); - - if (*maxentries == 0) - break; - - next_cookie = (uint32_t)edp->ed_off; - - if (edp->ed_ino == 0) { - *cookiep = next_cookie; - if (dp) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - DP_ADVANCE(dp, dirbuf, num_bytes); - if (dp == NULL) - edp = NULL; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - EDP_ADVANCE(edp, dirbuf, num_bytes); - } - continue; - } - - rc = smb_vop_lookup(dvp, edp->ed_name, &fvp, - NULL, 0, NULL, cr); - - if (rc) { - if (rc == ENOENT) { - *cookiep = next_cookie; - if (dp) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - DP_ADVANCE(dp, dirbuf, - num_bytes); - if (dp == NULL) - edp = NULL; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - EDP_ADVANCE(edp, dirbuf, - num_bytes); - } - continue; - } - if (ebuf) - kmem_free(ebuf, ebufsize); - - return (rc); - } - - ret_snode = smb_node_lookup(sr, NULL, cr, fvp, - edp->ed_name, dir_snode, NULL, &ret_attr); - - if (ret_snode == NULL) { - VN_RELE(fvp); - - if (ebuf) - kmem_free(ebuf, ebufsize); - - return (ENOMEM); - } - - if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, - name83, pattern, (flags & SMB_IGNORE_CASE))) { - - tmp_name = edp->ed_name; - - if ((flags & SMB_IGNORE_CASE) && - ED_CASE_CONFLICTS(edp)) { - rc = smb_mangle_name(edp->ed_ino, edp->ed_name, - shortname, name83, 1); - if (rc == 1) - tmp_name = shortname; - } else { - rc = smb_mangle_name(edp->ed_ino, edp->ed_name, - shortname, name83, 0); - } - - if (rc != 1) { - (void) strlcpy(shortname, edp->ed_name, - SMB_SHORTNAMELEN); - (void) strlcpy(name83, edp->ed_name, - SMB_SHORTNAMELEN); - shortname[SMB_SHORTNAMELEN - 1] = '\0'; - name83[SMB_SHORTNAMELEN - 1] = '\0'; - } - - rc = smb_gather_dents_info(arg, edp->ed_ino, - strlen(tmp_name), tmp_name, next_cookie, dircountp, - &ret_attr, ret_snode, shortname, name83); - - if (rc < 0) { - if (ebuf) - kmem_free(ebuf, ebufsize); - *maxentries = 0; - return (0); - } - - if (rc > 0) - (*maxentries)--; - } else { - smb_node_release(ret_snode); - } - - *cookiep = next_cookie; - - if (dp) { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - DP_ADVANCE(dp, dirbuf, num_bytes); - if (dp == NULL) - edp = NULL; - } else { - /*LINTED E_BAD_PTR_CAST_ALIGN*/ - EDP_ADVANCE(edp, dirbuf, num_bytes); - } - } - - if (ebuf) - kmem_free(ebuf, ebufsize); - - return (0); -} - -/* * smb_vop_stream_lookup() * * The name returned in od_name is the on-disk name of the stream with the @@ -1472,80 +906,6 @@ smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) return (error); } -/* - * smb_vop_stream_readdir() - * - * Note: stream_info.size is not filled in in this routine. - * It needs to be filled in by the caller due to the parameters for getattr. - * - * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX - * removed. - */ - -int -smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, - struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, - int flags, cred_t *cr) -{ - int nsize; - int error = 0; - ino64_t ino; - char *tmp_name; - vnode_t *xattrdirvp; - vnode_t *vp; - - if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, - cr)) != 0) - return (error); - - bzero(stream_info->name, sizeof (stream_info->name)); - stream_info->size = 0; - - tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); - - for (;;) { - nsize = MAXNAMELEN-1; - error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, - &ino, &vp, NULL, flags, cr); - - if (error || (*cookiep == SMB_EOF)) - break; - - if (strncmp(tmp_name, SMB_STREAM_PREFIX, - SMB_STREAM_PREFIX_LEN)) { - VN_RELE(vp); - continue; - } - - tmp_name[nsize] = '\0'; - (void) strlcpy(stream_info->name, - &(tmp_name[SMB_STREAM_PREFIX_LEN]), - sizeof (stream_info->name)); - - nsize -= SMB_STREAM_PREFIX_LEN; - break; - } - - if ((error == 0) && nsize) { - if (vpp) - *vpp = vp; - else - VN_RELE(vp); - - if (xattrdirvpp) - *xattrdirvpp = xattrdirvp; - else - VN_RELE(xattrdirvp); - - } else { - VN_RELE(xattrdirvp); - } - - kmem_free(tmp_name, MAXNAMELEN); - - return (error); -} - int smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, cred_t *cr) diff --git a/usr/src/uts/common/fs/smbsrv/smb_vss.c b/usr/src/uts/common/fs/smbsrv/smb_vss.c index 4ae695a251..444e8e8c77 100644 --- a/usr/src/uts/common/fs/smbsrv/smb_vss.c +++ b/usr/src/uts/common/fs/smbsrv/smb_vss.c @@ -201,12 +201,19 @@ smb_vss_lookup_nodes(smb_request_t *sr, smb_node_t *root_node, /* note the value of cur_node->vp */ err = vnodetopath(fsrootvp, cur_node->vp, nodepath, MAXPATHLEN, kcred); - - if (err != 0) + if (err != 0) { + VN_RELE(vp); goto error; + } *vss_root_node = smb_node_lookup(sr, NULL, kcred, vp, gmttoken, cur_node, NULL, &attr); + VN_RELE(vp); + + if (*vss_root_node == NULL) { + err = ENOENT; + goto error; + } (void) snprintf(rootpath, MAXPATHLEN, ".zfs/snapshot/%s/%s", snapname, nodepath); @@ -217,6 +224,8 @@ smb_vss_lookup_nodes(smb_request_t *sr, smb_node_t *root_node, if (vp) { *vss_cur_node = smb_node_lookup(sr, NULL, kcred, vp, gmttoken, cur_node, NULL, &attr); + VN_RELE(vp); + if (*vss_cur_node != NULL) { smb_vss_remove_first_token_from_path(buf); } else { diff --git a/usr/src/uts/common/smbsrv/Makefile b/usr/src/uts/common/smbsrv/Makefile index a6ee5b3d69..07e63dfa7e 100644 --- a/usr/src/uts/common/smbsrv/Makefile +++ b/usr/src/uts/common/smbsrv/Makefile @@ -19,10 +19,8 @@ # CDDL HEADER END # # -# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. -# -# ident "@(#)Makefile 1.6 08/08/07 SMI" include ../../../Makefile.master @@ -66,6 +64,7 @@ HDRS= alloc.h \ smb_i18n.h \ smb_idmap.h \ smb_incl.h \ + smb_inet.h \ smb_ioctl.h \ smb_kproto.h \ smb_kstat.h \ @@ -77,7 +76,6 @@ HDRS= alloc.h \ smb_xdr.h \ smbfmt.h \ smbinfo.h \ - smbtrans.h \ string.h \ svrapi.h \ winioctl.h \ diff --git a/usr/src/uts/common/smbsrv/cifs.h b/usr/src/uts/common/smbsrv/cifs.h index d038389c60..257d7bcea1 100644 --- a/usr/src/uts/common/smbsrv/cifs.h +++ b/usr/src/uts/common/smbsrv/cifs.h @@ -538,7 +538,7 @@ extern "C" { /* * Flags for TRANS2_FIND_FIRST2 and TRANS2_FIND_NEXT2 - * (NTDDK cifs.h and smbtrans.h). + * (NTDDK cifs.h). * * If SMB_FIND_RETURN_RESUME_KEYS was set in the request parameters, * each entry is preceded by a four-byte resume key. diff --git a/usr/src/uts/common/smbsrv/netrauth.h b/usr/src/uts/common/smbsrv/netrauth.h index fc5a549c9b..43477ca7b2 100644 --- a/usr/src/uts/common/smbsrv/netrauth.h +++ b/usr/src/uts/common/smbsrv/netrauth.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -35,6 +35,8 @@ #include <sys/types.h> #include <smbsrv/wintypes.h> #include <smbsrv/netbios.h> +#include <smbsrv/smb_xdr.h> +#include <smbsrv/smbinfo.h> #ifndef _KERNEL #include <syslog.h> @@ -111,24 +113,14 @@ typedef struct netr_info { time_t timestamp; } netr_info_t; -/* - * netr_client_t flags - * - * NETR_CFLG_ANON Anonymous connection - * NETR_CFLG_LOCAL Local user - * NETR_CFLG_DOMAIN Domain user - */ -#define NETR_CFLG_ANON 0x01 -#define NETR_CFLG_LOCAL 0x02 -#define NETR_CFLG_DOMAIN 0x04 - - typedef struct netr_client { uint16_t logon_level; char *username; char *domain; + char *real_username; + char *real_domain; char *workstation; - uint32_t ipaddr; + smb_inaddr_t ipaddr; struct { uint32_t challenge_key_len; uint8_t *challenge_key_val; @@ -144,9 +136,8 @@ typedef struct netr_client { uint32_t logon_id; int native_os; int native_lm; - uint32_t local_ipaddr; + smb_inaddr_t local_ipaddr; uint16_t local_port; - uint32_t flags; } netr_client_t; diff --git a/usr/src/uts/common/smbsrv/smb_door_svc.h b/usr/src/uts/common/smbsrv/smb_door_svc.h index 3b0facaa0f..ce19ff2a68 100644 --- a/usr/src/uts/common/smbsrv/smb_door_svc.h +++ b/usr/src/uts/common/smbsrv/smb_door_svc.h @@ -150,14 +150,14 @@ void smb_kdoor_clnt_free(char *, size_t, char *, size_t); /* * SMB upcalls */ -smb_token_t *smb_upcall_get_token(netr_client_t *); +smb_token_t *smb_get_token(netr_client_t *); int smb_set_downcall_desc(door_desc_t *, uint_t); void smb_user_nonauth_logon(uint32_t); void smb_user_auth_logoff(uint32_t); uint32_t smb_upcall_vss_get_count(char *); -void smb_upcall_vss_get_snapshots(char *resource_path, uint32_t count, - smb_dr_return_gmttokens_t *gmttokens); -void smb_upcall_vss_get_snapshots_free(smb_dr_return_gmttokens_t *reply); +void smb_upcall_vss_get_snapshots(char *, uint32_t, + smb_dr_return_gmttokens_t *); +void smb_upcall_vss_get_snapshots_free(smb_dr_return_gmttokens_t *); void smb_upcall_vss_map_gmttoken(char *, char *, char *); #else /* _KERNEL */ diff --git a/usr/src/uts/common/smbsrv/smb_fsops.h b/usr/src/uts/common/smbsrv/smb_fsops.h index b3fefcb615..e8ba57bedb 100644 --- a/usr/src/uts/common/smbsrv/smb_fsops.h +++ b/usr/src/uts/common/smbsrv/smb_fsops.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SMBSRV_SMB_FSOPS_H #define _SMBSRV_SMB_FSOPS_H -#pragma ident "@(#)smb_fsops.h 1.8 08/07/15 SMI" - /* * This header file contains all the functions for the interface between * the smb layer and the fs layer. @@ -68,15 +66,6 @@ int smb_fsop_rmdir(struct smb_request *sr, cred_t *cr, smb_node_t *dir_snode, int smb_fsop_getattr(struct smb_request *sr, cred_t *cr, smb_node_t *snode, smb_attr_t *attr); -int smb_fsop_readdir(struct smb_request *sr, cred_t *cr, smb_node_t *snode, - uint32_t *cookie, char *name, int *namelen, ino64_t *fileid, - struct fs_stream_info *stream_info, smb_node_t **ret_snode, - smb_attr_t *ret_attr); - -int smb_fsop_getdents(struct smb_request *sr, cred_t *cr, - struct smb_node *dir_snode, uint32_t *cookie, uint64_t *verifierp, - int32_t *maxcnt, char *args, char *pattern); - int smb_maybe_mangled_name(char *name); int smb_fsop_rename(struct smb_request *sr, cred_t *cr, @@ -115,10 +104,6 @@ int smb_fsop_lookup(struct smb_request *sr, cred_t *cr, int flags, int smb_fsop_commit(smb_request_t *sr, cred_t *cr, struct smb_node *snode); -int smb_fsop_stream_readdir(struct smb_request *sr, cred_t *cr, - smb_node_t *fnode, uint32_t *cookiep, struct fs_stream_info *stream_info, - smb_node_t **ret_snode, smb_attr_t *ret_attr); - int smb_fsop_aclread(smb_request_t *, cred_t *, smb_node_t *, smb_fssd_t *); int smb_fsop_aclwrite(smb_request_t *, cred_t *, smb_node_t *, smb_fssd_t *); acl_type_t smb_fsop_acltype(smb_node_t *); diff --git a/usr/src/uts/common/smbsrv/smb_inet.h b/usr/src/uts/common/smbsrv/smb_inet.h new file mode 100644 index 0000000000..2ae07bf520 --- /dev/null +++ b/usr/src/uts/common/smbsrv/smb_inet.h @@ -0,0 +1,71 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * This file was originally generated using rpcgen. + */ + +#ifndef _SMB_INET_H +#define _SMB_INET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _KERNEL +#include <inet/tcp.h> +#include <arpa/inet.h> +#endif /* !_KERNEL */ +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +typedef struct smb_inaddr { + union { + in_addr_t au_ipv4; + in6_addr_t au_ipv6; + in6_addr_t au_ip; + } au_addr; + int a_family; +} smb_inaddr_t; + +#define a_ipv4 au_addr.au_ipv4 +#define a_ipv6 au_addr.au_ipv6 +#define a_ip au_addr.au_ip + +#define SMB_IPSTRLEN(family) \ +((family == AF_INET) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN) + +#define SMB_INET_NOMASK 0xffffffff + +boolean_t smb_inet_equal(smb_inaddr_t *, smb_inaddr_t *, uint32_t); +boolean_t smb_inet_iszero(smb_inaddr_t *); +const char *smb_inet_ntop(smb_inaddr_t *, char *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _SMB_INET_H */ diff --git a/usr/src/uts/common/smbsrv/smb_kproto.h b/usr/src/uts/common/smbsrv/smb_kproto.h index f32dad05de..101c686b26 100644 --- a/usr/src/uts/common/smbsrv/smb_kproto.h +++ b/usr/src/uts/common/smbsrv/smb_kproto.h @@ -208,7 +208,7 @@ boolean_t smb_oplock_conflict(struct smb_node *, struct smb_session *, #define SMB_SAME_SESSION(sess1, sess2) \ ((sess1) && (sess2) && \ - ((sess1)->ipaddr == (sess2)->ipaddr) && \ + (smb_inet_equal(&sess1->ipaddr, &sess2->ipaddr, 0)) && \ ((sess1)->s_kid == (sess2)->s_kid)) \ #define SMB_ATTR_ONLY_OPEN(op) \ @@ -248,10 +248,6 @@ int smb_ascii_or_unicode_strlen_null(struct smb_request *, char *); int smb_ascii_or_unicode_null_len(struct smb_request *); int smb_search(struct smb_request *); -void smb_rdir_close(struct smb_request *); -int smb_rdir_open(struct smb_request *, char *, unsigned short); -int smb_rdir_next(smb_request_t *sr, smb_node_t **rnode, - smb_odir_context_t *pc); uint32_t smb_common_open(smb_request_t *); DWORD smb_validate_object_name(char *path, unsigned int ftype); @@ -295,10 +291,7 @@ int smb_xlate_dialect_str_to_cd(char *); char *smb_xlate_com_cd_to_str(int); char *smb_xlate_dialect_cd_to_str(int); -void smb_od_destruct(struct smb_session *, struct smb_odir *); int smbd_fs_query(smb_request_t *, smb_fqi_t *, int); -int smb_component_match(struct smb_request *sr, ino64_t fileid, - struct smb_odir *od, smb_odir_context_t *pc); int smb_lock_range_access(struct smb_request *, struct smb_node *, uint64_t, uint64_t, boolean_t); @@ -481,14 +474,14 @@ int smb_sign_check_secondary(struct smb_request *req, unsigned int seqnum); void smb_sign_reply(struct smb_request *req, struct mbuf_chain *reply); -boolean_t smb_sattr_check(smb_attr_t *, char *, unsigned short); +boolean_t smb_sattr_check(uint16_t, uint16_t, char *); void smb_request_cancel(smb_request_t *sr); /* * session functions (file smb_session.c) */ -smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *); +smb_session_t *smb_session_create(ksocket_t, uint16_t, smb_server_t *, int); int smb_session_daemon(smb_session_list_t *); void smb_session_reconnection_check(smb_session_list_t *, smb_session_t *); void smb_session_timers(smb_session_list_t *); @@ -539,13 +532,21 @@ cred_t *smb_ofile_getcred(smb_ofile_t *); /* * odir functions (file smb_odir.c) */ -smb_odir_t *smb_odir_open(smb_tree_t *tree, smb_node_t *node, char *pattern, - uint16_t pid, unsigned short sattr); -void smb_odir_close(smb_odir_t *od); -void smb_odir_close_all(smb_tree_t *tree); -void smb_odir_close_all_by_pid(smb_tree_t *tree, uint16_t pid); -void smb_odir_release(smb_odir_t *od); -smb_odir_t *smb_odir_lookup_by_sid(smb_tree_t *tree, uint16_t sid); +uint16_t smb_odir_open(smb_request_t *, char *, uint16_t); +uint16_t smb_odir_openat(smb_request_t *, smb_node_t *); +void smb_odir_close(smb_odir_t *); +boolean_t smb_odir_hold(smb_odir_t *); +void smb_odir_release(smb_odir_t *); + +int smb_odir_read(smb_request_t *, smb_odir_t *, + smb_odirent_t *, boolean_t *); +int smb_odir_read_fileinfo(smb_request_t *, smb_odir_t *, + smb_fileinfo_t *, boolean_t *); +int smb_odir_read_streaminfo(smb_request_t *, smb_odir_t *, + smb_streaminfo_t *, boolean_t *); + +void smb_odir_save_cookie(smb_odir_t *, int, uint32_t cookie); +void smb_odir_resume_at(smb_odir_t *, smb_odir_resume_t *); /* * SMB user functions (file smb_user.c) @@ -579,8 +580,8 @@ void smb_tree_close_pid(smb_tree_t *, uint16_t); boolean_t smb_tree_has_feature(smb_tree_t *, uint_t); boolean_t smb_tree_hold(smb_tree_t *); void smb_tree_release(smb_tree_t *); - void smb_dr_ulist_free(smb_dr_ulist_t *ulist); +smb_odir_t *smb_tree_lookup_odir(smb_tree_t *, uint16_t); /* * SMB user's credential functions @@ -625,7 +626,7 @@ size_t oemstounicodes(mts_wchar_t *unicodestring, const char *oemstring, int uioxfer(struct uio *src_uio, struct uio *dst_uio, int n); -int smb_match_name(ino64_t, char *, char *, char *, char *, boolean_t); +int smb_match_name(ino64_t, char *, char *, boolean_t); boolean_t smb_is_dot_or_dotdot(const char *); int token2buf(smb_token_t *token, char *buf); diff --git a/usr/src/uts/common/smbsrv/smb_ktypes.h b/usr/src/uts/common/smbsrv/smb_ktypes.h index 918746a701..7dac2b250c 100644 --- a/usr/src/uts/common/smbsrv/smb_ktypes.h +++ b/usr/src/uts/common/smbsrv/smb_ktypes.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -50,6 +50,7 @@ extern "C" { #include <sys/ksocket.h> #include <sys/fem.h> #include <sys/door.h> +#include <sys/extdirent.h> #include <smbsrv/smb.h> #include <smbsrv/smbinfo.h> #include <smbsrv/mbuf.h> @@ -75,9 +76,15 @@ int smb_noop(void *, size_t, int); */ #define SMB_MAX_SEARCH 10 +#define SMB_SEARCH_ATTRIBUTES \ + (FILE_ATTRIBUTE_HIDDEN | \ + FILE_ATTRIBUTE_SYSTEM | \ + FILE_ATTRIBUTE_DIRECTORY) + #define SMB_SEARCH_HIDDEN(sattr) ((sattr) & FILE_ATTRIBUTE_HIDDEN) #define SMB_SEARCH_SYSTEM(sattr) ((sattr) & FILE_ATTRIBUTE_SYSTEM) #define SMB_SEARCH_DIRECTORY(sattr) ((sattr) & FILE_ATTRIBUTE_DIRECTORY) +#define SMB_SEARCH_ALL(sattr) ((sattr) & SMB_SEARCH_ATTRIBUTES) extern uint32_t smb_audit_flags; @@ -401,7 +408,7 @@ int MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC, typedef struct smb_oplock { struct smb_ofile *op_ofile; uint32_t op_flags; - uint32_t op_ipaddr; + smb_inaddr_t op_ipaddr; uint64_t op_kid; } smb_oplock_t; @@ -677,8 +684,8 @@ typedef struct smb_session { uint64_t opentime; uint16_t vcnumber; uint16_t s_local_port; - uint32_t ipaddr; - uint32_t local_ipaddr; + smb_inaddr_t ipaddr; + smb_inaddr_t local_ipaddr; char workstation[SMB_PI_MAX_HOST]; int dialect; int native_os; @@ -801,7 +808,7 @@ typedef struct smb_tree { smb_idpool_t t_fid_pool; smb_llist_t t_odir_list; - smb_idpool_t t_sid_pool; + smb_idpool_t t_odid_pool; uint32_t t_refcnt; uint32_t t_flags; @@ -955,12 +962,8 @@ typedef struct smb_ofile { pid_t f_pid; } smb_ofile_t; -/* odir flags bits */ -#define SMB_DIR_FLAG_OPEN 0x0001 -#define SMB_DIR_FLAG_CLOSE 0x0002 -#define SMB_DIR_CLOSED(dir) ((dir)->d_flags & SMB_DIR_FLAG_CLOSE) - -#define SMB_ODIR_MAGIC 0x4F444952 /* 'ODIR' */ +#define SMB_ODIR_MAGIC 0x4F444952 /* 'ODIR' */ +#define SMB_ODIR_BUFSIZE (8 * 1024) typedef enum { SMB_ODIR_STATE_OPEN = 0, @@ -969,35 +972,78 @@ typedef enum { SMB_ODIR_STATE_SENTINEL } smb_odir_state_t; +typedef enum { + SMB_ODIR_RESUME_IDX, + SMB_ODIR_RESUME_COOKIE, + SMB_ODIR_RESUME_FNAME +} smb_odir_resume_type_t; + +typedef struct smb_odir_resume { + smb_odir_resume_type_t or_type; + int or_idx; + uint32_t or_cookie; + char *or_fname; +} smb_odir_resume_t; + typedef struct smb_odir { uint32_t d_magic; kmutex_t d_mutex; list_node_t d_lnd; smb_odir_state_t d_state; - smb_session_t *d_session; smb_user_t *d_user; smb_tree_t *d_tree; - - uint32_t d_refcnt; - uint32_t d_cookie; - uint32_t d_cookies[SMB_MAX_SEARCH]; - uint16_t d_sid; + smb_node_t *d_dnode; + uint16_t d_odid; uint16_t d_opened_by_pid; uint16_t d_sattr; + uint32_t d_refcnt; + + boolean_t d_wildcards; + boolean_t d_ignore_case; + boolean_t d_xat; + boolean_t d_eof; + boolean_t d_is_edp; + int d_bufsize; + uint64_t d_offset; + union { + char *u_bufptr; + edirent_t *u_edp; + dirent64_t *u_dp; + } d_u; + uint32_t d_cookies[SMB_MAX_SEARCH]; char d_pattern[MAXNAMELEN]; - struct smb_node *d_dir_snode; - unsigned int d_wildcards; + char d_buf[SMB_ODIR_BUFSIZE]; } smb_odir_t; - -typedef struct smb_odir_context { - uint32_t dc_cookie; - uint16_t dc_dattr; - char dc_name[MAXNAMELEN]; /* Real 'Xxxx.yyy.xx' */ - char dc_name83[SMB_SHORTNAMELEN]; /* w/ dot 'XXXX .XX ' */ - char dc_shortname[SMB_SHORTNAMELEN]; /* w/ dot 'XXXX.XX' */ - smb_attr_t dc_attr; -} smb_odir_context_t; +#define d_bufptr d_u.u_bufptr +#define d_edp d_u.u_edp +#define d_dp d_u.u_dp + +typedef struct smb_odirent { + char od_name[MAXNAMELEN]; /* on disk name */ + ino64_t od_ino; + uint32_t od_eflags; +} smb_odirent_t; + +typedef struct smb_fileinfo { + char fi_name[MAXNAMELEN]; + char fi_name83[SMB_SHORTNAMELEN]; + char fi_shortname[SMB_SHORTNAMELEN]; + uint32_t fi_cookie; + uint32_t fi_dosattr; /* DOS attributes */ + uint64_t fi_nodeid; /* file system node id */ + uint64_t fi_size; /* file size in bytes */ + uint64_t fi_alloc_size; /* allocation size in bytes */ + timestruc_t fi_atime; /* last access */ + timestruc_t fi_mtime; /* last modification */ + timestruc_t fi_ctime; /* last status change */ + timestruc_t fi_crtime; /* file creation */ +} smb_fileinfo_t; + +typedef struct smb_streaminfo { + uint64_t si_size; + char si_name[MAXPATHLEN]; +} smb_streaminfo_t; #define SMB_LOCK_MAGIC 0x4C4F434B /* 'LOCK' */ @@ -1295,14 +1341,12 @@ typedef struct smb_request { struct mbuf_chain smb_data; uint16_t smb_fid; /* not in hdr, but common */ - uint16_t smb_sid; /* not in hdr, but common */ unsigned char andx_com; uint16_t andx_off; struct smb_tree *tid_tree; struct smb_ofile *fid_ofile; - struct smb_odir *sid_odir; smb_user_t *uid_user; union { @@ -1457,6 +1501,7 @@ typedef struct { kt_did_t ld_ktdid; ksocket_t ld_so; struct sockaddr_in ld_sin; + struct sockaddr_in6 ld_sin6; smb_session_list_t ld_session_list; } smb_listener_daemon_t; diff --git a/usr/src/uts/common/smbsrv/smb_privilege.h b/usr/src/uts/common/smbsrv/smb_privilege.h index 9fad667938..8a6504a6f1 100644 --- a/usr/src/uts/common/smbsrv/smb_privilege.h +++ b/usr/src/uts/common/smbsrv/smb_privilege.h @@ -19,17 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SMB_PRIVILEGE_H #define _SMB_PRIVILEGE_H -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <smbsrv/smb_xdr.h> - #ifdef __cplusplus extern "C" { #endif @@ -188,11 +184,6 @@ void smb_privset_enable(smb_privset_t *privset, uint32_t id); int smb_privset_query(smb_privset_t *privset, uint32_t id); void smb_privset_log(smb_privset_t *privset); -/* XDR routines */ -extern bool_t xdr_smb_luid_t(); -extern bool_t xdr_smb_luid_attrs_t(); -extern bool_t xdr_smb_privset_t(); - #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/smbsrv/smb_share.h b/usr/src/uts/common/smbsrv/smb_share.h index 52a71fc3f5..aabeda1f81 100644 --- a/usr/src/uts/common/smbsrv/smb_share.h +++ b/usr/src/uts/common/smbsrv/smb_share.h @@ -211,7 +211,7 @@ uint32_t smb_shr_rename(char *, char *); uint32_t smb_shr_get(char *, smb_share_t *); uint32_t smb_shr_modify(smb_share_t *); uint32_t smb_shr_get_realpath(const char *, char *, int); -void smb_shr_hostaccess(smb_share_t *, ipaddr_t); +void smb_shr_hostaccess(smb_share_t *, smb_inaddr_t *); boolean_t smb_shr_exists(char *); int smb_shr_is_special(char *); @@ -228,7 +228,6 @@ void smb_shr_sa_csc_option(const char *, smb_share_t *); */ uint32_t smb_share_list(int, smb_shrlist_t *); int smb_share_count(void); -uint32_t smb_share_get(char *, smb_share_t *); uint32_t smb_share_delete(char *); uint32_t smb_share_rename(char *, char *); uint32_t smb_share_create(smb_share_t *); @@ -238,7 +237,8 @@ uint32_t smb_share_modify(smb_share_t *); door_handle_t smb_kshare_init(int); void smb_kshare_fini(door_handle_t); -uint32_t smb_kshare_getinfo(door_handle_t, char *, smb_share_t *, ipaddr_t); +uint32_t smb_kshare_getinfo(door_handle_t, char *, smb_share_t *, + smb_inaddr_t *); int smb_kshare_upcall(door_handle_t, void *, boolean_t); uint32_t smb_kshare_enum(door_handle_t, smb_enumshare_info_t *); diff --git a/usr/src/uts/common/smbsrv/smb_sid.h b/usr/src/uts/common/smbsrv/smb_sid.h index 97ccba8aa5..69229980d7 100644 --- a/usr/src/uts/common/smbsrv/smb_sid.h +++ b/usr/src/uts/common/smbsrv/smb_sid.h @@ -216,6 +216,31 @@ typedef struct smb_sid { } smb_sid_t; /* + * Only group attributes are defined. No user attributes defined. + */ +#define SE_GROUP_MANDATORY 0x00000001 +#define SE_GROUP_ENABLED_BY_DEFAULT 0x00000002 +#define SE_GROUP_ENABLED 0x00000004 +#define SE_GROUP_OWNER 0x00000008 +#define SE_GROUP_USE_FOR_DENY_ONLY 0x00000010 +#define SE_GROUP_LOGON_ID 0xC0000000 + +/* + * smb_id_t consists of both the Windows security identifier + * and its corresponding POSIX/ephemeral ID. + */ +typedef struct smb_id { + uint32_t i_attrs; + smb_sid_t *i_sid; + uid_t i_id; +} smb_id_t; + +typedef struct smb_ids { + uint32_t i_cnt; + smb_id_t *i_ids; +} smb_ids_t; + +/* * The maximum size of a SID in string format */ #define SMB_SID_STRSZ 256 @@ -225,7 +250,7 @@ int smb_sid_len(smb_sid_t *); smb_sid_t *smb_sid_dup(smb_sid_t *); smb_sid_t *smb_sid_splice(smb_sid_t *, uint32_t); int smb_sid_getrid(smb_sid_t *, uint32_t *); -int smb_sid_split(smb_sid_t *, uint32_t *); +smb_sid_t *smb_sid_split(smb_sid_t *, uint32_t *); boolean_t smb_sid_cmp(smb_sid_t *, smb_sid_t *); boolean_t smb_sid_islocal(smb_sid_t *); boolean_t smb_sid_indomain(smb_sid_t *, smb_sid_t *); @@ -235,6 +260,8 @@ void smb_sid_tostr(smb_sid_t *, char *); smb_sid_t *smb_sid_fromstr(char *); char *smb_sid_type2str(uint16_t); +void smb_ids_free(smb_ids_t *); + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/smbsrv/smb_token.h b/usr/src/uts/common/smbsrv/smb_token.h index d132dc9724..6fe58f233e 100644 --- a/usr/src/uts/common/smbsrv/smb_token.h +++ b/usr/src/uts/common/smbsrv/smb_token.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -29,6 +29,7 @@ #include <smbsrv/netrauth.h> #include <smbsrv/smb_privilege.h> #include <smbsrv/smb_sid.h> +#include <smbsrv/smb_xdr.h> #ifdef __cplusplus extern "C" { @@ -51,40 +52,8 @@ typedef struct smb_session_key { * used when access is requested to an object by comparing this * information with the DACL in the object's security descriptor. * - * Only group attributes are defined. No user attributes defined. - */ - -#define SE_GROUP_MANDATORY 0x00000001 -#define SE_GROUP_ENABLED_BY_DEFAULT 0x00000002 -#define SE_GROUP_ENABLED 0x00000004 -#define SE_GROUP_OWNER 0x00000008 -#define SE_GROUP_USE_FOR_DENY_ONLY 0x00000010 -#define SE_GROUP_LOGON_ID 0xC0000000 - -typedef struct smb_sid_attrs { - uint32_t attrs; - smb_sid_t *sid; -} smb_sid_attrs_t; - -/* - * smb_id_t consists of both the Windows security identifier - * and its corresponding POSIX/ephemeral ID. - */ -typedef struct smb_id { - smb_sid_attrs_t i_sidattr; - uid_t i_id; -} smb_id_t; - -/* - * Windows groups (each group SID is associated with a POSIX/ephemeral - * gid. - */ -typedef struct smb_win_grps { - uint16_t wg_count; - smb_id_t wg_groups[ANY_SIZE_ARRAY]; -} smb_win_grps_t; - -/* + * There should be one unique token per user per session per client. + * * Access Token Flags * * SMB_ATF_GUEST Token belongs to guest user @@ -106,80 +75,26 @@ typedef struct smb_win_grps { * It consists of the primary and supplementary POSIX groups. */ typedef struct smb_posix_grps { - uint32_t pg_ngrps; - gid_t pg_grps[ANY_SIZE_ARRAY]; + uint32_t pg_ngrps; + gid_t pg_grps[ANY_SIZE_ARRAY]; } smb_posix_grps_t; -/* - * Token Structure. - * - * This structure contains information of a user. There should be one - * unique token per user per session per client. The information - * provided will either give or deny access to shares, files or folders. - */ typedef struct smb_token { - smb_id_t *tkn_user; - smb_id_t *tkn_owner; - smb_id_t *tkn_primary_grp; - smb_win_grps_t *tkn_win_grps; - smb_privset_t *tkn_privileges; - char *tkn_account_name; - char *tkn_domain_name; - uint32_t tkn_flags; - uint32_t tkn_audit_sid; + smb_id_t tkn_user; + smb_id_t tkn_owner; + smb_id_t tkn_primary_grp; + smb_ids_t tkn_win_grps; + smb_privset_t *tkn_privileges; + char *tkn_account_name; + char *tkn_domain_name; + uint32_t tkn_flags; + uint32_t tkn_audit_sid; smb_session_key_t *tkn_session_key; smb_posix_grps_t *tkn_posix_grps; } smb_token_t; -/* - * Information returned by an RPC call is allocated on an internal heap - * which is deallocated before returning from the interface call. The - * smb_userinfo structure provides a useful common mechanism to get the - * information back to the caller. It's like a compact access token but - * only parts of it are filled in by each RPC so the content is call - * specific. - */ -typedef struct smb_rid_attrs { - uint32_t rid; - uint32_t attributes; -} smb_rid_attrs_t; - -#define SMB_UINFO_FLAG_ANON 0x01 -#define SMB_UINFO_FLAG_LADMIN 0x02 /* Local admin */ -#define SMB_UINFO_FLAG_DADMIN 0x04 /* Domain admin */ -#define SMB_UINFO_FLAG_ADMIN (SMB_UINFO_FLAG_LADMIN | SMB_UINFO_FLAG_DADMIN) - -/* - * This structure is mainly used where there's some - * kind of user related interaction with a domain - * controller via different RPC calls. - */ -typedef struct smb_userinfo { - uint16_t sid_name_use; - uint32_t rid; - uint32_t primary_group_rid; - char *name; - char *domain_name; - smb_sid_t *domain_sid; - uint32_t n_groups; - smb_rid_attrs_t *groups; - uint32_t n_other_grps; - smb_sid_attrs_t *other_grps; - smb_session_key_t *session_key; - - smb_sid_t *user_sid; - smb_sid_t *pgrp_sid; - uint32_t flags; -} smb_userinfo_t; - /* XDR routines */ -extern bool_t xdr_smb_session_key_t(); extern bool_t xdr_netr_client_t(); -extern bool_t xdr_smb_sid_t(); -extern bool_t xdr_smb_sid_attrs_t(); -extern bool_t xdr_smb_id_t(); -extern bool_t xdr_smb_win_grps_t(); -extern bool_t xdr_smb_posix_grps_t(); extern bool_t xdr_smb_token_t(); diff --git a/usr/src/uts/common/smbsrv/smb_vops.h b/usr/src/uts/common/smbsrv/smb_vops.h index 3de3605083..7286db45dd 100644 --- a/usr/src/uts/common/smbsrv/smb_vops.h +++ b/usr/src/uts/common/smbsrv/smb_vops.h @@ -19,15 +19,13 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SMBSRV_SMB_VOPS_H #define _SMBSRV_SMB_VOPS_H -#pragma ident "@(#)smb_vops.h 1.9 08/08/07 SMI" - /* * Common file system interfaces and definitions. */ @@ -56,80 +54,7 @@ extern "C" { #define SMB_STREAM_PREFIX_LEN (sizeof (SMB_STREAM_PREFIX) - 1) #define SMB_SHORTNAMELEN 14 -#define SMB_EOF 0x7FFFFFFF - -/* - * SMB_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to - * VOP_READDIR. Its value is the size of the maximum possible edirent_t - * for solaris. The EDIRENT_RECLEN macro returns the size of edirent_t - * required for a given name length. MAXNAMELEN is the maximum - * filename length allowed in Solaris. The first two EDIRENT_RECLEN() - * macros are to allow for . and .. entries -- just a minor tweak to try - * and guarantee that buffer we give to VOP_READDIR will be large enough - * to hold ., .., and the largest possible solaris edirent_t. - * - * This bufsize will also be used when reading dirent64_t entries. - */ - -#define SMB_MINLEN_RDDIR_BUF \ - (EDIRENT_RECLEN(1) + EDIRENT_RECLEN(2) + EDIRENT_RECLEN(MAXNAMELEN)) - -/* - * DP_TO_EDP - * - * Fill in an edirent_t structure with information from a dirent64_t. - * This allows the use of an edirent_t in code where both edirent_t's - * and dirent64_t's are manipulated. - */ - -#define DP_TO_EDP(dp, edp) \ -{ \ - ASSERT((dp)); \ - ASSERT((edp)); \ - (edp)->ed_ino = (dp)->d_ino; \ - (edp)->ed_off = (dp)->d_off; \ - (edp)->ed_eflags = 0; \ - (edp)->ed_reclen = (dp)->d_reclen; \ - (void) strlcpy((edp)->ed_name, (dp)->d_name, MAXNAMELEN); \ -} - -/* - * DP_ADVANCE - * - * In readdir operations, advance to read the next entry in a buffer - * returned from VOP_READDIR. The entries are of type dirent64_t. - */ - -#define DP_ADVANCE(dp, dirbuf, numbytes) \ -{ \ - ASSERT((dp)); \ - if ((dp)->d_reclen == 0) { \ - (dp) = NULL; \ - } else { \ - (dp) = (dirent64_t *)((char *)(dp) + (dp)->d_reclen); \ - if ((dp) >= (dirent64_t *)((dirbuf) + (numbytes))) \ - (dp) = NULL; \ - } \ -} - -/* - * EDP_ADVANCE - * - * In readdir operations, advance to read the next entry in a buffer - * returned from VOP_READDIR. The entries are of type edirent_t. - */ - -#define EDP_ADVANCE(edp, dirbuf, numbytes) \ -{ \ - ASSERT((edp)); \ - if ((edp)->ed_reclen == 0) { \ - (edp) = NULL; \ - } else { \ - (edp) = (edirent_t *)((char *)(edp) + (edp)->ed_reclen);\ - if ((edp) >= (edirent_t *)((dirbuf) + (numbytes))) \ - (edp) = NULL; \ - } \ -} +#define SMB_MAXDIRSIZE 0x7FFFFFFF struct smb_node; struct smb_request; @@ -173,11 +98,6 @@ typedef struct smb_attr { SMB_AT_ATIME|SMB_AT_MTIME|SMB_AT_CTIME|SMB_AT_RDEV|\ SMB_AT_BLKSIZE|SMB_AT_NBLOCKS|SMB_AT_SEQ|SMB_AT_SMB) -struct fs_stream_info { - char name[MAXPATHLEN]; - uint64_t size; -}; - int fhopen(const struct smb_node *, int); int smb_vop_init(void); @@ -200,19 +120,14 @@ int smb_vop_rename(vnode_t *, char *, vnode_t *, char *, int, cred_t *); int smb_vop_mkdir(vnode_t *, char *, smb_attr_t *, vnode_t **, int, cred_t *, vsecattr_t *); int smb_vop_rmdir(vnode_t *, char *, int, cred_t *); -int smb_vop_readdir(vnode_t *, uint32_t *, char *, int *, ino64_t *, vnode_t **, - char *, int, cred_t *); +int smb_vop_readdir(vnode_t *, uint32_t, void *, int *, int *, cred_t *); int smb_vop_commit(vnode_t *, cred_t *); -int smb_vop_getdents(struct smb_node *, uint32_t *, uint64_t *, int32_t *, - char *, char *, uint32_t, struct smb_request *, cred_t *); int smb_vop_statfs(vnode_t *, struct statvfs64 *, cred_t *); int smb_vop_stream_lookup(vnode_t *, char *, vnode_t **, char *, vnode_t **, int, vnode_t *, cred_t *); int smb_vop_stream_create(vnode_t *, char *, smb_attr_t *, vnode_t **, vnode_t **, int, cred_t *); int smb_vop_stream_remove(vnode_t *, char *, int, cred_t *); -int smb_vop_stream_readdir(vnode_t *, uint32_t *, struct fs_stream_info *, - vnode_t **, vnode_t **, int, cred_t *); int smb_vop_lookup_xattrdir(vnode_t *, vnode_t **, int, cred_t *); int smb_vop_traverse_check(vnode_t **); diff --git a/usr/src/uts/common/smbsrv/smb_xdr.h b/usr/src/uts/common/smbsrv/smb_xdr.h index ad9b44aec3..078ad03b26 100644 --- a/usr/src/uts/common/smbsrv/smb_xdr.h +++ b/usr/src/uts/common/smbsrv/smb_xdr.h @@ -32,6 +32,7 @@ extern "C" { #include <rpc/xdr.h> #include <sys/param.h> +#include <smbsrv/smbinfo.h> typedef struct smb_dr_kshare { int32_t k_op; @@ -101,7 +102,7 @@ typedef struct smb_opipe_context { char *oc_account; uint16_t oc_workstation_len; char *oc_workstation; - uint32_t oc_ipaddr; + smb_inaddr_t oc_ipaddr; int32_t oc_native_os; int64_t oc_logon_time; uint32_t oc_flags; @@ -117,6 +118,7 @@ extern bool_t xdr_smb_dr_string_t(XDR *, smb_dr_string_t *); extern bool_t xdr_smb_dr_bytes_t(XDR *, smb_dr_bytes_t *); extern bool_t xdr_smb_dr_ulist_t(XDR *, smb_dr_ulist_t *); extern bool_t xdr_smb_dr_kshare_t(XDR *, smb_dr_kshare_t *); +extern bool_t xdr_smb_inaddr_t(XDR *, smb_inaddr_t *); int smb_opipe_hdr_encode(smb_opipe_hdr_t *, uint8_t *, uint32_t); int smb_opipe_hdr_decode(smb_opipe_hdr_t *, uint8_t *, uint32_t); diff --git a/usr/src/uts/common/smbsrv/smbinfo.h b/usr/src/uts/common/smbsrv/smbinfo.h index 8261986b8a..7aef7ccd09 100644 --- a/usr/src/uts/common/smbsrv/smbinfo.h +++ b/usr/src/uts/common/smbsrv/smbinfo.h @@ -28,6 +28,8 @@ #include <sys/types.h> #include <smbsrv/netbios.h> +#include <netinet/in.h> +#include <smbsrv/smb_inet.h> #ifdef __cplusplus extern "C" { @@ -114,6 +116,7 @@ typedef struct smb_kmod_cfg { int32_t skc_oplock_enable; int32_t skc_sync_enable; int32_t skc_secmode; + int32_t skc_ipv6_enable; char skc_nbdomain[NETBIOS_NAME_SZ]; char skc_fqdn[SMB_PI_MAX_DOMAIN]; char skc_hostname[SMB_PI_MAX_HOST]; diff --git a/usr/src/uts/common/smbsrv/smbtrans.h b/usr/src/uts/common/smbsrv/smbtrans.h deleted file mode 100644 index 9ffd7e3667..0000000000 --- a/usr/src/uts/common/smbsrv/smbtrans.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _SMBSRV_SMBTRANS_H -#define _SMBSRV_SMBTRANS_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/param.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Note that name can be variable length; therefore, it has to - * stay last. - */ -typedef struct smb_dent_info { - uint32_t cookie; - smb_attr_t attr; - struct smb_node *snode; - char name83[14]; - char shortname[14]; - char name[1]; -} smb_dent_info_t; - -#define SMB_MAX_DENT_INFO_SIZE (sizeof (smb_dent_info_t) + MAXNAMELEN - 1) -#define SMB_MAX_DENTS_BUF_SIZE (64 * 1024) /* 64k */ -#define SMB_MAX_DENTS_IOVEC (SMB_MAX_DENTS_BUF_SIZE / SMB_MAX_DENT_INFO_SIZE) - -typedef struct smb_dent_info_hdr { - struct smb_request *sr; - char *pattern; - unsigned short sattr; - struct uio uio; - struct iovec iov[SMB_MAX_DENTS_IOVEC]; -} smb_dent_info_hdr_t; - -int smb_get_dents(struct smb_request *sr, uint32_t *cookie, - struct smb_node *dir_snode, unsigned int wildcards, - smb_dent_info_hdr_t *ihdr, int *more); - -#ifdef __cplusplus -} -#endif - -#endif /* _SMBSRV_SMBTRANS_H */ |