2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Server Service (srvsvc) client side RPC library interface. The
2N/A * srvsvc interface allows a client to query a server for information
2N/A * on shares, sessions, connections and files on the server. Some
2N/A * functions are available via anonymous IPC while others require
2N/A * administrator privilege. Also, some functions return NT status
2N/A * values while others return Win32 errors codes.
2N/A */
2N/A
2N/A#include <sys/errno.h>
2N/A#include <stdio.h>
2N/A#include <time.h>
2N/A#include <strings.h>
2N/A
2N/A#include <smbsrv/libsmb.h>
2N/A#include <smbsrv/libntsvcs.h>
2N/A#include <smbsrv/smbinfo.h>
2N/A#include <smbsrv/ndl/srvsvc.ndl>
2N/A
2N/A/*
2N/A * Information level for NetShareGetInfo.
2N/A */
2N/ADWORD srvsvc_info_level = 1;
2N/Astatic void srvsvc_net_free(srvsvc_info_t *);
2N/Astatic int srvsvc_gettime_core(struct timeval *, struct tm *);
2N/A
2N/A/*
2N/A * Bind to the the SRVSVC.
2N/A *
2N/A * If username argument is NULL, an anonymous connection will be established.
2N/A * Otherwise, an authenticated connection will be established.
2N/A */
2N/Astatic int
2N/Asrvsvc_open(char *server, char *domain, char *username, mlsvc_handle_t *handle)
2N/A{
2N/A smb_domainex_t di;
2N/A
2N/A if (server == NULL || domain == NULL) {
2N/A if (!smb_domain_getinfo(&di))
2N/A return (-1);
2N/A
2N/A server = di.d_dc;
2N/A domain = di.d_primary.di_nbname;
2N/A }
2N/A
2N/A if (ndr_rpc_bind(handle, server, domain, username, "SRVSVC") < 0)
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Unbind the SRVSVC connection.
2N/A */
2N/Astatic void
2N/Asrvsvc_close(mlsvc_handle_t *handle)
2N/A{
2N/A ndr_rpc_unbind(handle);
2N/A}
2N/A
2N/Astatic srvsvc_info_t *
2N/Asrvsvc_net_enum_add(srvsvc_list_t *sl, uint32_t type)
2N/A{
2N/A srvsvc_info_t *info;
2N/A
2N/A if ((info = calloc(1, sizeof (srvsvc_info_t))) == NULL)
2N/A return (NULL);
2N/A
2N/A info->l_type = type;
2N/A list_insert_tail(&sl->sl_list, info);
2N/A ++sl->sl_count;
2N/A return (info);
2N/A}
2N/A
2N/Astatic void
2N/Asrvsvc_net_enum_remove(srvsvc_list_t *sl, srvsvc_info_t *si)
2N/A{
2N/A list_remove(&sl->sl_list, si);
2N/A --sl->sl_count;
2N/A srvsvc_net_free(si);
2N/A free(si);
2N/A}
2N/A
2N/Astatic void
2N/Asrvsvc_net_free(srvsvc_info_t *info)
2N/A{
2N/A srvsvc_share_info_t *si;
2N/A srvsvc_session_info_t *ss;
2N/A srvsvc_connect_info_t *sc;
2N/A srvsvc_file_info_t *sf;
2N/A
2N/A switch (info->l_type) {
2N/A case SMB_SVCENUM_TYPE_USER:
2N/A ss = &info->l_list.ul_session;
2N/A free(ss->ui_account);
2N/A free(ss->ui_workstation);
2N/A bzero(ss, sizeof (srvsvc_session_info_t));
2N/A break;
2N/A case SMB_SVCENUM_TYPE_TREE:
2N/A sc = &info->l_list.ul_connection;
2N/A free(sc->ci_share);
2N/A free(sc->ci_username);
2N/A bzero(sc, sizeof (srvsvc_connect_info_t));
2N/A break;
2N/A case SMB_SVCENUM_TYPE_FILE:
2N/A sf = &info->l_list.ul_file;
2N/A free(sf->fi_path);
2N/A free(sf->fi_username);
2N/A bzero(sf, sizeof (srvsvc_file_info_t));
2N/A break;
2N/A case SMB_SVCENUM_TYPE_SHARE:
2N/A si = &info->l_list.ul_shr;
2N/A free(si->si_netname);
2N/A free(si->si_comment);
2N/A free(si->si_path);
2N/A free(si->si_servername);
2N/A bzero(si, sizeof (srvsvc_share_info_t));
2N/A break;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * This is a client side routine for NetShareGetInfo enumeration.
2N/A * Only level 1 request is supported.
2N/A */
2N/Aint
2N/Asrvsvc_net_share_enum(char *server, char *domain, uint32_t level,
2N/A srvsvc_list_t *sl)
2N/A{
2N/A typedef struct mslm_infonres srvsvc_infonres_t;
2N/A
2N/A struct mslm_NetShareEnum arg;
2N/A mlsvc_handle_t handle;
2N/A srvsvc_infonres_t infonres;
2N/A srvsvc_infonres_t *result;
2N/A struct mslm_NetShareInfo_1 *info1;
2N/A srvsvc_info_t *info;
2N/A srvsvc_share_info_t *si;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A char *comment;
2N/A int opnum;
2N/A int rc;
2N/A int i;
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if (srvsvc_open(server, domain, user, &handle) != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetShareEnum;
2N/A bzero(&arg, sizeof (struct mslm_NetShareEnum));
2N/A bzero(&infonres, sizeof (srvsvc_infonres_t));
2N/A
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A arg.level = level; /* share information level */
2N/A arg.result.level = level;
2N/A arg.result.bufptr.p = &infonres;
2N/A arg.prefmaxlen = (uint32_t)-1;
2N/A
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if (rc != 0) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A if ((arg.status != 0) && (arg.status != ERROR_MORE_DATA)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A result = (srvsvc_infonres_t *)arg.result.bufptr.p;
2N/A info1 = (struct mslm_NetShareInfo_1 *)result->entries;
2N/A
2N/A sl->sl_level = level;
2N/A sl->sl_totalentries = arg.totalentries;
2N/A sl->sl_entriesread = result->entriesread;
2N/A
2N/A for (i = 0; i < result->entriesread && i < arg.totalentries; ++i) {
2N/A if (info1[i].shi1_comment == NULL)
2N/A comment = "";
2N/A else
2N/A comment = (char *)info1[i].shi1_comment;
2N/A
2N/A if ((info = srvsvc_net_enum_add(sl,
2N/A SMB_SVCENUM_TYPE_SHARE)) != NULL) {
2N/A si = &info->l_list.ul_shr;
2N/A si->si_netname = strdup((char *)info1[i].shi1_netname);
2N/A si->si_comment = strdup(comment);
2N/A si->si_type = info1[i].shi1_type;
2N/A
2N/A if (si->si_netname == NULL || si->si_comment == NULL)
2N/A srvsvc_net_enum_remove(sl, info);
2N/A }
2N/A }
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * This is a client side routine for NetShareGetInfo.
2N/A * Levels 0 and 1 work with an anonymous connection but
2N/A * level 2 requires administrator access.
2N/A */
2N/Aint
2N/Asrvsvc_net_share_get_info(char *server, char *domain, char *netname,
2N/A uint32_t level, srvsvc_share_info_t *si)
2N/A{
2N/A struct mlsm_NetShareGetInfo arg;
2N/A mlsvc_handle_t handle;
2N/A int rc;
2N/A int opnum;
2N/A struct mslm_NetShareInfo_0 *info0;
2N/A struct mslm_NetShareInfo_1 *info1;
2N/A struct mslm_NetShareInfo_2 *info2;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A if (netname == NULL || si == NULL)
2N/A return (-1);
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if (srvsvc_open(server, domain, user, &handle) != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetShareGetInfo;
2N/A bzero(&arg, sizeof (struct mlsm_NetShareGetInfo));
2N/A
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A arg.netname = (LPTSTR)netname;
2N/A arg.level = level; /* share information level */
2N/A
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if ((rc != 0) || (arg.status != 0)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A bzero(si, sizeof (srvsvc_share_info_t));
2N/A
2N/A switch (arg.result.switch_value) {
2N/A case 0:
2N/A info0 = arg.result.ru.info0;
2N/A si->si_netname = strdup((char *)info0->shi0_netname);
2N/A break;
2N/A
2N/A case 1:
2N/A info1 = arg.result.ru.info1;
2N/A si->si_netname = strdup((char *)info1->shi1_netname);
2N/A si->si_type = info1->shi1_type;
2N/A
2N/A if (info1->shi1_comment)
2N/A si->si_comment = strdup((char *)info1->shi1_comment);
2N/A break;
2N/A
2N/A case 2:
2N/A info2 = arg.result.ru.info2;
2N/A si->si_netname = strdup((char *)info2->shi2_netname);
2N/A si->si_type = info2->shi2_type;
2N/A si->si_permissions = info2->shi2_permissions;
2N/A si->si_max_uses = info2->shi2_max_uses;
2N/A si->si_current_uses = info2->shi2_current_uses;
2N/A
2N/A if (info2->shi2_comment)
2N/A si->si_comment = strdup((char *)info2->shi2_comment);
2N/A
2N/A if (info2->shi2_path)
2N/A si->si_path = strdup((char *)info2->shi2_path);
2N/A
2N/A break;
2N/A
2N/A default:
2N/A smb_tracef("srvsvc: unknown level");
2N/A break;
2N/A }
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * This is a client side routine for NetFilesEnum.
2N/A * NetFilesEnum requires administrator rights.
2N/A * Level 2 and 3 requests are supported.
2N/A *
2N/A * The basepath parameter specifies a qualifier for the returned information.
2N/A * If this parameter is not NULL, the server MUST enumerate only resources that
2N/A * have basepath as a prefix.
2N/A *
2N/A * If username parameter is specified, the server MUST limit the files returned
2N/A * to those that were opened by a session whose user name matches username.
2N/A */
2N/Aint
2N/Asrvsvc_net_files_enum(char *server, char *domain, char *basepath,
2N/A char *username, uint32_t level, srvsvc_list_t *sl)
2N/A{
2N/A struct mslm_NetFileEnum arg;
2N/A mlsvc_handle_t handle;
2N/A int rc, opnum, i;
2N/A struct mslm_NetFileInfo2 info2;
2N/A struct mslm_NetFileInfo3 info3;
2N/A struct mslm_NetFileInfo2 *result2;
2N/A struct mslm_NetFileInfo3 *result3;
2N/A struct mslm_NetFileInfoBuf2 *fib2;
2N/A struct mslm_NetFileInfoBuf3 *fib3;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A srvsvc_file_info_t *sf;
2N/A srvsvc_info_t *info;
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A rc = srvsvc_open(server, domain, user, &handle);
2N/A if (rc != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetFileEnum;
2N/A bzero(&arg, sizeof (struct mslm_NetFileEnum));
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A if (basepath != NULL)
2N/A arg.basepath = (LPTSTR)basepath;
2N/A
2N/A if (username != NULL)
2N/A arg.username = (LPTSTR)username;
2N/A
2N/A arg.info.level = arg.info.switch_value = level;
2N/A arg.resume_handle = NULL;
2N/A arg.pref_max_len = (uint32_t)-1;
2N/A switch (level) {
2N/A case 2:
2N/A bzero(&info2, sizeof (struct mslm_NetFileInfo2));
2N/A arg.info.ru.info2 = &info2;
2N/A break;
2N/A case 3:
2N/A bzero(&info3, sizeof (struct mslm_NetFileInfo3));
2N/A arg.info.ru.info3 = &info3;
2N/A break;
2N/A default:
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if ((rc != 0) || (arg.status != 0)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A sl->sl_level = arg.info.switch_value;
2N/A sl->sl_totalentries = arg.total_entries;
2N/A switch (level) {
2N/A case 2:
2N/A result2 = (struct mslm_NetFileInfo2 *)arg.info.ru.info2;
2N/A fib2 = (struct mslm_NetFileInfoBuf2 *)result2->fi2;
2N/A sl->sl_entriesread = result2->entries_read;
2N/A for (i = 0; i < sl->sl_entriesread &&
2N/A i < sl->sl_totalentries; ++i) {
2N/A if ((info = srvsvc_net_enum_add(sl,
2N/A SMB_SVCENUM_TYPE_FILE)) != NULL) {
2N/A sf = &info->l_list.ul_file;
2N/A sf->fi_fid = fib2[i].fi2_id;
2N/A }
2N/A }
2N/A break;
2N/A case 3:
2N/A result3 = (struct mslm_NetFileInfo3 *)arg.info.ru.info3;
2N/A fib3 = (struct mslm_NetFileInfoBuf3 *)result3->fi3;
2N/A sl->sl_entriesread = result3->entries_read;
2N/A for (i = 0; i < sl->sl_entriesread &&
2N/A i < sl->sl_totalentries; ++i) {
2N/A if ((fib3[i].fi3_username == NULL) ||
2N/A (fib3[i].fi3_pathname == NULL))
2N/A break;
2N/A
2N/A if ((info = srvsvc_net_enum_add(sl,
2N/A SMB_SVCENUM_TYPE_FILE)) != NULL) {
2N/A sf = &info->l_list.ul_file;
2N/A sf->fi_username =
2N/A strdup((char *)fib3[i].fi3_username);
2N/A sf->fi_path =
2N/A strdup((char *)fib3[i].fi3_pathname);
2N/A sf->fi_fid = fib3[i].fi3_id;
2N/A sf->fi_permissions = fib3[i].fi3_permissions;
2N/A sf->fi_numlocks = fib3[i].fi3_num_locks;
2N/A
2N/A if (sf->fi_path == NULL ||
2N/A sf->fi_username == NULL)
2N/A srvsvc_net_enum_remove(sl, info);
2N/A }
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A rc = -1;
2N/A break;
2N/A }
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * This is a client side routine for NetConnectEnum.
2N/A * NetConnectEnum requires administrator rights.
2N/A * Level 0 and 1 requests are supported.
2N/A *
2N/A * The qualifier parameter specifies a share name or computer name for
2N/A * connections of interest to the client. Qualifiers that begin with \\ are
2N/A * considered server names and anything else is considered a share name.
2N/A * Share names MUST NOT begin with \\.
2N/A *
2N/A * The qualifier parameter must not be NULL.
2N/A */
2N/Aint
2N/Asrvsvc_net_connect_enum(char *server, char *domain, char *qualifier,
2N/A uint32_t level, srvsvc_list_t *sl)
2N/A{
2N/A struct mslm_NetConnectEnum arg;
2N/A mlsvc_handle_t handle;
2N/A int rc, i, opnum;
2N/A struct mslm_NetConnectInfo0 info0;
2N/A struct mslm_NetConnectInfo1 info1;
2N/A struct mslm_NetConnectInfo0 *result0;
2N/A struct mslm_NetConnectInfo1 *result1;
2N/A struct mslm_NetConnectInfoBuf0 *cib0;
2N/A struct mslm_NetConnectInfoBuf1 *cib1;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A srvsvc_connect_info_t *sc;
2N/A srvsvc_info_t *info;
2N/A
2N/A if (qualifier == NULL)
2N/A return (-1);
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A rc = srvsvc_open(server, domain, user, &handle);
2N/A if (rc != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetConnectEnum;
2N/A bzero(&arg, sizeof (struct mslm_NetConnectEnum));
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A arg.qualifier = (LPTSTR)qualifier;
2N/A arg.resume_handle = NULL;
2N/A arg.pref_max_len = (uint32_t)-1;
2N/A arg.info.level = arg.info.switch_value = level;
2N/A switch (level) {
2N/A case 0:
2N/A bzero(&info0, sizeof (struct mslm_NetConnectInfo0));
2N/A arg.info.ru.info0 = &info0;
2N/A break;
2N/A case 1:
2N/A bzero(&info1, sizeof (struct mslm_NetConnectInfo1));
2N/A arg.info.ru.info1 = &info1;
2N/A break;
2N/A default:
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if ((rc != 0) || (arg.status != 0)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A sl->sl_level = arg.info.switch_value;
2N/A sl->sl_totalentries = arg.total_entries;
2N/A switch (level) {
2N/A case 0:
2N/A result0 = (struct mslm_NetConnectInfo0 *)arg.info.ru.info0;
2N/A cib0 = (struct mslm_NetConnectInfoBuf0 *)result0->ci0;
2N/A sl->sl_entriesread = result0->entries_read;
2N/A for (i = 0; i < sl->sl_entriesread &&
2N/A i < sl->sl_totalentries; ++i) {
2N/A if ((info = srvsvc_net_enum_add(sl,
2N/A SMB_SVCENUM_TYPE_TREE)) != NULL) {
2N/A sc = &info->l_list.ul_connection;
2N/A sc->ci_id = cib0[i].coni0_id;
2N/A }
2N/A }
2N/A break;
2N/A case 1:
2N/A result1 = (struct mslm_NetConnectInfo1 *)arg.info.ru.info1;
2N/A cib1 = (struct mslm_NetConnectInfoBuf1 *)result1->ci1;
2N/A sl->sl_entriesread = result1->entries_read;
2N/A for (i = 0; i < sl->sl_entriesread &&
2N/A i < sl->sl_totalentries; ++i) {
2N/A if ((cib1[i].coni1_username == NULL) ||
2N/A (cib1[i].coni1_netname == NULL))
2N/A break;
2N/A
2N/A if ((info = srvsvc_net_enum_add(sl,
2N/A SMB_SVCENUM_TYPE_TREE)) != NULL) {
2N/A sc = &info->l_list.ul_connection;
2N/A sc->ci_username =
2N/A strdup((char *)cib1[i].coni1_username);
2N/A sc->ci_share =
2N/A strdup((char *)cib1[i].coni1_netname);
2N/A sc->ci_numopens = cib1[i].coni1_num_opens;
2N/A sc->ci_time = cib1[i].coni1_time;
2N/A sc->ci_numusers = cib1[i].coni1_num_users;
2N/A
2N/A if (sc->ci_username == NULL ||
2N/A sc->ci_share == NULL)
2N/A srvsvc_net_enum_remove(sl, info);
2N/A }
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A rc = -1;
2N/A break;
2N/A }
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * This is a client side routine for NetSessionEnum.
2N/A * NetSessionEnum requires administrator rights.
2N/A * Only level 1 request is supported.
2N/A *
2N/A * The clientname parameter specifies a qualifier for the returned information.
2N/A * If a clientname is specified (i.e. it is not a NULL (zero-length) string),
2N/A * the client computer name MUST match the ClientName for the session to be
2N/A * returned. If a clientname is specified, it MUST start with "\\".
2N/A *
2N/A * The username parameter specifies a qualifier for the returned information.
2N/A * If a username is specified (that is, not a NULL (zero-length) string), the
2N/A * user name MUST match the username parameter for the session to be returned.
2N/A */
2N/Aint
2N/Asrvsvc_net_session_enum(char *server, char *domain, char *clientname,
2N/A char *username, uint32_t level, srvsvc_list_t *sl)
2N/A{
2N/A struct mslm_NetSessionEnum arg;
2N/A mlsvc_handle_t handle;
2N/A int rc, i, opnum;
2N/A struct mslm_infonres infonres;
2N/A struct mslm_infonres *result;
2N/A struct mslm_SESSION_INFO_1 *nsi1;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A srvsvc_session_info_t *ss;
2N/A srvsvc_info_t *info;
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A rc = srvsvc_open(server, domain, user, &handle);
2N/A if (rc != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetSessionEnum;
2N/A bzero(&arg, sizeof (struct mslm_NetSessionEnum));
2N/A bzero(&infonres, sizeof (struct mslm_infonres));
2N/A
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A if (clientname != NULL)
2N/A arg.clientname = (LPTSTR)clientname;
2N/A
2N/A if (username != NULL)
2N/A arg.username = (LPTSTR)username;
2N/A
2N/A arg.level = level;
2N/A arg.result.level = level;
2N/A arg.result.bufptr.p = &infonres;
2N/A arg.resume_handle = NULL;
2N/A arg.pref_max_len = (uint32_t)-1;
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if ((rc != 0) || (arg.status != 0)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A result = (struct mslm_infonres *)arg.result.bufptr.p;
2N/A nsi1 = (struct mslm_SESSION_INFO_1 *)result->entries;
2N/A
2N/A sl->sl_level = arg.result.level;
2N/A sl->sl_totalentries = arg.total_entries;
2N/A sl->sl_entriesread = result->entriesread;
2N/A for (i = 0; i < sl->sl_entriesread && i < sl->sl_totalentries; ++i) {
2N/A if ((info = srvsvc_net_enum_add(sl,
2N/A SMB_SVCENUM_TYPE_USER)) != NULL) {
2N/A ss = &info->l_list.ul_session;
2N/A ss->ui_account =
2N/A strdup((char *)nsi1[i].sesi1_uname);
2N/A ss->ui_workstation =
2N/A strdup((char *)nsi1[i].sesi1_cname);
2N/A ss->ui_logon_time = nsi1[i].sesi1_time;
2N/A ss->ui_numopens = nsi1[i].sesi1_nopens;
2N/A ss->ui_flags = nsi1[i].sesi1_uflags;
2N/A
2N/A if (ss->ui_account == NULL ||
2N/A ss->ui_workstation == NULL)
2N/A srvsvc_net_enum_remove(sl, info);
2N/A }
2N/A }
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Windows 95+ and Windows NT4.0 both report the version as 4.0.
2N/A * Windows 2000+ reports the version as 5.x.
2N/A */
2N/Aint
2N/Asrvsvc_net_server_getinfo(char *server, char *domain,
2N/A srvsvc_server_info_t *svinfo)
2N/A{
2N/A mlsvc_handle_t handle;
2N/A struct mslm_NetServerGetInfo arg;
2N/A struct mslm_SERVER_INFO_101 *sv101;
2N/A int opnum, rc;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A if (srvsvc_open(server, domain, user, &handle) != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetServerGetInfo;
2N/A bzero(&arg, sizeof (arg));
2N/A
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A arg.level = 101;
2N/A
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if ((rc != 0) || (arg.status != 0)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A sv101 = arg.result.bufptr.bufptr101;
2N/A
2N/A bzero(svinfo, sizeof (srvsvc_server_info_t));
2N/A svinfo->sv_platform_id = sv101->sv101_platform_id;
2N/A svinfo->sv_version_major = sv101->sv101_version_major;
2N/A svinfo->sv_version_minor = sv101->sv101_version_minor;
2N/A svinfo->sv_type = sv101->sv101_type;
2N/A if (sv101->sv101_name)
2N/A svinfo->sv_name = strdup((char *)sv101->sv101_name);
2N/A if (sv101->sv101_comment)
2N/A svinfo->sv_comment = strdup((char *)sv101->sv101_comment);
2N/A
2N/A if (svinfo->sv_type & SV_TYPE_WFW)
2N/A svinfo->sv_os = NATIVE_OS_WIN95;
2N/A if (svinfo->sv_type & SV_TYPE_WINDOWS)
2N/A svinfo->sv_os = NATIVE_OS_WIN95;
2N/A if ((svinfo->sv_type & SV_TYPE_NT) ||
2N/A (svinfo->sv_type & SV_TYPE_SERVER_NT))
2N/A svinfo->sv_os = NATIVE_OS_WINNT;
2N/A if (svinfo->sv_version_major > 4)
2N/A svinfo->sv_os = NATIVE_OS_WIN2000;
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * NetRemoteTOD to get the current GMT time from a Windows NT server.
2N/A */
2N/Aint
2N/Asrvsvc_gettime(unsigned long *t)
2N/A{
2N/A struct timeval tv;
2N/A struct tm tm;
2N/A
2N/A if (srvsvc_gettime_core(&tv, &tm) != 0)
2N/A return (-1);
2N/A
2N/A *t = tv.tv_sec;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Wrapper function for srvsvc_net_remote_tod() that gets the time and
2N/A * date from the selected DC. The time information is returned in
2N/A * the timeval and tm.
2N/A *
2N/A * Upon detection of a DC failure, reports the failed DC to DC failover
2N/A * service and retries with a newly selected DC after DC failover completes.
2N/A */
2N/Astatic int
2N/Asrvsvc_gettime_core(struct timeval *tv, struct tm *tm)
2N/A{
2N/A smb_domainex_t di;
2N/A int rc;
2N/A int i = 0;
2N/A
2N/A do {
2N/A if (!smb_domain_getinfo(&di))
2N/A return (-1);
2N/A
2N/A errno = 0;
2N/A rc = srvsvc_net_remote_tod(di.d_dc, di.d_primary.di_nbname, tv,
2N/A tm);
2N/A
2N/A if (rc == 0)
2N/A break;
2N/A
2N/A if (!ntsvcs_srv_down(errno))
2N/A break;
2N/A
2N/A smb_dc_report_failure(di.d_primary.di_fqname, di.d_dc);
2N/A
2N/A } while (i++ < SMB_MAX_DC_FAILURES);
2N/A
2N/A return (rc);
2N/A}
2N/A
2N/A/*
2N/A * This is a client side routine for NetRemoteTOD, which gets the time
2N/A * and date from a remote system. The time information is returned in
2N/A * the timeval and tm.
2N/A *
2N/A * typedef struct _TIME_OF_DAY_INFO {
2N/A * DWORD tod_elapsedt; // seconds since 00:00:00 January 1 1970 GMT
2N/A * DWORD tod_msecs; // arbitrary milliseconds (since reset)
2N/A * DWORD tod_hours; // current hour [0-23]
2N/A * DWORD tod_mins; // current minute [0-59]
2N/A * DWORD tod_secs; // current second [0-59]
2N/A * DWORD tod_hunds; // current hundredth (0.01) second [0-99]
2N/A * LONG tod_timezone; // time zone of the server
2N/A * DWORD tod_tinterval; // clock tick time interval
2N/A * DWORD tod_day; // day of the month [1-31]
2N/A * DWORD tod_month; // month of the year [1-12]
2N/A * DWORD tod_year; // current year
2N/A * DWORD tod_weekday; // day of the week since sunday [0-6]
2N/A * } TIME_OF_DAY_INFO;
2N/A *
2N/A * The time zone of the server is calculated in minutes from Greenwich
2N/A * Mean Time (GMT). For time zones west of Greenwich, the value is
2N/A * positive; for time zones east of Greenwich, the value is negative.
2N/A * A value of -1 indicates that the time zone is undefined.
2N/A *
2N/A * The clock tick value represents a resolution of one ten-thousandth
2N/A * (0.0001) second.
2N/A */
2N/Aint
2N/Asrvsvc_net_remote_tod(char *server, char *domain, struct timeval *tv,
2N/A struct tm *tm)
2N/A{
2N/A struct mslm_NetRemoteTOD arg;
2N/A struct mslm_TIME_OF_DAY_INFO *tod;
2N/A mlsvc_handle_t handle;
2N/A int rc;
2N/A int opnum;
2N/A char user[SMB_USERNAME_MAXLEN];
2N/A
2N/A smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
2N/A
2N/A rc = srvsvc_open(server, domain, user, &handle);
2N/A if (rc != 0)
2N/A return (-1);
2N/A
2N/A opnum = SRVSVC_OPNUM_NetRemoteTOD;
2N/A bzero(&arg, sizeof (struct mslm_NetRemoteTOD));
2N/A
2N/A arg.servername = ndr_rpc_derive_nbhandle(&handle, server);
2N/A if (arg.servername == NULL) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A rc = ndr_rpc_call(&handle, opnum, &arg);
2N/A if ((rc != 0) || (arg.status != 0)) {
2N/A srvsvc_close(&handle);
2N/A return (-1);
2N/A }
2N/A
2N/A /*
2N/A * We're assigning milliseconds to microseconds
2N/A * here but the value's not really relevant.
2N/A */
2N/A tod = arg.bufptr;
2N/A
2N/A if (tv) {
2N/A tv->tv_sec = tod->tod_elapsedt;
2N/A tv->tv_usec = tod->tod_msecs;
2N/A }
2N/A
2N/A if (tm) {
2N/A tm->tm_sec = tod->tod_secs;
2N/A tm->tm_min = tod->tod_mins;
2N/A tm->tm_hour = tod->tod_hours;
2N/A tm->tm_mday = tod->tod_day;
2N/A tm->tm_mon = tod->tod_month - 1;
2N/A tm->tm_year = tod->tod_year - 1900;
2N/A tm->tm_wday = tod->tod_weekday;
2N/A }
2N/A
2N/A ndr_rpc_release(&handle);
2N/A srvsvc_close(&handle);
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Asrvsvc_net_enum_init(srvsvc_list_t *sl)
2N/A{
2N/A list_create(&sl->sl_list, sizeof (srvsvc_info_t),
2N/A offsetof(srvsvc_info_t, l_lnd));
2N/A sl->sl_count = 0;
2N/A}
2N/A
2N/Avoid
2N/Asrvsvc_net_enum_fini(srvsvc_list_t *sl)
2N/A{
2N/A list_t *lst;
2N/A srvsvc_info_t *info;
2N/A
2N/A if (sl == NULL)
2N/A return;
2N/A
2N/A lst = &sl->sl_list;
2N/A while ((info = list_head(lst)) != NULL) {
2N/A list_remove(lst, info);
2N/A srvsvc_net_free(info);
2N/A free(info);
2N/A }
2N/A list_destroy(lst);
2N/A sl->sl_count = 0;
2N/A}
2N/A
2N/Avoid
2N/Asrvsvc_net_test(char *server, char *domain, char *netname)
2N/A{
2N/A smb_domainex_t di;
2N/A srvsvc_server_info_t svinfo;
2N/A srvsvc_share_info_t shinfo;
2N/A
2N/A (void) smb_tracef("%s %s %s", server, domain, netname);
2N/A
2N/A if (smb_domain_getinfo(&di)) {
2N/A server = di.d_dc;
2N/A domain = di.d_primary.di_nbname;
2N/A }
2N/A
2N/A if (srvsvc_net_server_getinfo(server, domain, &svinfo) == 0) {
2N/A smb_tracef("NetServerGetInfo: %s %s (%d.%d) id=%d type=0x%08x",
2N/A svinfo.sv_name ? svinfo.sv_name : "NULL",
2N/A svinfo.sv_comment ? svinfo.sv_comment : "NULL",
2N/A svinfo.sv_version_major, svinfo.sv_version_minor,
2N/A svinfo.sv_platform_id, svinfo.sv_type);
2N/A
2N/A free(svinfo.sv_name);
2N/A free(svinfo.sv_comment);
2N/A }
2N/A
2N/A if (srvsvc_net_share_get_info(server, domain, netname,
2N/A srvsvc_info_level, &shinfo) == 0) {
2N/A smb_tracef("NetShareGetInfo: %s %s %s (type=%d) %s",
2N/A shinfo.si_netname ? shinfo.si_netname : "NULL",
2N/A shinfo.si_path ? shinfo.si_path : "NULL",
2N/A shinfo.si_servername ? shinfo.si_servername : "NULL",
2N/A shinfo.si_type,
2N/A shinfo.si_comment ? shinfo.si_comment : "NULL");
2N/A }
2N/A}