staticint cifs_swn_auth_info_krb(struct cifs_tcon *tcon, struct sk_buff *skb)
{ int ret;
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_KRB_AUTH); if (ret < 0) return ret;
return 0;
}
staticint cifs_swn_auth_info_ntlm(struct cifs_tcon *tcon, struct sk_buff *skb)
{ int ret;
if (tcon->ses->user_name != NULL) {
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_USER_NAME, tcon->ses->user_name); if (ret < 0) return ret;
}
if (tcon->ses->password != NULL) {
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_PASSWORD, tcon->ses->password); if (ret < 0) return ret;
}
if (tcon->ses->domainName != NULL) {
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_DOMAIN_NAME, tcon->ses->domainName); if (ret < 0) return ret;
}
return 0;
}
/* * Sends a register message to the userspace daemon based on the registration. * The authentication information to connect to the witness service is bundled * into the message.
*/ staticint cifs_swn_send_register_message(struct cifs_swn_reg *swnreg)
{ struct sk_buff *skb; struct genlmsghdr *hdr; enum securityEnum authtype; struct sockaddr_storage *addr; int ret;
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (skb == NULL) {
ret = -ENOMEM; goto fail;
}
hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_REGISTER); if (hdr == NULL) {
ret = -ENOMEM; goto nlmsg_fail;
}
ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); if (ret < 0) goto nlmsg_fail;
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); if (ret < 0) goto nlmsg_fail;
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); if (ret < 0) goto nlmsg_fail;
/* * If there is an address stored use it instead of the server address, because we are * in the process of reconnecting to it after a share has been moved or we have been * told to switch to it (client move message). In these cases we unregister from the * server address and register to the new address when we receive the notification.
*/ if (swnreg->tcon->ses->server->use_swn_dstaddr)
addr = &swnreg->tcon->ses->server->swn_dstaddr; else
addr = &swnreg->tcon->ses->server->dstaddr;
ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage), addr); if (ret < 0) goto nlmsg_fail;
if (swnreg->net_name_notify) {
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); if (ret < 0) goto nlmsg_fail;
}
if (swnreg->share_name_notify) {
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); if (ret < 0) goto nlmsg_fail;
}
if (swnreg->ip_notify) {
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); if (ret < 0) goto nlmsg_fail;
}
authtype = cifs_select_sectype(swnreg->tcon->ses->server, swnreg->tcon->ses->sectype); switch (authtype) { case Kerberos:
ret = cifs_swn_auth_info_krb(swnreg->tcon, skb); if (ret < 0) {
cifs_dbg(VFS, "%s: Failed to get kerberos auth info: %d\n", __func__, ret); goto nlmsg_fail;
} break; case NTLMv2: case RawNTLMSSP:
ret = cifs_swn_auth_info_ntlm(swnreg->tcon, skb); if (ret < 0) {
cifs_dbg(VFS, "%s: Failed to get NTLM auth info: %d\n", __func__, ret); goto nlmsg_fail;
} break; default:
cifs_dbg(VFS, "%s: secType %d not supported!\n", __func__, authtype);
ret = -EINVAL; goto nlmsg_fail;
}
/* * Sends an uregister message to the userspace daemon based on the registration
*/ staticint cifs_swn_send_unregister_message(struct cifs_swn_reg *swnreg)
{ struct sk_buff *skb; struct genlmsghdr *hdr; int ret;
skb = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (skb == NULL) return -ENOMEM;
hdr = genlmsg_put(skb, 0, 0, &cifs_genl_family, 0, CIFS_GENL_CMD_SWN_UNREGISTER); if (hdr == NULL) {
ret = -ENOMEM; goto nlmsg_fail;
}
ret = nla_put_u32(skb, CIFS_GENL_ATTR_SWN_REGISTRATION_ID, swnreg->id); if (ret < 0) goto nlmsg_fail;
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_NET_NAME, swnreg->net_name); if (ret < 0) goto nlmsg_fail;
ret = nla_put_string(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME, swnreg->share_name); if (ret < 0) goto nlmsg_fail;
ret = nla_put(skb, CIFS_GENL_ATTR_SWN_IP, sizeof(struct sockaddr_storage),
&swnreg->tcon->ses->server->dstaddr); if (ret < 0) goto nlmsg_fail;
if (swnreg->net_name_notify) {
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY); if (ret < 0) goto nlmsg_fail;
}
if (swnreg->share_name_notify) {
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY); if (ret < 0) goto nlmsg_fail;
}
if (swnreg->ip_notify) {
ret = nla_put_flag(skb, CIFS_GENL_ATTR_SWN_IP_NOTIFY); if (ret < 0) goto nlmsg_fail;
}
/* * Try to find a matching registration for the tcon's server name and share name. * Calls to this function must be protected by cifs_swnreg_idr_mutex. * TODO Try to avoid memory allocations
*/ staticstruct cifs_swn_reg *cifs_find_swn_reg(struct cifs_tcon *tcon)
{ struct cifs_swn_reg *swnreg; int id; constchar *share_name; constchar *net_name;
net_name = extract_hostname(tcon->tree_name); if (IS_ERR(net_name)) { int ret;
ret = PTR_ERR(net_name);
cifs_dbg(VFS, "%s: failed to extract host name from target '%s': %d\n",
__func__, tcon->tree_name, ret); return ERR_PTR(-EINVAL);
}
share_name = extract_sharename(tcon->tree_name); if (IS_ERR(share_name)) { int ret;
ret = PTR_ERR(share_name);
cifs_dbg(VFS, "%s: failed to extract share name from target '%s': %d\n",
__func__, tcon->tree_name, ret);
kfree(net_name); return ERR_PTR(-EINVAL);
}
cifs_dbg(FYI, "Existing swn registration for %s:%s found\n", swnreg->net_name,
swnreg->share_name);
kfree(net_name);
kfree(share_name);
return swnreg;
}
kfree(net_name);
kfree(share_name);
return ERR_PTR(-EEXIST);
}
/* * Get a registration for the tcon's server and share name, allocating a new one if it does not * exists
*/ staticstruct cifs_swn_reg *cifs_get_swn_reg(struct cifs_tcon *tcon)
{ struct cifs_swn_reg *reg = NULL; int ret;
mutex_lock(&cifs_swnreg_idr_mutex);
/* Check if we are already registered for this network and share names */
reg = cifs_find_swn_reg(tcon); if (!IS_ERR(reg)) {
kref_get(®->ref_count);
mutex_unlock(&cifs_swnreg_idr_mutex); return reg;
} elseif (PTR_ERR(reg) != -EEXIST) {
mutex_unlock(&cifs_swnreg_idr_mutex); return reg;
}
reg->id = idr_alloc(&cifs_swnreg_idr, reg, 1, 0, GFP_ATOMIC); if (reg->id < 0) {
cifs_dbg(FYI, "%s: failed to allocate registration id\n", __func__);
ret = reg->id; goto fail;
}
reg->net_name = extract_hostname(tcon->tree_name); if (IS_ERR(reg->net_name)) {
ret = PTR_ERR(reg->net_name);
cifs_dbg(VFS, "%s: failed to extract host name from target: %d\n", __func__, ret); goto fail_idr;
}
reg->share_name = extract_sharename(tcon->tree_name); if (IS_ERR(reg->share_name)) {
ret = PTR_ERR(reg->share_name);
cifs_dbg(VFS, "%s: failed to extract share name from target: %d\n", __func__, ret); goto fail_net_name;
}
staticint cifs_swn_reconnect(struct cifs_tcon *tcon, struct sockaddr_storage *addr)
{ int ret = 0;
/* Store the reconnect address */
cifs_server_lock(tcon->ses->server); if (cifs_sockaddr_equal(&tcon->ses->server->dstaddr, addr)) goto unlock;
ret = cifs_swn_store_swn_addr(addr, &tcon->ses->server->dstaddr,
&tcon->ses->server->swn_dstaddr); if (ret < 0) {
cifs_dbg(VFS, "%s: failed to store address: %d\n", __func__, ret); goto unlock;
}
tcon->ses->server->use_swn_dstaddr = true;
/* * Unregister to stop receiving notifications for the old IP address.
*/
ret = cifs_swn_unregister(tcon); if (ret < 0) {
cifs_dbg(VFS, "%s: Failed to unregister for witness notifications: %d\n",
__func__, ret); goto unlock;
}
/* * And register to receive notifications for the new IP address now that we have * stored the new address.
*/
ret = cifs_swn_register(tcon); if (ret < 0) {
cifs_dbg(VFS, "%s: Failed to register for witness notifications: %d\n",
__func__, ret); goto unlock;
}
int cifs_swn_register(struct cifs_tcon *tcon)
{ struct cifs_swn_reg *swnreg; int ret;
swnreg = cifs_get_swn_reg(tcon); if (IS_ERR(swnreg)) return PTR_ERR(swnreg);
ret = cifs_swn_send_register_message(swnreg); if (ret < 0) {
cifs_dbg(VFS, "%s: Failed to send swn register message: %d\n", __func__, ret); /* Do not put the swnreg or return error, the echo task will retry */
}
return 0;
}
int cifs_swn_unregister(struct cifs_tcon *tcon)
{ struct cifs_swn_reg *swnreg;
mutex_lock(&cifs_swnreg_idr_mutex);
swnreg = cifs_find_swn_reg(tcon); if (IS_ERR(swnreg)) {
mutex_unlock(&cifs_swnreg_idr_mutex); return PTR_ERR(swnreg);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.