ϪfAldZddlZddlmZmZddlmZmZmZddl m Z m Z ddl m Z ddlmZddlmZmZdd lmZdd lmZdd lmZGd d ej2ZGddej2ZdZdZdZdZdZ dZ!iZ"e#e$jKD]\Z&Z'e&dddk(se&e"e'<e"e_(e"e_(["['dZ)dZ*y)z Implementation of the ssh-userauth service. Currently implemented authentication types are public-key and password. Maintainer: Paul Swartz N)error interfaces)keysservice transport)NSgetNS) credentials)UnauthorizedLogin)deferreactor)Logger)failure) nativeStringceZdZdZdZdZdZdZeZ e jde jdiZ eZdZd Zd Zd Zd Zd ZdZdZdZdZdZdZy)SSHUserAuthServera A service implementing the server side of the 'ssh-userauth' service. It is used to authenticate the user on the other side as being able to access this server. @ivar name: the name of this service: 'ssh-userauth' @type name: L{bytes} @ivar authenticatedWith: a list of authentication methods that have already been used. @type authenticatedWith: L{list} @ivar loginTimeout: the number of seconds we wait before disconnecting the user for taking too long to authenticate @type loginTimeout: L{int} @ivar attemptsBeforeDisconnect: the number of failed login attempts we allow before disconnecting. @type attemptsBeforeDisconnect: L{int} @ivar loginAttempts: the number of login attempts that have been made @type loginAttempts: L{int} @ivar passwordDelay: the number of seconds to delay when the user gives an incorrect password @type passwordDelay: L{int} @ivar interfaceToMethod: a L{dict} mapping credential interfaces to authentication methods. The server checks to see which of the cred interfaces have checkers and tells the client that those methods are valid for authentication. @type interfaceToMethod: L{dict} @ivar supportedAuthentications: A list of the supported authentication methods. @type supportedAuthentications: L{list} of L{bytes} @ivar user: the last username the client tried to authenticate with @type user: L{bytes} @ivar method: the current authentication method @type method: L{bytes} @ivar nextService: the service the user wants started after authentication has been completed. @type nextService: L{bytes} @ivar portal: the L{twisted.cred.portal.Portal} we are using for authentication @type portal: L{twisted.cred.portal.Portal} @ivar clock: an object with a callLater method. Stubbed out for testing. ssh-userauthi publickeypasswordc2g|_d|_d|_d|_|jj j |_g|_|j jD]9}||jvs|jj|j|;|jjds)d|jvr|jjd|jj|j|j |_y)z Called when the userauth service is started. Set up instance variables, check if we should allow password authentication (only allow if the outgoing connection is encrypted) and set up a login timeout. rNinr)authenticatedWith loginAttemptsuser nextServicerfactoryportalsupportedAuthenticationslistCredentialsInterfacesinterfaceToMethodappend isEncryptedremoveclock callLater loginTimeouttimeoutAuthentication_cancelLoginTimeout)selfis @type packet: L{bytes} zauth returned noneN)r rrrmethodrE _ebBadAuthrFailurerr? addCallback_cbFinishedAuth addErrback_ebMaybeBadAuth)r+packetrrrHrestds r-ssh_USERAUTH_REQUESTz&SSHUserAuthServer.ssh_USERAUTH_REQUESTs+0*:'k64 499  t/?/? ?%'D " & LLt , OOGOOE,<,<=Q,RS T  d**+ T))* T__%r/c|\}}}||j_||j_|jjj |j|j }|s"t jd|j |jjd|j|j|jjtd|jj|y)z The callback when user has successfully been authenticated. For a description of the arguments, see L{twisted.cred.portal.Portal.login}. We start the service requested by the user. zcould not get next service: z&{user!r} authenticated with {method!r}rrHr/N)ravatarlogoutFunctionr getServicerrr?r<r=rrH sendPacketMSG_USERAUTH_SUCCESS setService)r+result interfacerUlogoutrs r-rLz!SSHUserAuthServer._cbFinishedAuths '-#FF &(.%..((33DNNDDTDTU""%A$BRBRAS#TU U  4499T[[   !!"6< !!'),r/c|jtj|jj t t dj|jdzy)z An intermediate errback. If the reason is error.NotEnoughAuthentication, we send a MSG_USERAUTH_FAILURE, but with the partial success indicator set. @type reason: L{twisted.python.failure.Failure} ,N) traprNotEnoughAuthenticationrrXMSG_USERAUTH_FAILURErjoinr r+reasons r-rNz!SSHUserAuthServer._ebMaybeBadAuthsG  E112 !! "TYYt/L/L%M"NQX"X r/cl|jtjry|jdk7r?|jj d|j |j|jtr,|jj d|jns|jtjr,|jj d|jn(|jjd ||j |xjd z c_ |j|jkDr+|jjtjd y|jj!t"t%d j'|j(dzy)a{ The final errback in the authentication chain. If the reason is error.IgnoreAuthentication, we simply return; the authentication method has sent its own response. Otherwise, send a failure message and (if the method is not 'none') increment the number of login attempts. @type reason: L{twisted.python.failure.Failure} Nnonez{user!r} failed auth {method!r}rTzunauthorized login: {message})messagezreason: {reason})rfz#Error checking auth for user {user})rrrstoo many bad authsr_)checkrIgnoreAuthenticationrHr<r=rr getErrorMessager?rrattemptsBeforeDisconnectrr5r6rXrcrrdr res r-rIzSSHUserAuthServer._ebBadAuthsL <<22 3  ;;' ! IIOO1 $++  ||-. 3V=S=S=U e../  26;Q;Q;ST !!9""   ! # !!D$A$AA--GG) !! "TYYt/L/L%M"NQX"X r/c$t|dd}t|ddd\}}} tjj ||xrt|dxsd}|rt|jjt!t"fzt|j$zt|j&ztdzt!|fzt|zt|z}t)j*|j$||||} |j,j/| dt0j2St)j*|j$||dd} |j,j/| dt0j2j5|j6|ddS#tj $r\dj |jd}|jj|tjt|cYSwxYw)a Public key authentication. Payload:: byte has signature string algorithm name string key blob [string signature] (if has signature is True) Create a SSHPublicKey credential and verify it using our portal. rrNz"Unsupported key type {} or bad keyasciir)ordr rKey fromString BadKeyErrorformatdecoder<rr r>r rr sessionIDbytesMSG_USERAUTH_REQUESTrrr SSHPrivateKeyrloginr IConchUserrM _ebCheckKey) r+rOhasSigalgNameblobrPr signaturebcs r-auth_publickeyz SSHUserAuthServer.auth_publickeysVAa[!#F12J2t 8 HH   % -uT{1~5 4>>++,-/01TYY- T%%&'\" #  " # W+ T( ))$))WdAyQA;;$$Qj.C.CD D))$))WdD$OA;;$$Qj.C.CDOO  &* + 88??w@WXE IIOOE "::/67 7 8sF A,HHc|jtj|jj t |t jtjS)z Called back if the user did not sent a signature. If reason is error.ValidPublicKey then this key is valid for the user to authenticate with. Send MSG_USERAUTH_PK_OK. ) rarValidPublicKeyrrXMSG_USERAUTH_PK_OKrrJrl)r+rfrOs r-r~zSSHUserAuthServer._ebCheckKey$sC  E(() !!"4f=u99;<.orderByPreferences=t*****00664..//r/c3>K|]}|jvr|ywr)r).0rr+s r- z9SSHUserAuthClient.ssh_USERAUTH_FAILURE..s' t555 sr_)keyzcan continue with: {methods})methodsN) r rrrr#rsortedsplitr<r=_cbUserauthFailureiter)r+rO canContinuepartialrs` r-ssh_USERAUTH_FAILUREz&SSHUserAuthClient.ssh_USERAUTH_FAILUREs, %V} Wg,   " " ) )$-- 8 0" '--d3  "   6 L&&tT+->??r/c|ry t|}tj|j|}|j |j ||S#t $r-|jjtjdYywxYw)Ns(no more authentication methods available) nextr maybeDeferredrErKr StopIterationrr5r6)r+r[iteratorrHrQs r-rz$SSHUserAuthClient._cbUserauthFailuresv   (^F##DLL&9A MM$118 <H  NN ) )CC;  s A3BBc t|dt|jjddzd}|||S|j ddy)z This message (number 60) can mean several different messages depending on the current authentication type. We dispatch to individual methods in order to handle this request. zssh_USERAUTH_PK_OK_%sr9r:Nrhr/)rArrr@r)r+rOfuncs r-ssh_USERAUTH_PK_OKz$SSHUserAuthClient.ssh_USERAUTH_PK_OKsR   #l4==3H3Ht3T&U U    <  OOGS )r/c(|j}t|jjt t fzt|j zt|jjztdzdzt|jzt|jz}|j||}|s|jddy|j|j|j|j y)z This is MSG_USERAUTH_PK. Our public key is valid, so we create a signature and try to authenticate with it. rrhr/N)rrrrxryrzrrrsshTypersignDatarrK _cbSignedDatarMr)r+rO publicKeyrrQs r-ssh_USERAUTH_PK_OK_publickeyz.SSHUserAuthClient.ssh_USERAUTH_PK_OK_publickeys && t~~'' ()+, -m ##$ %      ""$%  &!" #  MM)Q ' OOGS )  d(() T\\"r/c(t|d\}}dx__jd}|j j j }|jfd|j jj y)z This is MSG_USERAUTH_PASSWD_CHANGEREQ. The password given has expired. We ask for an old password and a new password, then send both back to the server. rpNsOld Password: c&jSr) getPassword)rpromptr+s r-z?SSHUserAuthClient.ssh_USERAUTH_PK_OK_password..sd&6&6v&>r/) r _oldPass_newPassr addCallbacks _setOldPassrrK _setNewPass)r+rOlanguagerPrQrs` @r-ssh_USERAUTH_PK_OK_passwordz-SSHUserAuthClient.ssh_USERAUTH_PK_OK_passwordsv "'vq!1$(,,    . / NN4++T\\ : >? t''6r/ct|d\}}}}tjd|ddd}|dd}g}t|D]?}t|\} }t t |dd} |dd}|j | | fA|j|||} | j|j| j|jy)z This is MSG_USERAUTH_INFO_RESPONSE. The server has sent us the questions it wants us to answer, so we ask the user and sent the responses. rG!LNrr) r structunpackrangeboolrrr#getGenericAnswersrK_cbGenericAnswersrMr) r+rOr instructionlangrB numPromptspromptsr,rechorQs r-'ssh_USERAUTH_PK_OK_keyboard_interactivez9SSHUserAuthClient.ssh_USERAUTH_PK_OK_keyboard_interactives ).fa(8%k4]]4bq215 ABxz" +A ;LFDD1I'D8D NNFD> *  +  " "4g > d,,- T\\"r/c|j}|jddt|jzt|j zt|zy)z Called back out of self.signData with the signed data. Send the authentication request with the signature. @param signedData: the data signed by the user's private key. @type signedData: L{bytes} rrN)rrrrr)r+ signedDatars r-rzSSHUserAuthClient._cbSignedData&sN&&    b**,- -9>>3C0D Dr*~ U r/c||_y)z Called back when we are choosing a new password. Simply store the old password for now. @param op: the old password as entered by the user @type op: L{bytes} N)r)r+ops r-rzSSHUserAuthClient._setOldPass4s  r/c~|j}d|_|jddt|zt|zy)z Called back when we are choosing a new password. Get the old password and send the authentication message with both. @param np: the new password as entered by the user @type np: L{bytes} Nrr`)rrr)r+nprs r-rzSSHUserAuthClient._setNewPass>s4]]   Wr"v%52%>?r/ctjdt|}|D]}|t|j dz }!|j j t|y)a Called back when we are finished answering keyboard-interactive questions. Send the info back to the server in a MSG_USERAUTH_INFO_RESPONSE. @param responses: a list of L{bytes} responses @type responses: L{list} rUTF8N)rpackrrencoderrXMSG_USERAUTH_INFO_RESPONSE)r+ responsesrBrs r-rz#SSHUserAuthClient._cbGenericAnswersJsT{{4Y0 )A Bqxx'( (D ) !!">CSO T OOg9+<+<+>(??"Y^^EUBVV r/cv|j}|r'|j|j|jyy)z Try to authenticate with a password. Ask the user for a password. If the user will return a password, return True. Otherwise, return False. @rtype: L{bool} TF)rr _cbPasswordrrs r-rzSSHUserAuthClient.auth_passwordrs3     NN4++T\\ :r/c|jjd|jdtdtdzy)z Try to authenticate with keyboard-interactive authentication. Send the request to the server and return True. @rtype: L{bool} z!authing with keyboard-interactiverr/T)r<r=rrr2s r-auth_keyboard_interactivez+SSHUserAuthClient.auth_keyboard_interactives4 ;< /C2c71BCr/c@|jddt|zy)z Called back when the user gives a password. Send the request to the server. @param password: the password the user entered @type password: L{bytes} rrjN)rr)r+rs r-rzSSHUserAuthClient._cbPasswords  Wr(|%;NotImplementedErrorr2s r-rzSSHUserAuthClient.getPrivateKeyszz-/00r/Nc<tjtS)a Return a L{Deferred} that will be called back with a password. prompt is a string to display for the password, or None for a generic 'user@hostname's password: '. @type prompt: L{bytes}/L{None} @rtype: L{defer.Deferred} r)r+rs r-rzSSHUserAuthClient.getPasswordszz-/00r/c<tjtS)a Returns a L{Deferred} with the responses to the promopts. @param name: The name of the authentication currently in progress. @param instruction: Describes what the authentication wants. @param prompts: A list of (prompt, echo) pairs, where prompt is a string to display and echo is a boolean indicating whether the user's response should be echoed as they type it. r)r+rrrs r-rz#SSHUserAuthClient.getGenericAnswersszz-/00r/r)!rrrrrrrr.rrErrrrrrrrrrrrrrrrrrr rrrrrr/r-rrFs2 DIN!&   &16@p * #0 7#&   @ D    =;. ) 1 1 1r/r2345=<rMSG_)+rr twisted.conchrrtwisted.conch.sshrrrtwisted.conch.ssh.commonrr twisted.credr twisted.cred.errorr twisted.internetr r twisted.loggerrtwisted.pythonrtwisted.python.compatr SSHServicerrrzrcrYMSG_USERAUTH_BANNERrrmessageslistlocalsitemskvprotocolMessagesMSG_USERAUTH_PASSWD_CHANGEREQMSG_USERAUTH_INFO_REQUESTrr/r-r.s +66.$0+!".i**iX `1**`1F   ! "DAq!u &."%-" !#r/