1 // SPDX-License-Identifier: GPL-2.0
3 * Witness Service client for CIFS
5 * Copyright (c) 2020 Samuel Cabrero <scabrero@suse.de>
8 #include <linux/kref.h>
9 #include <net/genetlink.h>
10 #include <uapi/linux/cifs/cifs_netlink.h>
14 #include "cifsproto.h"
16 #include "cifs_debug.h"
19 static DEFINE_IDR(cifs_swnreg_idr
);
20 static DEFINE_MUTEX(cifs_swnreg_idr_mutex
);
24 struct kref ref_count
;
27 const char *share_name
;
29 bool share_name_notify
;
32 struct cifs_tcon
*tcon
;
35 static int cifs_swn_auth_info_krb(struct cifs_tcon
*tcon
, struct sk_buff
*skb
)
39 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_KRB_AUTH
);
46 static int cifs_swn_auth_info_ntlm(struct cifs_tcon
*tcon
, struct sk_buff
*skb
)
50 if (tcon
->ses
->user_name
!= NULL
) {
51 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_USER_NAME
, tcon
->ses
->user_name
);
56 if (tcon
->ses
->password
!= NULL
) {
57 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_PASSWORD
, tcon
->ses
->password
);
62 if (tcon
->ses
->domainName
!= NULL
) {
63 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_DOMAIN_NAME
, tcon
->ses
->domainName
);
72 * Sends a register message to the userspace daemon based on the registration.
73 * The authentication information to connect to the witness service is bundled
76 static int cifs_swn_send_register_message(struct cifs_swn_reg
*swnreg
)
79 struct genlmsghdr
*hdr
;
80 enum securityEnum authtype
;
81 struct sockaddr_storage
*addr
;
84 skb
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
90 hdr
= genlmsg_put(skb
, 0, 0, &cifs_genl_family
, 0, CIFS_GENL_CMD_SWN_REGISTER
);
96 ret
= nla_put_u32(skb
, CIFS_GENL_ATTR_SWN_REGISTRATION_ID
, swnreg
->id
);
100 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_NET_NAME
, swnreg
->net_name
);
104 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_SHARE_NAME
, swnreg
->share_name
);
109 * If there is an address stored use it instead of the server address, because we are
110 * in the process of reconnecting to it after a share has been moved or we have been
111 * told to switch to it (client move message). In these cases we unregister from the
112 * server address and register to the new address when we receive the notification.
114 if (swnreg
->tcon
->ses
->server
->use_swn_dstaddr
)
115 addr
= &swnreg
->tcon
->ses
->server
->swn_dstaddr
;
117 addr
= &swnreg
->tcon
->ses
->server
->dstaddr
;
119 ret
= nla_put(skb
, CIFS_GENL_ATTR_SWN_IP
, sizeof(struct sockaddr_storage
), addr
);
123 if (swnreg
->net_name_notify
) {
124 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY
);
129 if (swnreg
->share_name_notify
) {
130 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY
);
135 if (swnreg
->ip_notify
) {
136 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_IP_NOTIFY
);
141 authtype
= cifs_select_sectype(swnreg
->tcon
->ses
->server
, swnreg
->tcon
->ses
->sectype
);
144 ret
= cifs_swn_auth_info_krb(swnreg
->tcon
, skb
);
146 cifs_dbg(VFS
, "%s: Failed to get kerberos auth info: %d\n", __func__
, ret
);
154 ret
= cifs_swn_auth_info_ntlm(swnreg
->tcon
, skb
);
156 cifs_dbg(VFS
, "%s: Failed to get NTLM auth info: %d\n", __func__
, ret
);
161 cifs_dbg(VFS
, "%s: secType %d not supported!\n", __func__
, authtype
);
166 genlmsg_end(skb
, hdr
);
167 genlmsg_multicast(&cifs_genl_family
, skb
, 0, CIFS_GENL_MCGRP_SWN
, GFP_ATOMIC
);
169 cifs_dbg(FYI
, "%s: Message to register for network name %s with id %d sent\n", __func__
,
170 swnreg
->net_name
, swnreg
->id
);
175 genlmsg_cancel(skb
, hdr
);
182 * Sends an uregister message to the userspace daemon based on the registration
184 static int cifs_swn_send_unregister_message(struct cifs_swn_reg
*swnreg
)
187 struct genlmsghdr
*hdr
;
190 skb
= genlmsg_new(NLMSG_DEFAULT_SIZE
, GFP_KERNEL
);
194 hdr
= genlmsg_put(skb
, 0, 0, &cifs_genl_family
, 0, CIFS_GENL_CMD_SWN_UNREGISTER
);
200 ret
= nla_put_u32(skb
, CIFS_GENL_ATTR_SWN_REGISTRATION_ID
, swnreg
->id
);
204 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_NET_NAME
, swnreg
->net_name
);
208 ret
= nla_put_string(skb
, CIFS_GENL_ATTR_SWN_SHARE_NAME
, swnreg
->share_name
);
212 ret
= nla_put(skb
, CIFS_GENL_ATTR_SWN_IP
, sizeof(struct sockaddr_storage
),
213 &swnreg
->tcon
->ses
->server
->dstaddr
);
217 if (swnreg
->net_name_notify
) {
218 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_NET_NAME_NOTIFY
);
223 if (swnreg
->share_name_notify
) {
224 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_SHARE_NAME_NOTIFY
);
229 if (swnreg
->ip_notify
) {
230 ret
= nla_put_flag(skb
, CIFS_GENL_ATTR_SWN_IP_NOTIFY
);
235 genlmsg_end(skb
, hdr
);
236 genlmsg_multicast(&cifs_genl_family
, skb
, 0, CIFS_GENL_MCGRP_SWN
, GFP_ATOMIC
);
238 cifs_dbg(FYI
, "%s: Message to unregister for network name %s with id %d sent\n", __func__
,
239 swnreg
->net_name
, swnreg
->id
);
244 genlmsg_cancel(skb
, hdr
);
250 * Try to find a matching registration for the tcon's server name and share name.
251 * Calls to this funciton must be protected by cifs_swnreg_idr_mutex.
252 * TODO Try to avoid memory allocations
254 static struct cifs_swn_reg
*cifs_find_swn_reg(struct cifs_tcon
*tcon
)
256 struct cifs_swn_reg
*swnreg
;
258 const char *share_name
;
259 const char *net_name
;
261 net_name
= extract_hostname(tcon
->treeName
);
262 if (IS_ERR(net_name
)) {
265 ret
= PTR_ERR(net_name
);
266 cifs_dbg(VFS
, "%s: failed to extract host name from target '%s': %d\n",
267 __func__
, tcon
->treeName
, ret
);
268 return ERR_PTR(-EINVAL
);
271 share_name
= extract_sharename(tcon
->treeName
);
272 if (IS_ERR(share_name
)) {
275 ret
= PTR_ERR(net_name
);
276 cifs_dbg(VFS
, "%s: failed to extract share name from target '%s': %d\n",
277 __func__
, tcon
->treeName
, ret
);
279 return ERR_PTR(-EINVAL
);
282 idr_for_each_entry(&cifs_swnreg_idr
, swnreg
, id
) {
283 if (strcasecmp(swnreg
->net_name
, net_name
) != 0
284 || strcasecmp(swnreg
->share_name
, share_name
) != 0) {
288 cifs_dbg(FYI
, "Existing swn registration for %s:%s found\n", swnreg
->net_name
,
300 return ERR_PTR(-EEXIST
);
304 * Get a registration for the tcon's server and share name, allocating a new one if it does not
307 static struct cifs_swn_reg
*cifs_get_swn_reg(struct cifs_tcon
*tcon
)
309 struct cifs_swn_reg
*reg
= NULL
;
312 mutex_lock(&cifs_swnreg_idr_mutex
);
314 /* Check if we are already registered for this network and share names */
315 reg
= cifs_find_swn_reg(tcon
);
317 kref_get(®
->ref_count
);
318 mutex_unlock(&cifs_swnreg_idr_mutex
);
320 } else if (PTR_ERR(reg
) != -EEXIST
) {
321 mutex_unlock(&cifs_swnreg_idr_mutex
);
325 reg
= kmalloc(sizeof(struct cifs_swn_reg
), GFP_ATOMIC
);
327 mutex_unlock(&cifs_swnreg_idr_mutex
);
328 return ERR_PTR(-ENOMEM
);
331 kref_init(®
->ref_count
);
333 reg
->id
= idr_alloc(&cifs_swnreg_idr
, reg
, 1, 0, GFP_ATOMIC
);
335 cifs_dbg(FYI
, "%s: failed to allocate registration id\n", __func__
);
340 reg
->net_name
= extract_hostname(tcon
->treeName
);
341 if (IS_ERR(reg
->net_name
)) {
342 ret
= PTR_ERR(reg
->net_name
);
343 cifs_dbg(VFS
, "%s: failed to extract host name from target: %d\n", __func__
, ret
);
347 reg
->share_name
= extract_sharename(tcon
->treeName
);
348 if (IS_ERR(reg
->share_name
)) {
349 ret
= PTR_ERR(reg
->share_name
);
350 cifs_dbg(VFS
, "%s: failed to extract share name from target: %d\n", __func__
, ret
);
354 reg
->net_name_notify
= true;
355 reg
->share_name_notify
= true;
356 reg
->ip_notify
= (tcon
->capabilities
& SMB2_SHARE_CAP_SCALEOUT
);
360 mutex_unlock(&cifs_swnreg_idr_mutex
);
365 kfree(reg
->net_name
);
367 idr_remove(&cifs_swnreg_idr
, reg
->id
);
370 mutex_unlock(&cifs_swnreg_idr_mutex
);
374 static void cifs_swn_reg_release(struct kref
*ref
)
376 struct cifs_swn_reg
*swnreg
= container_of(ref
, struct cifs_swn_reg
, ref_count
);
379 ret
= cifs_swn_send_unregister_message(swnreg
);
381 cifs_dbg(VFS
, "%s: Failed to send unregister message: %d\n", __func__
, ret
);
383 idr_remove(&cifs_swnreg_idr
, swnreg
->id
);
384 kfree(swnreg
->net_name
);
385 kfree(swnreg
->share_name
);
389 static void cifs_put_swn_reg(struct cifs_swn_reg
*swnreg
)
391 mutex_lock(&cifs_swnreg_idr_mutex
);
392 kref_put(&swnreg
->ref_count
, cifs_swn_reg_release
);
393 mutex_unlock(&cifs_swnreg_idr_mutex
);
396 static int cifs_swn_resource_state_changed(struct cifs_swn_reg
*swnreg
, const char *name
, int state
)
401 case CIFS_SWN_RESOURCE_STATE_UNAVAILABLE
:
402 cifs_dbg(FYI
, "%s: resource name '%s' become unavailable\n", __func__
, name
);
403 for (i
= 0; i
< swnreg
->tcon
->ses
->chan_count
; i
++) {
404 spin_lock(&GlobalMid_Lock
);
405 if (swnreg
->tcon
->ses
->chans
[i
].server
->tcpStatus
!= CifsExiting
)
406 swnreg
->tcon
->ses
->chans
[i
].server
->tcpStatus
= CifsNeedReconnect
;
407 spin_unlock(&GlobalMid_Lock
);
410 case CIFS_SWN_RESOURCE_STATE_AVAILABLE
:
411 cifs_dbg(FYI
, "%s: resource name '%s' become available\n", __func__
, name
);
412 for (i
= 0; i
< swnreg
->tcon
->ses
->chan_count
; i
++) {
413 spin_lock(&GlobalMid_Lock
);
414 if (swnreg
->tcon
->ses
->chans
[i
].server
->tcpStatus
!= CifsExiting
)
415 swnreg
->tcon
->ses
->chans
[i
].server
->tcpStatus
= CifsNeedReconnect
;
416 spin_unlock(&GlobalMid_Lock
);
419 case CIFS_SWN_RESOURCE_STATE_UNKNOWN
:
420 cifs_dbg(FYI
, "%s: resource name '%s' changed to unknown state\n", __func__
, name
);
426 static bool cifs_sockaddr_equal(struct sockaddr_storage
*addr1
, struct sockaddr_storage
*addr2
)
428 if (addr1
->ss_family
!= addr2
->ss_family
)
431 if (addr1
->ss_family
== AF_INET
) {
432 return (memcmp(&((const struct sockaddr_in
*)addr1
)->sin_addr
,
433 &((const struct sockaddr_in
*)addr2
)->sin_addr
,
434 sizeof(struct in_addr
)) == 0);
437 if (addr1
->ss_family
== AF_INET6
) {
438 return (memcmp(&((const struct sockaddr_in6
*)addr1
)->sin6_addr
,
439 &((const struct sockaddr_in6
*)addr2
)->sin6_addr
,
440 sizeof(struct in6_addr
)) == 0);
446 static int cifs_swn_store_swn_addr(const struct sockaddr_storage
*new,
447 const struct sockaddr_storage
*old
,
448 struct sockaddr_storage
*dst
)
452 if (old
->ss_family
== AF_INET
) {
453 struct sockaddr_in
*ipv4
= (struct sockaddr_in
*)old
;
455 port
= ipv4
->sin_port
;
458 if (old
->ss_family
== AF_INET6
) {
459 struct sockaddr_in6
*ipv6
= (struct sockaddr_in6
*)old
;
461 port
= ipv6
->sin6_port
;
464 if (new->ss_family
== AF_INET
) {
465 struct sockaddr_in
*ipv4
= (struct sockaddr_in
*)new;
467 ipv4
->sin_port
= port
;
470 if (new->ss_family
== AF_INET6
) {
471 struct sockaddr_in6
*ipv6
= (struct sockaddr_in6
*)new;
473 ipv6
->sin6_port
= port
;
481 static int cifs_swn_reconnect(struct cifs_tcon
*tcon
, struct sockaddr_storage
*addr
)
485 /* Store the reconnect address */
486 mutex_lock(&tcon
->ses
->server
->srv_mutex
);
487 if (cifs_sockaddr_equal(&tcon
->ses
->server
->dstaddr
, addr
))
490 ret
= cifs_swn_store_swn_addr(addr
, &tcon
->ses
->server
->dstaddr
,
491 &tcon
->ses
->server
->swn_dstaddr
);
493 cifs_dbg(VFS
, "%s: failed to store address: %d\n", __func__
, ret
);
496 tcon
->ses
->server
->use_swn_dstaddr
= true;
499 * Unregister to stop receiving notifications for the old IP address.
501 ret
= cifs_swn_unregister(tcon
);
503 cifs_dbg(VFS
, "%s: Failed to unregister for witness notifications: %d\n",
509 * And register to receive notifications for the new IP address now that we have
510 * stored the new address.
512 ret
= cifs_swn_register(tcon
);
514 cifs_dbg(VFS
, "%s: Failed to register for witness notifications: %d\n",
519 spin_lock(&GlobalMid_Lock
);
520 if (tcon
->ses
->server
->tcpStatus
!= CifsExiting
)
521 tcon
->ses
->server
->tcpStatus
= CifsNeedReconnect
;
522 spin_unlock(&GlobalMid_Lock
);
525 mutex_unlock(&tcon
->ses
->server
->srv_mutex
);
530 static int cifs_swn_client_move(struct cifs_swn_reg
*swnreg
, struct sockaddr_storage
*addr
)
532 struct sockaddr_in
*ipv4
= (struct sockaddr_in
*)addr
;
533 struct sockaddr_in6
*ipv6
= (struct sockaddr_in6
*)addr
;
535 if (addr
->ss_family
== AF_INET
)
536 cifs_dbg(FYI
, "%s: move to %pI4\n", __func__
, &ipv4
->sin_addr
);
537 else if (addr
->ss_family
== AF_INET6
)
538 cifs_dbg(FYI
, "%s: move to %pI6\n", __func__
, &ipv6
->sin6_addr
);
540 return cifs_swn_reconnect(swnreg
->tcon
, addr
);
543 int cifs_swn_notify(struct sk_buff
*skb
, struct genl_info
*info
)
545 struct cifs_swn_reg
*swnreg
;
549 if (info
->attrs
[CIFS_GENL_ATTR_SWN_REGISTRATION_ID
]) {
552 swnreg_id
= nla_get_u32(info
->attrs
[CIFS_GENL_ATTR_SWN_REGISTRATION_ID
]);
553 mutex_lock(&cifs_swnreg_idr_mutex
);
554 swnreg
= idr_find(&cifs_swnreg_idr
, swnreg_id
);
555 mutex_unlock(&cifs_swnreg_idr_mutex
);
556 if (swnreg
== NULL
) {
557 cifs_dbg(FYI
, "%s: registration id %d not found\n", __func__
, swnreg_id
);
561 cifs_dbg(FYI
, "%s: missing registration id attribute\n", __func__
);
565 if (info
->attrs
[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE
]) {
566 type
= nla_get_u32(info
->attrs
[CIFS_GENL_ATTR_SWN_NOTIFICATION_TYPE
]);
568 cifs_dbg(FYI
, "%s: missing notification type attribute\n", __func__
);
573 case CIFS_SWN_NOTIFICATION_RESOURCE_CHANGE
: {
576 if (info
->attrs
[CIFS_GENL_ATTR_SWN_RESOURCE_NAME
]) {
577 nla_strscpy(name
, info
->attrs
[CIFS_GENL_ATTR_SWN_RESOURCE_NAME
],
580 cifs_dbg(FYI
, "%s: missing resource name attribute\n", __func__
);
583 if (info
->attrs
[CIFS_GENL_ATTR_SWN_RESOURCE_STATE
]) {
584 state
= nla_get_u32(info
->attrs
[CIFS_GENL_ATTR_SWN_RESOURCE_STATE
]);
586 cifs_dbg(FYI
, "%s: missing resource state attribute\n", __func__
);
589 return cifs_swn_resource_state_changed(swnreg
, name
, state
);
591 case CIFS_SWN_NOTIFICATION_CLIENT_MOVE
: {
592 struct sockaddr_storage addr
;
594 if (info
->attrs
[CIFS_GENL_ATTR_SWN_IP
]) {
595 nla_memcpy(&addr
, info
->attrs
[CIFS_GENL_ATTR_SWN_IP
], sizeof(addr
));
597 cifs_dbg(FYI
, "%s: missing IP address attribute\n", __func__
);
600 return cifs_swn_client_move(swnreg
, &addr
);
603 cifs_dbg(FYI
, "%s: unknown notification type %d\n", __func__
, type
);
610 int cifs_swn_register(struct cifs_tcon
*tcon
)
612 struct cifs_swn_reg
*swnreg
;
615 swnreg
= cifs_get_swn_reg(tcon
);
617 return PTR_ERR(swnreg
);
619 ret
= cifs_swn_send_register_message(swnreg
);
621 cifs_dbg(VFS
, "%s: Failed to send swn register message: %d\n", __func__
, ret
);
622 /* Do not put the swnreg or return error, the echo task will retry */
628 int cifs_swn_unregister(struct cifs_tcon
*tcon
)
630 struct cifs_swn_reg
*swnreg
;
632 mutex_lock(&cifs_swnreg_idr_mutex
);
634 swnreg
= cifs_find_swn_reg(tcon
);
635 if (IS_ERR(swnreg
)) {
636 mutex_unlock(&cifs_swnreg_idr_mutex
);
637 return PTR_ERR(swnreg
);
640 mutex_unlock(&cifs_swnreg_idr_mutex
);
642 cifs_put_swn_reg(swnreg
);
647 void cifs_swn_dump(struct seq_file
*m
)
649 struct cifs_swn_reg
*swnreg
;
650 struct sockaddr_in
*sa
;
651 struct sockaddr_in6
*sa6
;
654 seq_puts(m
, "Witness registrations:");
656 mutex_lock(&cifs_swnreg_idr_mutex
);
657 idr_for_each_entry(&cifs_swnreg_idr
, swnreg
, id
) {
658 seq_printf(m
, "\nId: %u Refs: %u Network name: '%s'%s Share name: '%s'%s Ip address: ",
659 id
, kref_read(&swnreg
->ref_count
),
660 swnreg
->net_name
, swnreg
->net_name_notify
? "(y)" : "(n)",
661 swnreg
->share_name
, swnreg
->share_name_notify
? "(y)" : "(n)");
662 switch (swnreg
->tcon
->ses
->server
->dstaddr
.ss_family
) {
664 sa
= (struct sockaddr_in
*) &swnreg
->tcon
->ses
->server
->dstaddr
;
665 seq_printf(m
, "%pI4", &sa
->sin_addr
.s_addr
);
668 sa6
= (struct sockaddr_in6
*) &swnreg
->tcon
->ses
->server
->dstaddr
;
669 seq_printf(m
, "%pI6", &sa6
->sin6_addr
.s6_addr
);
670 if (sa6
->sin6_scope_id
)
671 seq_printf(m
, "%%%u", sa6
->sin6_scope_id
);
674 seq_puts(m
, "(unknown)");
676 seq_printf(m
, "%s", swnreg
->ip_notify
? "(y)" : "(n)");
678 mutex_unlock(&cifs_swnreg_idr_mutex
);
682 void cifs_swn_check(void)
684 struct cifs_swn_reg
*swnreg
;
688 mutex_lock(&cifs_swnreg_idr_mutex
);
689 idr_for_each_entry(&cifs_swnreg_idr
, swnreg
, id
) {
690 ret
= cifs_swn_send_register_message(swnreg
);
692 cifs_dbg(FYI
, "%s: Failed to send register message: %d\n", __func__
, ret
);
694 mutex_unlock(&cifs_swnreg_idr_mutex
);