static SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, uint16_t port, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c = NULL; const char *server_n = server; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32_t fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; int flags = 0; struct smbXcli_tcon *tcon = NULL; int signing_state = SMB_SIGNING_DEFAULT; ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && share != NULL && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (!cli_state_has_tcon(srv->cli)) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, smbXcli_conn_remote_name(srv->cli->conn), srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tree_connect(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); status = NT_STATUS_OK; } else { status = cli_get_fs_attr_info(c, &fs_attrs); } if (!NT_STATUS_IS_OK(status)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", nt_errstr(status))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else if (!is_ipc) { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { const char *remote_name = smbXcli_conn_remote_name(srv->cli->conn); srv->dev = (dev_t)(str_checksum(remote_name) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); status = NT_STATUS_UNSUCCESSFUL; if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (smbc_getOptionFallbackAfterKerberos(context)) { flags |= CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS; } if (smbc_getOptionUseCCache(context)) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } if (smbc_getOptionUseNTHash(context)) { flags |= CLI_FULL_CONNECTION_USE_NT_HASH; } if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) { signing_state = SMB_SIGNING_REQUIRED; } if (port == 0) { if (share == NULL || *share == '\0' || is_ipc) { /* * Try 139 first for IPC$ */ status = cli_connect_nb(server_n, NULL, NBT_SMB_PORT, 0x20, smbc_getNetbiosName(context), signing_state, flags, &c); } } if (!NT_STATUS_IS_OK(status)) { /* * No IPC$ or 139 did not work */ status = cli_connect_nb(server_n, NULL, port, 0x20, smbc_getNetbiosName(context), signing_state, flags, &c); } if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); return NULL; } cli_set_timeout(c, smbc_getTimeout(context)); status = smbXcli_negprot(c->conn, c->timeout, lp_client_min_protocol(), lp_client_max_protocol()); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { /* Ensure we ask for some initial credits. */ smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS); } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if (smbXcli_conn_dfs_supported(c->conn) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, port, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tree_connect(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { tcon = c->smb2.tcon; } else { tcon = c->smb1.tcon; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); status = NT_STATUS_OK; } else { status = cli_get_fs_attr_info(c, &fs_attrs); } if (!NT_STATUS_IS_OK(status)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", nt_errstr(status))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else if (!is_ipc) { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); smbXcli_tcon_set_fs_attributes(tcon, fs_attrs); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); DLIST_ADD(srv->cli, c); srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_pathinfo3 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { if (c != NULL) { cli_shutdown(c); } SAFE_FREE(srv); return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
static SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c; struct nmb_name called, calling; const char *server_n = server; struct sockaddr_storage ss; int tried_reverse = 0; int port_try_first; int port_try_next; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32 fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; zero_sockaddr(&ss); ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, srv->cli->desthost, srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tcon_andx(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: zero_sockaddr(&ss); /* have to open a new connection */ if ((c = cli_initialise()) == NULL) { errno = ENOMEM; return NULL; } if (smbc_getOptionUseKerberos(context)) { c->use_kerberos = True; } if (smbc_getOptionFallbackAfterKerberos(context)) { c->fallback_after_kerberos = True; } if (smbc_getOptionUseCCache(context)) { c->use_ccache = True; } c->timeout = smbc_getTimeout(context); /* * Force use of port 139 for first try if share is $IPC, empty, or * null, so browse lists can work */ if (share == NULL || *share == '\0' || is_ipc) { port_try_first = 139; port_try_next = 445; } else { port_try_first = 445; port_try_next = 139; } c->port = port_try_first; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { /* First connection attempt failed. Try alternate port. */ c->port = port_try_next; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } } if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } else { /* Try one more time, but ensure we don't loop */ /* Only try this if server is an IP address ... */ if (is_ipaddress(server) && !tried_reverse) { fstring remote_name; struct sockaddr_storage rem_ss; if (!interpret_string_addr(&rem_ss, server, NI_NUMERICHOST)) { DEBUG(4, ("Could not convert IP address " "%s to struct sockaddr_storage\n", server)); errno = ETIMEDOUT; return NULL; } tried_reverse++; /* Yuck */ if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { make_nmb_name(&called, remote_name, 0x20); goto again; } } } errno = ETIMEDOUT; return NULL; } DEBUG(4,(" session request ok\n")); status = cli_negprot(c); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_session_setup fail with username=[%s], password=[%s]\n", username_used, *pp_password); /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } status = cli_init_creds(c, username_used, *pp_workgroup, *pp_password); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if ((c->capabilities & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tcon_andx(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_tcon_andx return %08X, errno=[%d]\n", NT_STATUS_V(status), errno); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive(c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
int SMBC_fstatvfs_ctx(SMBCCTX *context, SMBCFILE *file, struct statvfs *st) { unsigned long flags = 0; uint32 fs_attrs = 0; struct cli_state *cli = file->srv->cli; /* Initialize all fields (at least until we actually use them) */ memset(st, 0, sizeof(*st)); /* * The state of each flag is such that the same bits are unset as * would typically be unset on a local file system on a POSIX OS. Thus * the bit is on, for example, only for case-insensitive file systems * since most POSIX file systems are case sensitive and fstatvfs() * would typically return zero in these bits on such a local file * system. */ /* See if the server has UNIX CIFS support */ if (! SERVER_HAS_UNIX_CIFS(cli)) { uint64_t total_allocation_units; uint64_t caller_allocation_units; uint64_t actual_allocation_units; uint64_t sectors_per_allocation_unit; uint64_t bytes_per_sector; NTSTATUS status; /* Nope. If size data is available... */ status = cli_get_fs_full_size_info(cli, &total_allocation_units, &caller_allocation_units, &actual_allocation_units, §ors_per_allocation_unit, &bytes_per_sector); if (NT_STATUS_IS_OK(status)) { /* ... then provide it */ st->f_bsize = (unsigned long) bytes_per_sector; #if HAVE_FRSIZE st->f_frsize = (unsigned long) sectors_per_allocation_unit; #endif st->f_blocks = (fsblkcnt_t) total_allocation_units; st->f_bfree = (fsblkcnt_t) actual_allocation_units; } flags |= SMBC_VFS_FEATURE_NO_UNIXCIFS; } else { uint32 optimal_transfer_size; uint32 block_size; uint64_t total_blocks; uint64_t blocks_available; uint64_t user_blocks_available; uint64_t total_file_nodes; uint64_t free_file_nodes; uint64_t fs_identifier; NTSTATUS status; /* Has UNIXCIFS. If POSIX filesystem info is available... */ status = cli_get_posix_fs_info(cli, &optimal_transfer_size, &block_size, &total_blocks, &blocks_available, &user_blocks_available, &total_file_nodes, &free_file_nodes, &fs_identifier); if (NT_STATUS_IS_OK(status)) { /* ... then what's provided here takes precedence. */ st->f_bsize = (unsigned long) block_size; st->f_blocks = (fsblkcnt_t) total_blocks; st->f_bfree = (fsblkcnt_t) blocks_available; st->f_bavail = (fsblkcnt_t) user_blocks_available; st->f_files = (fsfilcnt_t) total_file_nodes; st->f_ffree = (fsfilcnt_t) free_file_nodes; #if HAVE_FSID_INT st->f_fsid = (unsigned long) fs_identifier; #endif } } /* See if the share is case sensitive */ if (!NT_STATUS_IS_OK(cli_get_fs_attr_info(cli, &fs_attrs))) { /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (! smbc_getOptionCaseSensitive(context)) { flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE; } } else { if (! (fs_attrs & FILE_CASE_SENSITIVE_SEARCH)) { flags |= SMBC_VFS_FEATURE_CASE_INSENSITIVE; } } /* See if DFS is supported */ if ((cli_state_capabilities(cli) & CAP_DFS) && cli->dfsroot) { flags |= SMBC_VFS_FEATURE_DFS; } #if HAVE_STATVFS_F_FLAG st->f_flag = flags; #elif HAVE_STATVFS_F_FLAGS st->f_flags = flags; #endif return 0; }
static int parse_quota_set(pstring set_str, pstring username_str, enum SMB_QUOTA_TYPE *qtype, int *cmd, SMB_NTQUOTA_STRUCT *pqt) { char *p = set_str,*p2; int todo; BOOL stop = False; BOOL enable = False; BOOL deny = False; if (strnequal(set_str,"UQLIM:",6)) { p += 6; *qtype = SMB_USER_QUOTA_TYPE; *cmd = QUOTA_SETLIM; todo = PARSE_LIM; if ((p2=strstr(p,":"))==NULL) { return -1; } *p2 = '\0'; p2++; fstrcpy(username_str,p); p = p2; } else if (strnequal(set_str,"FSQLIM:",7)) { p +=7; *qtype = SMB_USER_FS_QUOTA_TYPE; *cmd = QUOTA_SETLIM; todo = PARSE_LIM; } else if (strnequal(set_str,"FSQFLAGS:",9)) { p +=9; todo = PARSE_FLAGS; *qtype = SMB_USER_FS_QUOTA_TYPE; *cmd = QUOTA_SETFLAGS; } else { return -1; } switch (todo) { case PARSE_LIM: #if defined(HAVE_LONGLONG) if (sscanf(p,"%llu/%llu",&pqt->softlim,&pqt->hardlim)!=2) { #else if (sscanf(p,"%lu/%lu",&pqt->softlim,&pqt->hardlim)!=2) { #endif return -1; } break; case PARSE_FLAGS: while (!stop) { if ((p2=strstr(p,"/"))==NULL) { stop = True; } else { *p2 = '\0'; p2++; } if (strnequal(p,"QUOTA_ENABLED",13)) { enable = True; } else if (strnequal(p,"DENY_DISK",9)) { deny = True; } else if (strnequal(p,"LOG_SOFTLIMIT",13)) { pqt->qflags |= QUOTAS_LOG_THRESHOLD; } else if (strnequal(p,"LOG_HARDLIMIT",13)) { pqt->qflags |= QUOTAS_LOG_LIMIT; } else { return -1; } p=p2; } if (deny) { pqt->qflags |= QUOTAS_DENY_DISK; } else if (enable) { pqt->qflags |= QUOTAS_ENABLED; } break; } return 0; } static int do_quota(struct cli_state *cli, enum SMB_QUOTA_TYPE qtype, uint16 cmd, pstring username_str, SMB_NTQUOTA_STRUCT *pqt) { uint32 fs_attrs = 0; int quota_fnum = 0; SMB_NTQUOTA_LIST *qtl = NULL; SMB_NTQUOTA_STRUCT qt; ZERO_STRUCT(qt); if (!cli_get_fs_attr_info(cli, &fs_attrs)) { d_printf("Failed to get the filesystem attributes %s.\n", cli_errstr(cli)); return -1; } if (!(fs_attrs & FILE_VOLUME_QUOTAS)) { d_printf("Quotas are not supported by the server.\n"); return 0; } if (!cli_get_quota_handle(cli, "a_fnum)) { d_printf("Failed to open \\%s %s.\n", FAKE_FILE_NAME_QUOTA,cli_errstr(cli)); return -1; } switch(qtype) { case SMB_USER_QUOTA_TYPE: if (!StringToSid(&qt.sid, username_str)) { d_printf("StringToSid() failed for [%s]\n",username_str); return -1; } switch(cmd) { case QUOTA_GET: if (!cli_get_user_quota(cli, quota_fnum, &qt)) { d_printf("%s cli_get_user_quota %s\n", cli_errstr(cli),username_str); return -1; } dump_ntquota(&qt,verbose,numeric,SidToString); break; case QUOTA_SETLIM: pqt->sid = qt.sid; if (!cli_set_user_quota(cli, quota_fnum, pqt)) { d_printf("%s cli_set_user_quota %s\n", cli_errstr(cli),username_str); return -1; } if (!cli_get_user_quota(cli, quota_fnum, &qt)) { d_printf("%s cli_get_user_quota %s\n", cli_errstr(cli),username_str); return -1; } dump_ntquota(&qt,verbose,numeric,SidToString); break; case QUOTA_LIST: if (!cli_list_user_quota(cli, quota_fnum, &qtl)) { d_printf("%s cli_set_user_quota %s\n", cli_errstr(cli),username_str); return -1; } dump_ntquota_list(&qtl,verbose,numeric,SidToString); free_ntquota_list(&qtl); break; default: d_printf("Unknown Error\n"); return -1; } break; case SMB_USER_FS_QUOTA_TYPE: switch(cmd) { case QUOTA_GET: if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; case QUOTA_SETLIM: if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } qt.softlim = pqt->softlim; qt.hardlim = pqt->hardlim; if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_set_fs_quota_info\n", cli_errstr(cli)); return -1; } if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; case QUOTA_SETFLAGS: if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } qt.qflags = pqt->qflags; if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_set_fs_quota_info\n", cli_errstr(cli)); return -1; } if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; default: d_printf("Unknown Error\n"); return -1; } break; default: d_printf("Unknown Error\n"); return -1; } cli_close(cli, quota_fnum); return 0; }
static int do_quota(struct cli_state *cli, enum SMB_QUOTA_TYPE qtype, uint16_t cmd, const char *username_str, SMB_NTQUOTA_STRUCT *pqt) { uint32_t fs_attrs = 0; uint16_t quota_fnum = 0; SMB_NTQUOTA_LIST *qtl = NULL; TALLOC_CTX *qtl_ctx = NULL; SMB_NTQUOTA_STRUCT qt; NTSTATUS status; ZERO_STRUCT(qt); status = cli_get_fs_attr_info(cli, &fs_attrs); if (!NT_STATUS_IS_OK(status)) { d_printf("Failed to get the filesystem attributes %s.\n", nt_errstr(status)); return -1; } if (!(fs_attrs & FILE_VOLUME_QUOTAS)) { d_printf("Quotas are not supported by the server.\n"); return 0; } status = cli_get_quota_handle(cli, "a_fnum); if (!NT_STATUS_IS_OK(status)) { d_printf("Quotas are not enabled on this share.\n"); d_printf("Failed to open %s %s.\n", FAKE_FILE_NAME_QUOTA_WIN32, nt_errstr(status)); return -1; } switch(qtype) { case SMB_USER_QUOTA_TYPE: if (!StringToSid(&qt.sid, username_str)) { d_printf("StringToSid() failed for [%s]\n",username_str); return -1; } switch(cmd) { case QUOTA_GET: status = cli_get_user_quota( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_user_quota %s\n", nt_errstr(status), username_str); return -1; } dump_ntquota(&qt,verbose,numeric,SidToString); break; case QUOTA_SETLIM: pqt->sid = qt.sid; if ((qtl_ctx = talloc_init( "SMB_USER_QUOTA_SET")) == NULL) { return -1; } if (!add_record_to_ntquota_list( qtl_ctx, pqt, &qtl)) { TALLOC_FREE(qtl_ctx); return -1; } status = cli_set_user_quota( cli, quota_fnum, qtl); free_ntquota_list(&qtl); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_set_user_quota %s\n", nt_errstr(status), username_str); return -1; } status = cli_get_user_quota( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_user_quota %s\n", nt_errstr(status), username_str); return -1; } dump_ntquota(&qt,verbose,numeric,SidToString); break; case QUOTA_LIST: status = cli_list_user_quota( cli, quota_fnum, &qtl); if (!NT_STATUS_IS_OK(status)) { d_printf( "%s cli_list_user_quota\n", nt_errstr(status)); return -1; } dump_ntquota_list(&qtl,verbose,numeric,SidToString); free_ntquota_list(&qtl); break; default: d_printf("Unknown Error\n"); return -1; } break; case SMB_USER_FS_QUOTA_TYPE: switch(cmd) { case QUOTA_GET: status = cli_get_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_fs_quota_info\n", nt_errstr(status)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; case QUOTA_SETLIM: status = cli_get_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_fs_quota_info\n", nt_errstr(status)); return -1; } qt.softlim = pqt->softlim; qt.hardlim = pqt->hardlim; status = cli_set_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_set_fs_quota_info\n", nt_errstr(status)); return -1; } status = cli_get_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_fs_quota_info\n", nt_errstr(status)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; case QUOTA_SETFLAGS: status = cli_get_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_fs_quota_info\n", nt_errstr(status)); return -1; } qt.qflags = pqt->qflags; status = cli_set_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_set_fs_quota_info\n", nt_errstr(status)); return -1; } status = cli_get_fs_quota_info( cli, quota_fnum, &qt); if (!NT_STATUS_IS_OK(status)) { d_printf("%s cli_get_fs_quota_info\n", nt_errstr(status)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; default: d_printf("Unknown Error\n"); return -1; } break; default: d_printf("Unknown Error\n"); return -1; } cli_close(cli, quota_fnum); return 0; }
static int do_quota(struct cli_state *cli, enum SMB_QUOTA_TYPE qtype, uint16 cmd, const char *username_str, SMB_NTQUOTA_STRUCT *pqt) { uint32 fs_attrs = 0; int quota_fnum = 0; SMB_NTQUOTA_LIST *qtl = NULL; SMB_NTQUOTA_STRUCT qt; ZERO_STRUCT(qt); if (!cli_get_fs_attr_info(cli, &fs_attrs)) { d_printf("Failed to get the filesystem attributes %s.\n", cli_errstr(cli)); return -1; } if (!(fs_attrs & FILE_VOLUME_QUOTAS)) { d_printf("Quotas are not supported by the server.\n"); return 0; } if (!cli_get_quota_handle(cli, "a_fnum)) { d_printf("Quotas are not enabled on this share.\n"); d_printf("Failed to open %s %s.\n", FAKE_FILE_NAME_QUOTA_WIN32,cli_errstr(cli)); return -1; } switch(qtype) { case SMB_USER_QUOTA_TYPE: if (!StringToSid(&qt.sid, username_str)) { d_printf("StringToSid() failed for [%s]\n",username_str); return -1; } switch(cmd) { case QUOTA_GET: if (!cli_get_user_quota(cli, quota_fnum, &qt)) { d_printf("%s cli_get_user_quota %s\n", cli_errstr(cli),username_str); return -1; } dump_ntquota(&qt,verbose,numeric,SidToString); break; case QUOTA_SETLIM: pqt->sid = qt.sid; if (!cli_set_user_quota(cli, quota_fnum, pqt)) { d_printf("%s cli_set_user_quota %s\n", cli_errstr(cli),username_str); return -1; } if (!cli_get_user_quota(cli, quota_fnum, &qt)) { d_printf("%s cli_get_user_quota %s\n", cli_errstr(cli),username_str); return -1; } dump_ntquota(&qt,verbose,numeric,SidToString); break; case QUOTA_LIST: if (!cli_list_user_quota(cli, quota_fnum, &qtl)) { d_printf("%s cli_set_user_quota %s\n", cli_errstr(cli),username_str); return -1; } dump_ntquota_list(&qtl,verbose,numeric,SidToString); free_ntquota_list(&qtl); break; default: d_printf("Unknown Error\n"); return -1; } break; case SMB_USER_FS_QUOTA_TYPE: switch(cmd) { case QUOTA_GET: if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; case QUOTA_SETLIM: if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } qt.softlim = pqt->softlim; qt.hardlim = pqt->hardlim; if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_set_fs_quota_info\n", cli_errstr(cli)); return -1; } if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; case QUOTA_SETFLAGS: if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } qt.qflags = pqt->qflags; if (!cli_set_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_set_fs_quota_info\n", cli_errstr(cli)); return -1; } if (!cli_get_fs_quota_info(cli, quota_fnum, &qt)) { d_printf("%s cli_get_fs_quota_info\n", cli_errstr(cli)); return -1; } dump_ntquota(&qt,True,numeric,NULL); break; default: d_printf("Unknown Error\n"); return -1; } break; default: d_printf("Unknown Error\n"); return -1; } cli_close(cli, quota_fnum); return 0; }