From 1c941fd7879b39cd8ac9ed15a47681e23e4c6caa Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Sat, 24 Sep 2016 03:34:45 -0700 Subject: [PATCH] rpc: Should validate server versions. (#2775) Fixes #2764 --- cmd/auth-rpc-client.go | 18 ++++++++++++------ cmd/controller-handlers.go | 3 +++ cmd/lock-rpc-server.go | 1 + cmd/namespace-lock.go | 1 - cmd/storage-rpc-server.go | 13 +++++++++---- 5 files changed, 25 insertions(+), 11 deletions(-) diff --git a/cmd/auth-rpc-client.go b/cmd/auth-rpc-client.go index c88d0a01c..89f2bd967 100644 --- a/cmd/auth-rpc-client.go +++ b/cmd/auth-rpc-client.go @@ -53,8 +53,8 @@ type RPCLoginArgs struct { // with subsequent requests. type RPCLoginReply struct { Token string - ServerVersion string Timestamp time.Time + ServerVersion string } // Validates if incoming token is valid. @@ -90,11 +90,12 @@ type authConfig struct { // AuthRPCClient is a wrapper type for RPCClient which provides JWT based authentication across reconnects. type AuthRPCClient struct { - config *authConfig - rpc *RPCClient // reconnect'able rpc client built on top of net/rpc Client - isLoggedIn bool // Indicates if the auth client has been logged in and token is valid. - token string // JWT based token - tstamp time.Time // Timestamp as received on Login RPC. + config *authConfig + rpc *RPCClient // reconnect'able rpc client built on top of net/rpc Client + isLoggedIn bool // Indicates if the auth client has been logged in and token is valid. + token string // JWT based token + tstamp time.Time // Timestamp as received on Login RPC. + serverVerison string // Server version exchanged by the RPC. } // newAuthClient - returns a jwt based authenticated (go) rpc client, which does automatic reconnect. @@ -129,9 +130,14 @@ func (authClient *AuthRPCClient) Login() error { }, &reply); err != nil { return err } + // Validate if version do indeed match. + if reply.ServerVersion != Version { + return errServerVersionMismatch + } // Set token, time stamp as received from a successful login call. authClient.token = reply.Token authClient.tstamp = reply.Timestamp + authClient.serverVerison = reply.ServerVersion authClient.isLoggedIn = true return nil } diff --git a/cmd/controller-handlers.go b/cmd/controller-handlers.go index c19f9c12e..9d6ca9654 100644 --- a/cmd/controller-handlers.go +++ b/cmd/controller-handlers.go @@ -21,6 +21,9 @@ import "errors" // errServerNotInitialized - server not initialized. var errServerNotInitialized = errors.New("Server not initialized, please try again.") +// errServerVersionMismatch - server versions do not match. +var errServerVersionMismatch = errors.New("Server versions do not match.") + /// Auth operations // Login - login handler. diff --git a/cmd/lock-rpc-server.go b/cmd/lock-rpc-server.go index a4e455fb2..493d3b351 100644 --- a/cmd/lock-rpc-server.go +++ b/cmd/lock-rpc-server.go @@ -154,6 +154,7 @@ func (l *lockServer) LoginHandler(args *RPCLoginArgs, reply *RPCLoginReply) erro } reply.Token = token reply.Timestamp = l.timestamp + reply.ServerVersion = Version return nil } diff --git a/cmd/namespace-lock.go b/cmd/namespace-lock.go index 010abbcf5..e35dceb9f 100644 --- a/cmd/namespace-lock.go +++ b/cmd/namespace-lock.go @@ -50,7 +50,6 @@ func initDsyncNodes(disks []string, port int) error { path: pathutil.Join(lockRPCPath, disk[idx+1:]), loginMethod: "Dsync.LoginHandler", })) - if isLocalStorage(disk) && myNode == -1 { myNode = len(clnts) - 1 } diff --git a/cmd/storage-rpc-server.go b/cmd/storage-rpc-server.go index 8b733a2e5..6f347c2c0 100644 --- a/cmd/storage-rpc-server.go +++ b/cmd/storage-rpc-server.go @@ -22,6 +22,7 @@ import ( "net/rpc" "path" "strings" + "time" router "github.com/gorilla/mux" "github.com/minio/minio/pkg/disk" @@ -30,8 +31,9 @@ import ( // Storage server implements rpc primitives to facilitate exporting a // disk over a network. type storageServer struct { - storage StorageAPI - path string + storage StorageAPI + path string + timestamp time.Time } /// Auth operations @@ -50,6 +52,7 @@ func (s *storageServer) LoginHandler(args *RPCLoginArgs, reply *RPCLoginReply) e return err } reply.Token = token + reply.Timestamp = s.timestamp reply.ServerVersion = Version return nil } @@ -213,6 +216,7 @@ func newRPCServer(serverConfig serverCmdConfig) (servers []*storageServer, err e for _, ignoredExport := range ignoredExports { skipDisks[ignoredExport] = true } + t := time.Now().UTC() for _, export := range exports { if skipDisks[export] { continue @@ -231,8 +235,9 @@ func newRPCServer(serverConfig serverCmdConfig) (servers []*storageServer, err e export = export[idx+1:] } servers = append(servers, &storageServer{ - storage: storage, - path: export, + storage: storage, + path: export, + timestamp: t, }) } }