/* * Returns the Unicode string length for the target UNC of * the specified entry by 'refno' * * Note that the UNC path should be encoded with ONE leading * slash not two as is common to user-visible UNC paths. */ static uint16_t smb_dfs_referrals_unclen(dfs_info_t *referrals, uint16_t refno) { uint16_t len; if (refno >= referrals->i_ntargets) return (0); /* Encoded target UNC \server\share */ len = smb_wcequiv_strlen(referrals->i_targets[refno].t_server) + smb_wcequiv_strlen(referrals->i_targets[refno].t_share) + smb_wcequiv_strlen("\\\\") + 2; /* two '\' + NULL */ return (len); }
/* * samr_lookup_domain * * Lookup up the domain SID for the specified domain name. The handle * should be one returned from samr_connect. The allocated memory for * the returned SID must be freed by caller. */ 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; size_t length; if (ndr_is_null_handle(samr_handle) || domain_name == NULL) return (NULL); opnum = SAMR_OPNUM_LookupDomain; bzero(&arg, sizeof (struct samr_LookupDomain)); (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (samr_handle_t)); length = smb_wcequiv_strlen(domain_name); if (ndr_rpc_server_os(samr_handle) == NATIVE_OS_WIN2000) length += sizeof (smb_wchar_t); arg.domain_name.length = length; arg.domain_name.allosize = length; arg.domain_name.str = (unsigned char *)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 (domsid); }
/* * FileFsVolumeInformation */ uint32_t smb2_qfs_volume(smb_request_t *sr) { smb_tree_t *tree = sr->tid_tree; smb_node_t *snode; fsid_t fsid; uint32_t LabelLength; if (!STYPE_ISDSK(tree->t_res_type)) return (NT_STATUS_INVALID_PARAMETER); snode = tree->t_snode; fsid = SMB_NODE_FSID(snode); LabelLength = smb_wcequiv_strlen(tree->t_volume); /* * NT has the "supports objects" flag set to 1. */ (void) smb_mbc_encodef( &sr->raw_data, "qllb.U", 0LL, /* Volume creation time (q) */ fsid.val[0], /* serial no. (l) */ LabelLength, /* (l) */ 0, /* Supports objects (b) */ /* reserved (.) */ tree->t_volume); /* (U) */ return (0); }
/* * This fills in a samr_user_password (a.k.a. SAMPR_USER_PASSWORD * in the MS Net API) which has the new password "right justified" * in the buffer, and any space on the left filled with random junk * to improve the quality of the encryption that is subsequently * applied to this buffer before it goes over the wire. */ static void samr_fill_userpw(struct samr_user_password *upw, const char *new_pw) { smb_wchar_t *pbuf; uint32_t pwlen_bytes; size_t pwlen_wchars; /* * First fill the whole buffer with the random junk. * (Slightly less random when debugging:) */ #ifdef DEBUG (void) memset(upw->Buffer, '*', sizeof (upw->Buffer)); #else randomize((char *)upw->Buffer, sizeof (upw->Buffer)); #endif /* * Now overwrite the last pwlen characters of * that buffer with the password, and set the * length field so the receiving end knows where * the junk ends and the real password starts. */ pwlen_wchars = smb_wcequiv_strlen(new_pw) / 2; if (pwlen_wchars > SAMR_USER_PWLEN) pwlen_wchars = SAMR_USER_PWLEN; pwlen_bytes = pwlen_wchars * 2; pbuf = &upw->Buffer[SAMR_USER_PWLEN - pwlen_wchars]; (void) smb_mbstowcs(pbuf, new_pw, pwlen_wchars); /* Yes, this is in Bytes, not wchars. */ upw->Length = htolel(pwlen_bytes); }
/* * Prepare a response with V3/V4 referral format. * * For more details, see comments for smb_dfs_encode_refv2() or see * MS-DFSC specification. */ static uint32_t smb_dfs_encode_refv3x(smb_request_t *sr, mbuf_chain_t *mbc, dfs_info_t *referrals, uint16_t ver) { _NOTE(ARGUNUSED(sr)) uint16_t entsize, rep_bufsize, hdrsize; uint16_t server_type; uint16_t flags = 0; uint16_t path_offs, altpath_offs, netpath_offs; uint16_t targetsz, total_targetsz = 0; uint16_t dfs_pathsz; uint16_t r; hdrsize = (ver == DFS_REFERRAL_V3) ? DFS_REFV3_ENTSZ : DFS_REFV4_ENTSZ; rep_bufsize = MBC_MAXBYTES(mbc); dfs_pathsz = smb_wcequiv_strlen(referrals->i_uncpath) + 2; entsize = hdrsize + dfs_pathsz + dfs_pathsz + smb_dfs_referrals_unclen(referrals, 0); if (entsize > rep_bufsize) { /* need room for at least one referral */ return (NT_STATUS_BUFFER_OVERFLOW); } server_type = (referrals->i_type == DFS_OBJECT_ROOT) ? DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT; rep_bufsize -= entsize; for (r = 0; r < referrals->i_ntargets; r++) { path_offs = (referrals->i_ntargets - r) * hdrsize; altpath_offs = path_offs + dfs_pathsz; netpath_offs = altpath_offs + dfs_pathsz + total_targetsz; targetsz = smb_dfs_referrals_unclen(referrals, r); if (r != 0) { entsize = hdrsize + targetsz; if (entsize > rep_bufsize) /* silently drop targets that do not fit */ break; rep_bufsize -= entsize; flags = 0; } else if (ver == DFS_REFERRAL_V4) { flags = DFS_ENTFLG_T; } (void) smb_mbc_encodef(mbc, "wwwwlwww16.", ver, hdrsize, server_type, flags, referrals->i_timeout, path_offs, altpath_offs, netpath_offs); total_targetsz += targetsz; } smb_dfs_encode_targets(mbc, referrals); return (NT_STATUS_SUCCESS); }
/* * samr_lookup_domain_names * * 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 NT status codes. */ uint32_t samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name, smb_account_t *account) { struct samr_LookupNames arg; int opnum; uint32_t status; size_t length; if (ndr_is_null_handle(domain_handle) || 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)); (void) memcpy(&arg.handle, &domain_handle->handle, sizeof (samr_handle_t)); arg.n_entry = 1; arg.max_n_entry = 1000; arg.index = 0; arg.total = 1; length = smb_wcequiv_strlen(name); if (ndr_rpc_server_os(domain_handle) == NATIVE_OS_WIN2000) length += sizeof (smb_wchar_t); arg.name.length = length; arg.name.allosize = length; arg.name.str = (unsigned char *)name; if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) { status = NT_STATUS_INVALID_PARAMETER; } else if (arg.status != NT_STATUS_SUCCESS) { status = NT_SC_VALUE(arg.status); /* * Handle none-mapped status quietly. */ if (status != NT_STATUS_NONE_MAPPED) ndr_rpc_status(domain_handle, opnum, arg.status); } else { 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); return (status); }
void smb_rpc_off(char *dst, char *src, uint32_t *offset, uint32_t *outoffset) { int nwchars; int bytes; bytes = smb_wcequiv_strlen(src) + 2; nwchars = strlen(src) + 1; *offset -= bytes; *outoffset = *offset; /*LINTED E_BAD_PTR_CAST_ALIGN*/ (void) smb_mbstowcs(((smb_wchar_t *)(dst + *offset)), src, nwchars); }
/* * Make an ndr_mstring_t from a regular string. */ int ndr_heap_mstring(ndr_heap_t *heap, const char *s, ndr_mstring_t *out) { if (s == NULL || out == NULL) return (-1); out->length = smb_wcequiv_strlen(s); out->allosize = out->length + sizeof (smb_wchar_t); if ((out->str = ndr_heap_strdup(heap, s)) == NULL) return (-1); return (0); }
/* * FileFsAttributeInformation */ uint32_t smb2_qfs_attr(smb_request_t *sr) { smb_tree_t *tree = sr->tid_tree; char *fsname; uint32_t namelen; uint32_t FsAttr; /* This call is OK on all tree types. */ switch (tree->t_res_type & STYPE_MASK) { case STYPE_IPC: fsname = "PIPE"; break; case STYPE_DISKTREE: fsname = "NTFS"; /* A lie, but compatible... */ break; case STYPE_PRINTQ: case STYPE_DEVICE: default: /* gcc -Wuninitialized */ return (NT_STATUS_INVALID_PARAMETER); } namelen = smb_wcequiv_strlen(fsname); /* * Todo: Store the FsAttributes in the tree object, * then just return that directly here. */ FsAttr = FILE_CASE_PRESERVED_NAMES; if (tree->t_flags & SMB_TREE_UNICODE_ON_DISK) FsAttr |= FILE_UNICODE_ON_DISK; if (tree->t_flags & SMB_TREE_SUPPORTS_ACLS) FsAttr |= FILE_PERSISTENT_ACLS; if ((tree->t_flags & SMB_TREE_CASEINSENSITIVE) == 0) FsAttr |= FILE_CASE_SENSITIVE_SEARCH; if (tree->t_flags & SMB_TREE_STREAMS) FsAttr |= FILE_NAMED_STREAMS; if (tree->t_flags & SMB_TREE_QUOTA) FsAttr |= FILE_VOLUME_QUOTAS; if (tree->t_flags & SMB_TREE_SPARSE) FsAttr |= FILE_SUPPORTS_SPARSE_FILES; (void) smb_mbc_encodef( &sr->raw_data, "lllU", FsAttr, MAXNAMELEN-1, namelen, fsname); return (0); }
static void smb_dfs_encode_hdr(mbuf_chain_t *mbc, dfs_info_t *referrals) { uint16_t path_consumed; uint32_t flags; path_consumed = smb_wcequiv_strlen(referrals->i_uncpath); flags = DFS_HDRFLG_S; if (referrals->i_type == DFS_OBJECT_ROOT) flags |= DFS_HDRFLG_R; /* Fill rep_param_mb in SMB1 caller. */ (void) smb_mbc_encodef(mbc, "wwl", path_consumed, referrals->i_ntargets, flags); }
static uint32_t smb_dfs_encode_refv1(smb_request_t *sr, mbuf_chain_t *mbc, dfs_info_t *referrals) { _NOTE(ARGUNUSED(sr)) uint16_t entsize, rep_bufsize; uint16_t server_type; uint16_t flags = 0; uint16_t r; char *target; rep_bufsize = MBC_MAXBYTES(mbc); server_type = (referrals->i_type == DFS_OBJECT_ROOT) ? DFS_SRVTYPE_ROOT : DFS_SRVTYPE_NONROOT; target = kmem_alloc(MAXPATHLEN, KM_SLEEP); for (r = 0; r < referrals->i_ntargets; r++) { (void) snprintf(target, MAXPATHLEN, "\\%s\\%s", referrals->i_targets[r].t_server, referrals->i_targets[r].t_share); entsize = DFS_REFV1_ENTSZ + smb_wcequiv_strlen(target) + 2; if (entsize > rep_bufsize) break; (void) smb_mbc_encodef(mbc, "wwwwU", DFS_REFERRAL_V1, entsize, server_type, flags, target); rep_bufsize -= entsize; } kmem_free(target, MAXPATHLEN); /* * Need room for at least one entry. * Windows will silently drop targets that do not fit in * the response buffer. */ if (r == 0) { return (NT_STATUS_BUFFER_OVERFLOW); } return (NT_STATUS_SUCCESS); }
/* * Our regular string marshalling always creates null terminated strings * but some Windows clients and servers are pedantic about the string * formats they will accept and require non-null terminated strings. * This function can be used to build a wide-char, non-null terminated * string in the heap as a varying/conformant array. We need to do the * wide-char conversion here because the marshalling code won't be * aware that this is really a string. */ void ndr_heap_mkvcs(ndr_heap_t *heap, char *s, ndr_vcstr_t *vc) { int mlen; vc->wclen = smb_wcequiv_strlen(s); vc->wcsize = vc->wclen; mlen = sizeof (ndr_vcs_t) + vc->wcsize + sizeof (smb_wchar_t); vc->vcs = ndr_heap_malloc(heap, mlen); if (vc->vcs) { vc->vcs->vc_first_is = 0; vc->vcs->vc_length_is = vc->wclen / sizeof (smb_wchar_t); (void) smb_mbstowcs((smb_wchar_t *)vc->vcs->buffer, s, vc->vcs->vc_length_is); } }
/* * lsar_lookup_priv_display_name * * Map a privilege name to a privilege display name. The input handle * should be an LSA policy handle and the name would normally be one * of the privileges defined in smb_privilege.h * * There's something peculiar about the return status from NT servers, * it's not always present. So for now, I'm ignoring the status in the * RPC response. * * Returns NT status codes. */ DWORD lsar_lookup_priv_display_name(mlsvc_handle_t *lsa_handle, char *name, char *display_name, int display_len) { struct mslsa_LookupPrivDisplayName arg; int opnum; size_t length; DWORD status; if (lsa_handle == NULL || name == NULL || display_name == NULL) return (NT_STATUS_INVALID_PARAMETER); opnum = LSARPC_OPNUM_LookupPrivDisplayName; bzero(&arg, sizeof (struct mslsa_LookupPrivDisplayName)); (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); length = smb_wcequiv_strlen(name); arg.name.length = length; arg.name.allosize = length; arg.name.str = (unsigned char *)name; arg.client_language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); arg.default_language = MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL); if (ndr_rpc_call(lsa_handle, opnum, &arg) != 0) status = NT_STATUS_INVALID_PARAMETER; #if 0 else if (arg.status != 0) status = NT_SC_VALUE(arg.status); #endif else { (void) strlcpy(display_name, (char const *)arg.display_name->str, display_len); status = NT_STATUS_SUCCESS; } ndr_rpc_release(lsa_handle); return (status); }
/* * FileAlternateNameInformation * See also: * SMB_QUERY_FILE_ALT_NAME_INFO * SMB_FILE_ALT_NAME_INFORMATION */ static uint32_t smb2_qif_altname(smb_request_t *sr, smb_queryinfo_t *qi) { smb_ofile_t *of = sr->fid_ofile; ASSERT(qi->qi_namelen > 0); ASSERT(qi->qi_attr.sa_mask & SMB_AT_NODEID); if (of->f_ftype != SMB_FTYPE_DISK) return (NT_STATUS_OBJECT_NAME_NOT_FOUND); if ((of->f_tree->t_flags & SMB_TREE_SHORTNAMES) == 0) return (NT_STATUS_OBJECT_NAME_NOT_FOUND); /* fill in qi->qi_shortname */ smb_query_shortname(of->f_node, qi); (void) smb_mbc_encodef( &sr->raw_data, "%lU", sr, smb_wcequiv_strlen(qi->qi_shortname), qi->qi_shortname); return (0); }
/* * lsar_lookup_priv_value * * Map a privilege name to a local unique id (LUID). Privilege names * are consistent across the network. LUIDs are machine specific. * This function provides the means to map a privilege name to the * LUID used by a remote server to represent it. The handle here is * a policy handle. */ int lsar_lookup_priv_value(mlsvc_handle_t *lsa_handle, char *name, struct ms_luid *luid) { struct mslsa_LookupPrivValue arg; int opnum; int rc; size_t length; if (lsa_handle == NULL || name == NULL || luid == NULL) return (-1); opnum = LSARPC_OPNUM_LookupPrivValue; bzero(&arg, sizeof (struct mslsa_LookupPrivValue)); (void) memcpy(&arg.handle, lsa_handle, sizeof (mslsa_handle_t)); length = smb_wcequiv_strlen(name); if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) length += sizeof (smb_wchar_t); arg.name.length = length; arg.name.allosize = length; arg.name.str = (unsigned char *)name; rc = ndr_rpc_call(lsa_handle, opnum, &arg); if (rc == 0) { if (arg.status != 0) rc = -1; else (void) memcpy(luid, &arg.luid, sizeof (struct ms_luid)); } ndr_rpc_release(lsa_handle); return (rc); }
/* * Lookup a name and obtain the sid/rid. * This is a wrapper for the various lookup sid RPCs. */ uint32_t lsar_lookup_names(mlsvc_handle_t *lsa_handle, char *name, smb_account_t *info) { static lsar_nameop_t ops[] = { lsar_lookup_names3, lsar_lookup_names2, lsar_lookup_names1 }; const srvsvc_server_info_t *svinfo; lsa_names_t names; char *p; uint32_t length; uint32_t status = NT_STATUS_INVALID_PARAMETER; int n_op = (sizeof (ops) / sizeof (ops[0])); int i; if (lsa_handle == NULL || name == NULL || info == NULL) return (NT_STATUS_INVALID_PARAMETER); bzero(info, sizeof (smb_account_t)); svinfo = ndr_rpc_server_info(lsa_handle); if (svinfo->sv_os == NATIVE_OS_WIN2000 && svinfo->sv_version_major == 5 && svinfo->sv_version_minor == 0) { /* * Windows 2000 doesn't like an LSA lookup for * DOMAIN\Administrator. */ if ((p = strchr(name, '\\')) != 0) { ++p; if (strcasecmp(p, "administrator") == 0) name = p; } } length = smb_wcequiv_strlen(name); names.name[0].length = length; names.name[0].allosize = length; names.name[0].str = (unsigned char *)name; names.n_entry = 1; if (ndr_rpc_server_os(lsa_handle) == NATIVE_OS_WIN2000) { for (i = 0; i < n_op; ++i) { ndr_rpc_set_nonull(lsa_handle); status = (*ops[i])(lsa_handle, &names, info); if (status != NT_STATUS_INVALID_PARAMETER) break; } } else { ndr_rpc_set_nonull(lsa_handle); status = lsar_lookup_names1(lsa_handle, &names, info); } if (status == NT_STATUS_SUCCESS) { info->a_name = lsar_get_username(name); if (!smb_account_validate(info)) { smb_account_free(info); status = NT_STATUS_NO_MEMORY; } else { smb_account_trace(info); } } return (status); }
/* * smb_trans2_mbc_encode * * This function encodes the mbc for one directory entry. * * The function returns -1 when the max data requested by client * is reached. If the entry is valid and successful encoded, 0 * will be returned; otherwise, 1 will be returned. * * We always null terminate the filename. The space for the null * is included in the maxdata calculation and is therefore included * in the next_entry_offset. namelen is the unterminated length of * the filename. For levels except STANDARD and EA_SIZE, if the * 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 */ 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; 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); next_entry_offset = args->fa_maxdata + namelen; 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 * include the null terminator for levels except STANDARD and * EASIZE. */ if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { if ((args->fa_infolev != SMB_INFO_STANDARD) && (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) namelen += 1; } 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; switch (args->fa_infolev) { case SMB_INFO_STANDARD: if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) (void) smb_mbc_encodef(&xa->rep_data_mb, "l", fileinfo->fi_cookie); (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwbu", sr, smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), dsize32, asize32, fileinfo->fi_dosattr, namelen, fileinfo->fi_name); break; case SMB_INFO_QUERY_EA_SIZE: if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) (void) smb_mbc_encodef(&xa->rep_data_mb, "l", fileinfo->fi_cookie); /* * Unicode filename should NOT be aligned. Encode ('u') * into a temporary buffer, then encode buffer as a * byte stream ('#c'). * Regardless of whether unicode or ascii, a single * termination byte is used. */ buflen = namelen + sizeof (smb_wchar_t); tmpbuf = kmem_zalloc(buflen, KM_SLEEP); smb_msgbuf_init(&mb, (uint8_t *)tmpbuf, buflen, mb_flags); if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_name) < 0) { smb_msgbuf_term(&mb); kmem_free(tmpbuf, buflen); return (-1); } tmpbuf[namelen] = '\0'; (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb#c", sr, smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), dsize32, asize32, fileinfo->fi_dosattr, 0L, /* EA Size */ namelen, namelen + 1, tmpbuf); smb_msgbuf_term(&mb); kmem_free(tmpbuf, buflen); break; case SMB_FIND_FILE_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqllu", sr, next_entry_offset, 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, fileinfo->fi_name); break; case SMB_FIND_FILE_FULL_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllu", sr, next_entry_offset, 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, 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, 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, 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", fileinfo->fi_shortname) < 0) { smb_msgbuf_term(&mb); return (-1); } shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24cu", sr, next_entry_offset, 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, fileinfo->fi_name); smb_msgbuf_term(&mb); break; case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: bzero(buf83, sizeof (buf83)); smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), mb_flags); if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { smb_msgbuf_term(&mb); return (-1); } 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, 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, fileinfo->fi_nodeid, fileinfo->fi_name); smb_msgbuf_term(&mb); break; case SMB_FIND_FILE_NAMES_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%lllu", sr, next_entry_offset, fileinfo->fi_cookie, namelen, fileinfo->fi_name); break; } return (0); }
/* * smb_query_encode_response * * Encode the data from smb_queryinfo_t into client response */ int smb_query_encode_response(smb_request_t *sr, smb_xa_t *xa, uint16_t infolev, smb_queryinfo_t *qinfo) { uint16_t dattr; u_offset_t datasz, allocsz; uint32_t isdir; dattr = qinfo->qi_attr.sa_dosattr & FILE_ATTRIBUTE_MASK; datasz = qinfo->qi_attr.sa_vattr.va_size; allocsz = qinfo->qi_attr.sa_allocsz; isdir = ((dattr & FILE_ATTRIBUTE_DIRECTORY) != 0); switch (infolev) { case SMB_QUERY_INFORMATION: (void) smbsr_encode_result(sr, 10, 0, "bwll10.w", 10, dattr, smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), smb_size32(datasz), 0); break; case SMB_QUERY_INFORMATION2: (void) smbsr_encode_result(sr, 11, 0, "byyyllww", 11, smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), smb_size32(datasz), smb_size32(allocsz), dattr, 0); break; case SMB_FILE_ACCESS_INFORMATION: ASSERT(sr->fid_ofile); (void) smb_mbc_encodef(&xa->rep_data_mb, "l", sr->fid_ofile->f_granted_access); break; case SMB_INFO_STANDARD: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYYllw" : "yyyllw"), smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), smb_size32(datasz), smb_size32(allocsz), dattr); break; case SMB_INFO_QUERY_EA_SIZE: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, ((sr->session->native_os == NATIVE_OS_WIN95) ? "YYYllwl" : "yyyllwl"), smb_time_gmt_to_local(sr, qinfo->qi_crtime.tv_sec), smb_time_gmt_to_local(sr, qinfo->qi_atime.tv_sec), smb_time_gmt_to_local(sr, qinfo->qi_mtime.tv_sec), smb_size32(datasz), smb_size32(allocsz), dattr, 0); break; case SMB_INFO_QUERY_ALL_EAS: case SMB_INFO_QUERY_EAS_FROM_LIST: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); break; case SMB_INFO_IS_NAME_VALID: break; case SMB_QUERY_FILE_BASIC_INFO: case SMB_FILE_BASIC_INFORMATION: /* * NT includes 6 bytes (spec says 4) at the end of this * response, which are required by NetBench 5.01. */ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.", &qinfo->qi_crtime, &qinfo->qi_atime, &qinfo->qi_mtime, &qinfo->qi_ctime, dattr); break; case SMB_QUERY_FILE_STANDARD_INFO: case SMB_FILE_STANDARD_INFORMATION: /* 2-byte pad at end */ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "qqlbb2.", (uint64_t)allocsz, (uint64_t)datasz, qinfo->qi_attr.sa_vattr.va_nlink, qinfo->qi_delete_on_close, (uint8_t)isdir); break; case SMB_QUERY_FILE_EA_INFO: case SMB_FILE_EA_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "l", 0); break; case SMB_QUERY_FILE_NAME_INFO: case SMB_FILE_NAME_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, qinfo->qi_namelen, qinfo->qi_name); break; case SMB_QUERY_FILE_ALL_INFO: case SMB_FILE_ALL_INFORMATION: /* * There is a 6-byte pad between Attributes and AllocationSize, * and a 2-byte pad after the Directory field. */ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTw6.qqlbb2.l", &qinfo->qi_crtime, &qinfo->qi_atime, &qinfo->qi_mtime, &qinfo->qi_ctime, dattr, (uint64_t)allocsz, (uint64_t)datasz, qinfo->qi_attr.sa_vattr.va_nlink, qinfo->qi_delete_on_close, isdir, 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "%lu", sr, qinfo->qi_namelen, qinfo->qi_name); break; case SMB_QUERY_FILE_ALT_NAME_INFO: case SMB_FILE_ALT_NAME_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "%lU", sr, smb_wcequiv_strlen(qinfo->qi_shortname), qinfo->qi_shortname); break; case SMB_QUERY_FILE_STREAM_INFO: case SMB_FILE_STREAM_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); smb_encode_stream_info(sr, xa, qinfo); break; case SMB_QUERY_FILE_COMPRESSION_INFO: case SMB_FILE_COMPRESSION_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "qwbbb3.", datasz, 0, 0, 0, 0); break; case SMB_FILE_INTERNAL_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "q", qinfo->qi_attr.sa_vattr.va_nodeid); break; case SMB_FILE_NETWORK_OPEN_INFORMATION: (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "TTTTqql4.", &qinfo->qi_crtime, &qinfo->qi_atime, &qinfo->qi_mtime, &qinfo->qi_ctime, (uint64_t)allocsz, (uint64_t)datasz, (uint32_t)dattr); break; case SMB_FILE_ATTR_TAG_INFORMATION: /* * If dattr includes FILE_ATTRIBUTE_REPARSE_POINT, the * second dword should be the reparse tag. Otherwise * the tag value should be set to zero. * We don't support reparse points, so we set the tag * to zero. */ (void) smb_mbc_encodef(&xa->rep_param_mb, "w", 0); (void) smb_mbc_encodef(&xa->rep_data_mb, "ll", (uint32_t)dattr, 0); break; default: if ((infolev > 1000) && smb_query_passthru) smbsr_error(sr, NT_STATUS_NOT_SUPPORTED, ERRDOS, ERROR_NOT_SUPPORTED); else smbsr_error(sr, 0, ERRDOS, ERROR_INVALID_LEVEL); return (-1); } return (0); }
smb_sdrc_t smb_com_negotiate(smb_request_t *sr) { smb_session_t *session = sr->session; smb_arg_negotiate_t *negprot = sr->sr_negprot; uint16_t secmode; uint32_t sesskey; char *nbdomain; uint8_t *wcbuf; int wclen; smb_msgbuf_t mb; int rc; if (session->s_state != SMB_SESSION_STATE_ESTABLISHED) { /* The protocol has already been negotiated. */ smbsr_error(sr, 0, ERRSRV, ERRerror); return (SDRC_ERROR); } /* * Special case for negotiating SMB2 from SMB1. The client * includes the "SMB 2..." dialects in the SMB1 negotiate, * and if SMB2 is enabled, we choose one of those and then * send an SMB2 reply to that SMB1 request. Yes, it's very * strange, but this SMB1 request can have an SMB2 reply! * To accomplish this, we let the SMB2 code send the reply * and return the special code SDRC_NO_REPLY to the SMB1 * dispatch logic so it will NOT send an SMB1 reply. * (Or possibly send an SMB1 error reply.) */ if (negprot->ni_dialect >= DIALECT_SMB2002) { rc = smb1_negotiate_smb2(sr); ASSERT(rc == SDRC_NO_REPLY || rc == SDRC_DROP_VC || rc == SDRC_ERROR); return (rc); } session->secmode = NEGOTIATE_ENCRYPT_PASSWORDS | NEGOTIATE_USER_SECURITY; secmode = session->secmode; sesskey = session->sesskey; negprot->ni_servertime.tv_sec = gethrestime_sec(); negprot->ni_servertime.tv_nsec = 0; negprot->ni_tzcorrection = sr->sr_gmtoff / 60; negprot->ni_maxmpxcount = sr->sr_cfg->skc_maxworkers; negprot->ni_keylen = SMB_CHALLENGE_SZ; bcopy(&session->challenge_key, negprot->ni_key, SMB_CHALLENGE_SZ); nbdomain = sr->sr_cfg->skc_nbdomain; /* * UNICODE support is required for long share names, * long file names and streams. Note: CAP_RAW_MODE * is not supported because it does nothing to help * modern clients and causes nasty complications. */ negprot->ni_capabilities = CAP_LARGE_FILES | CAP_UNICODE | CAP_NT_SMBS | CAP_STATUS32 | CAP_NT_FIND | CAP_LEVEL_II_OPLOCKS | CAP_LOCK_AND_READ | CAP_RPC_REMOTE_APIS | CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_DFS; if (smb_cap_passthru) negprot->ni_capabilities |= CAP_INFOLEVEL_PASSTHRU; else cmn_err(CE_NOTE, "smbsrv: cap passthru is %s", (negprot->ni_capabilities & CAP_INFOLEVEL_PASSTHRU) ? "enabled" : "disabled"); switch (negprot->ni_dialect) { case PC_NETWORK_PROGRAM_1_0: /* core */ (void) ksocket_setsockopt(session->sock, SOL_SOCKET, SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf, sizeof (smb_dos_tcp_rcvbuf), CRED()); rc = smbsr_encode_result(sr, 1, 0, "bww", 1, negprot->ni_index, 0); break; case Windows_for_Workgroups_3_1a: case PCLAN1_0: case MICROSOFT_NETWORKS_1_03: case MICROSOFT_NETWORKS_3_0: case LANMAN1_0: case LM1_2X002: case DOS_LM1_2X002: (void) ksocket_setsockopt(session->sock, SOL_SOCKET, SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf, sizeof (smb_dos_tcp_rcvbuf), CRED()); sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK; rc = smbsr_encode_result(sr, 13, VAR_BCC, "bwwwwwwlYww2.w#c", 13, /* wct */ negprot->ni_index, /* dialect index */ secmode, /* security mode */ SMB_DOS_MAXBUF, /* max buffer size */ 1, /* max MPX */ 1, /* max VCs */ 0, /* read/write raw */ sesskey, /* session key */ negprot->ni_servertime.tv_sec, /* server date/time */ negprot->ni_tzcorrection, (uint16_t)negprot->ni_keylen, /* encryption key length */ /* reserved field handled 2. */ VAR_BCC, (int)negprot->ni_keylen, negprot->ni_key); /* encryption key */ break; case DOS_LANMAN2_1: case LANMAN2_1: (void) ksocket_setsockopt(session->sock, SOL_SOCKET, SO_RCVBUF, (const void *)&smb_dos_tcp_rcvbuf, sizeof (smb_dos_tcp_rcvbuf), CRED()); sr->smb_flg |= SMB_FLAGS_LOCK_AND_READ_OK; rc = smbsr_encode_result(sr, 13, VAR_BCC, "bwwwwwwlYww2.w#cs", 13, /* wct */ negprot->ni_index, /* dialect index */ secmode, /* security mode */ SMB_DOS_MAXBUF, /* max buffer size */ 1, /* max MPX */ 1, /* max VCs */ 0, /* read/write raw */ sesskey, /* session key */ negprot->ni_servertime.tv_sec, /* server date/time */ negprot->ni_tzcorrection, (uint16_t)negprot->ni_keylen, /* encryption key length */ /* reserved field handled 2. */ VAR_BCC, (int)negprot->ni_keylen, negprot->ni_key, /* encryption key */ nbdomain); break; case NT_LM_0_12: (void) ksocket_setsockopt(session->sock, SOL_SOCKET, SO_RCVBUF, (const void *)&smb_nt_tcp_rcvbuf, sizeof (smb_nt_tcp_rcvbuf), CRED()); /* * Allow SMB signatures if using encrypted passwords */ if ((secmode & NEGOTIATE_ENCRYPT_PASSWORDS) && sr->sr_cfg->skc_signing_enable) { secmode |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED; if (sr->sr_cfg->skc_signing_required) secmode |= NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; session->secmode = secmode; } /* * Does the client want Extended Security? * (and if we have it enabled) * If so, handle as if a different dialect. */ if ((sr->smb_flg2 & SMB_FLAGS2_EXT_SEC) && smb_cap_ext_sec) goto NT_LM_0_12_ext_sec; sr->smb_flg2 &= ~SMB_FLAGS2_EXT_SEC; /* * nbdomain is not expected to be aligned. * Use temporary buffer to avoid alignment padding */ wclen = smb_wcequiv_strlen(nbdomain) + sizeof (smb_wchar_t); wcbuf = smb_srm_zalloc(sr, wclen); smb_msgbuf_init(&mb, wcbuf, wclen, SMB_MSGBUF_UNICODE); if (smb_msgbuf_encode(&mb, "U", nbdomain) < 0) { smb_msgbuf_term(&mb); smbsr_error(sr, 0, ERRSRV, ERRerror); return (SDRC_ERROR); } rc = smbsr_encode_result(sr, 17, VAR_BCC, "bwbwwllllTwbw#c#c", 17, /* wct */ negprot->ni_index, /* dialect index */ secmode, /* security mode */ negprot->ni_maxmpxcount, /* max MPX */ 1, /* max VCs */ (DWORD)smb_maxbufsize, /* max buffer size */ 0xFFFF, /* max raw size */ sesskey, /* session key */ negprot->ni_capabilities, &negprot->ni_servertime, /* system time */ negprot->ni_tzcorrection, negprot->ni_keylen, /* encryption key length */ VAR_BCC, (int)negprot->ni_keylen, negprot->ni_key, /* encryption key */ wclen, wcbuf); /* nbdomain (unicode) */ smb_msgbuf_term(&mb); break; NT_LM_0_12_ext_sec: /* * This is the "Extended Security" variant of * dialect NT_LM_0_12. */ negprot->ni_capabilities |= CAP_EXTENDED_SECURITY; rc = smbsr_encode_result(sr, 17, VAR_BCC, "bwbwwllllTwbw#c#c", 17, /* wct */ negprot->ni_index, /* dialect index */ secmode, /* security mode */ negprot->ni_maxmpxcount, /* max MPX */ 1, /* max VCs */ (DWORD)smb_maxbufsize, /* max buffer size */ 0xFFFF, /* max raw size */ sesskey, /* session key */ negprot->ni_capabilities, &negprot->ni_servertime, /* system time */ negprot->ni_tzcorrection, 0, /* encryption key length (MBZ) */ VAR_BCC, UUID_LEN, sr->sr_cfg->skc_machine_uuid, sr->sr_cfg->skc_negtok_len, sr->sr_cfg->skc_negtok); break; default: rc = smbsr_encode_result(sr, 1, 0, "bww", 1, -1, 0); break; } if (rc != 0) return (SDRC_ERROR); /* * Save the agreed dialect. Note that the state is also * used to detect and reject attempts to re-negotiate. */ session->dialect = negprot->ni_dialect; session->s_state = SMB_SESSION_STATE_NEGOTIATED; /* Allow normal SMB1 requests now. */ session->newrq_func = smb1sr_newrq; return (SDRC_SUCCESS); }
/* * smb_trans2_mbc_encode * * This function encodes the mbc for one directory entry. * * The function returns -1 when the max data requested by client * is reached. If the entry is valid and successful encoded, 0 * will be returned; otherwise, 1 will be returned. * * We always null terminate the filename. The space for the null * is included in the maxdata calculation and is therefore included * in the next_entry_offset. namelen is the unterminated length of * the filename. For levels except STANDARD and EA_SIZE, if the * 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 */ 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; uint32_t next_entry_offset; uint32_t dsize32, asize32; uint32_t mb_flags = 0; uint32_t resume_key; char buf83[26]; smb_msgbuf_t mb; namelen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_name); if (namelen == -1) return (-1); /* * If ascii the filename length returned to the client should * include the null terminator for levels except STANDARD and * EASIZE. */ if (!(sr->smb_flg2 & SMB_FLAGS2_UNICODE)) { if ((args->fa_infolev != SMB_INFO_STANDARD) && (args->fa_infolev != SMB_INFO_QUERY_EA_SIZE)) namelen += 1; } next_entry_offset = args->fa_maxdata + namelen; if (MBC_ROOM_FOR(&xa->rep_data_mb, (args->fa_maxdata + namelen)) == 0) return (1); 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; resume_key = fileinfo->fi_cookie; if (smbd_use_resume_keys == 0) resume_key = 0; /* * This switch handles all the "information levels" (formats) * that we support. Note that all formats have the file name * placed after some fixed-size data, and the code to write * the file name is factored out at the end of this switch. */ switch (args->fa_infolev) { case SMB_INFO_STANDARD: if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) (void) smb_mbc_encodef(&xa->rep_data_mb, "l", resume_key); (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwb", sr, smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), dsize32, asize32, fileinfo->fi_dosattr, namelen); break; case SMB_INFO_QUERY_EA_SIZE: if (args->fa_fflag & SMB_FIND_RETURN_RESUME_KEYS) (void) smb_mbc_encodef(&xa->rep_data_mb, "l", resume_key); (void) smb_mbc_encodef(&xa->rep_data_mb, "%yyyllwlb", sr, smb_time_gmt_to_local(sr, fileinfo->fi_crtime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_atime.tv_sec), smb_time_gmt_to_local(sr, fileinfo->fi_mtime.tv_sec), dsize32, asize32, fileinfo->fi_dosattr, 0L, /* EA Size */ namelen); break; case SMB_FIND_FILE_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqll", sr, next_entry_offset, resume_key, &fileinfo->fi_crtime, &fileinfo->fi_atime, &fileinfo->fi_mtime, &fileinfo->fi_ctime, fileinfo->fi_size, fileinfo->fi_alloc_size, fileinfo->fi_dosattr, namelen); break; case SMB_FIND_FILE_FULL_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll", sr, next_entry_offset, resume_key, &fileinfo->fi_crtime, &fileinfo->fi_atime, &fileinfo->fi_mtime, &fileinfo->fi_ctime, fileinfo->fi_size, fileinfo->fi_alloc_size, fileinfo->fi_dosattr, namelen, 0L); break; case SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlll4.q", sr, next_entry_offset, resume_key, &fileinfo->fi_crtime, &fileinfo->fi_atime, &fileinfo->fi_mtime, &fileinfo->fi_ctime, fileinfo->fi_size, fileinfo->fi_alloc_size, fileinfo->fi_dosattr, namelen, 0L, fileinfo->fi_nodeid); 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", fileinfo->fi_shortname) < 0) { smb_msgbuf_term(&mb); return (-1); } shortlen = smb_wcequiv_strlen(fileinfo->fi_shortname); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c", sr, next_entry_offset, resume_key, &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); smb_msgbuf_term(&mb); break; case SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO: bzero(buf83, sizeof (buf83)); smb_msgbuf_init(&mb, (uint8_t *)buf83, sizeof (buf83), mb_flags); if (smb_msgbuf_encode(&mb, "u", fileinfo->fi_shortname) < 0) { smb_msgbuf_term(&mb); return (-1); } shortlen = smb_ascii_or_unicode_strlen(sr, fileinfo->fi_shortname); (void) smb_mbc_encodef(&xa->rep_data_mb, "%llTTTTqqlllb.24c2.q", sr, next_entry_offset, resume_key, &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, fileinfo->fi_nodeid); smb_msgbuf_term(&mb); break; case SMB_FIND_FILE_NAMES_INFO: (void) smb_mbc_encodef(&xa->rep_data_mb, "%lll", sr, next_entry_offset, resume_key, namelen); break; default: /* invalid info. level */ return (-1); } /* * At this point we have written all the fixed-size data * for the specified info. level, and we're about to put * the file name string in the message. We may later * need the offset in the trans2 data where this string * is placed, so save the message position now. Note: * We also need to account for the alignment padding * that may precede the unicode string. */ args->fa_lno = xa->rep_data_mb.chain_offset; if ((sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0 && (args->fa_lno & 1) != 0) args->fa_lno++; (void) smb_mbc_encodef(&xa->rep_data_mb, "%u", sr, fileinfo->fi_name); return (0); }
/* * GetPrinterData is used t obtain values from the registry for a * printer or a print server. See [MS-RPRN] for value descriptions. * The registry returns ERROR_FILE_NOT_FOUND for unknown keys. */ static int spoolss_s_GetPrinterData(void *arg, ndr_xa_t *mxa) { static spoolss_winreg_t reg[] = { { "ChangeId", 0x0050acf2 }, { "W3SvcInstalled", 0x00000000 }, { "BeepEnabled", 0x00000000 }, { "EventLog", 0x0000001f }, { "NetPopup", 0x00000000 }, { "NetPopupToComputer", 0x00000000 }, { "MajorVersion", 0x00000003 }, { "MinorVersion", 0x00000000 }, { "DsPresent", 0x00000000 } }; struct spoolss_GetPrinterData *param = arg; char *name = (char *)param->pValueName; char buf[MAXPATHLEN]; static uint8_t reserved_buf[4]; spoolss_winreg_t *rp; smb_share_t si; smb_version_t *osversion; struct utsname sysname; smb_wchar_t *wcs; uint32_t value; uint32_t status; int wcslen; int i; if (name == NULL || *name == '\0') { status = ERROR_FILE_NOT_FOUND; goto report_error; } for (i = 0; i < sizeof (reg) / sizeof (reg[0]); ++i) { param->pType = WINREG_DWORD; param->Needed = sizeof (uint32_t); rp = ®[i]; if (strcasecmp(name, rp->name) != 0) continue; if (param->Size < sizeof (uint32_t)) { param->Size = 0; goto need_more_data; } if ((param->Buf = NDR_NEW(mxa, uint32_t)) == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto report_error; } value = rp->value; if ((strcasecmp(name, "DsPresent") == 0) && (smb_config_get_secmode() == SMB_SECMODE_DOMAIN)) value = 0x00000001; bcopy(&value, param->Buf, sizeof (uint32_t)); param->Size = sizeof (uint32_t); param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } if (strcasecmp(name, "OSVersion") == 0) { param->pType = WINREG_BINARY; param->Needed = sizeof (smb_version_t); if (param->Size < sizeof (smb_version_t)) { param->Size = sizeof (smb_version_t); goto need_more_data; } if ((osversion = NDR_NEW(mxa, smb_version_t)) == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto report_error; } smb_config_get_version(osversion); param->Buf = (uint8_t *)osversion; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); } if (strcasecmp(name, "DNSMachineName") == 0) { param->pType = WINREG_SZ; buf[0] = '\0'; (void) smb_getfqhostname(buf, MAXHOSTNAMELEN); goto encode_string; } if (strcasecmp(name, "DefaultSpoolDirectory") == 0) { param->pType = WINREG_SZ; buf[0] = '\0'; if (smb_shr_get(SMB_SHARE_PRINT, &si) != NERR_Success) { status = ERROR_FILE_NOT_FOUND; goto report_error; } (void) snprintf(buf, MAXPATHLEN, "C:/%s", si.shr_path); (void) strcanon(buf, "/\\"); (void) strsubst(buf, '/', '\\'); goto encode_string; } if (strcasecmp(name, "Architecture") == 0) { param->pType = WINREG_SZ; if (uname(&sysname) < 0) (void) strlcpy(buf, "Solaris", MAXPATHLEN); else (void) snprintf(buf, MAXPATHLEN, "%s %s", sysname.sysname, sysname.machine); goto encode_string; } status = ERROR_FILE_NOT_FOUND; report_error: bzero(param, sizeof (struct spoolss_GetPrinterData)); param->Buf = reserved_buf; param->status = status; return (NDR_DRC_OK); encode_string: wcslen = smb_wcequiv_strlen(buf) + sizeof (smb_wchar_t); if (param->Size < wcslen) { param->Needed = wcslen; goto need_more_data; } if ((wcs = NDR_MALLOC(mxa, wcslen)) == NULL) { status = ERROR_NOT_ENOUGH_MEMORY; goto report_error; } (void) ndr_mbstowcs(NULL, wcs, buf, wcslen); param->Buf = (uint8_t *)wcs; param->Needed = wcslen; param->status = ERROR_SUCCESS; return (NDR_DRC_OK); need_more_data: param->Size = 0; param->Buf = reserved_buf; param->status = ERROR_MORE_DATA; return (NDR_DRC_OK); }