
    Vh                     D   d dl mZmZmZ eZd dlZd dlZd dlZd dl	m
Z
 d dlmZmZ d dlmZmZ  G d de      Zd Zd	 Zd
 Zd Zd Zd Zd Zd'dZ	 d(dZd Z	 d)dZd Zd Zd(dZ d Z!d Z"d Z#d Z$d*dZ%d(dZ&d(dZ'd Z(d Z)d Z*d  Z+d! Z,d(d"Z-d# Z.d$ Z/d% Z0d& Z1y)+    )absolute_importdivisionprint_functionN)	iteritems)mysql_driverget_server_implementation)mysql_sha256_password_hashmysql_sha256_password_hash_hexc                       e Zd Zy)InvalidPrivsErrorN)__name__
__module____qualname__     m/home/dcms/DCMS/lib/python3.12/site-packages/ansible_collections/community/mysql/plugins/module_utils/user.pyr   r      s    r   r   c                 f    | j                  d       | j                         }|d   }d|v rd}|S d}|S )NzSELECT @@sql_moder   ANSINOTANSIexecutefetchone)cursorresultmode_strmodes       r   get_moder   "   sD    
NN&'__FayH K Kr   c                     |r| j                  d|f       n| j                  d||f       | j                         }|d   dkD  S )Nz/SELECT count(*) FROM mysql.user WHERE user = %sz=SELECT count(*) FROM mysql.user WHERE user = %s AND host = %sr   r   )r   userhosthost_allcounts        r   user_existsr#   -   sF    H4'RVY]_cXdeOOE8a<r   c                    | j                  d||f       | j                         }t        |t              r|d   j	                  d      dkD  ryyt        |t
              r+|j                         D ]  }|j	                  d      dkD  s y y)NzSHOW CREATE USER %s@%sr   zACCOUNT LOCKTF)r   r   
isinstancetuplefinddictvalues)r   r   r    r   ress        r   user_is_lockedr+   7   s    
NN+dD\: __F &% !9>>.)A-  
FD	!==? 	Cxx'!+	 r   c                 "   i }| r| j                         D ]  }| |   ||j                         <    t        d |j                         D              r&|j                  dd        |j                  dd        |S d|j                         v rd}|S d}|S y )Nc              3   $   K   | ]  }|d v  
 yw))CIPHERISSUERSUBJECTNr   .0keys     r   	<genexpr>z$sanitize_requires.<locals>.<genexpr>O   s     [#s55[s   SSLX509)keysupperanypop)tls_requiressanitized_requiresr3   s      r   sanitize_requiresr=   J   s    $$& 	@C.:3.?syy{+	@[ASAXAXAZ[[""5$/""640%%',,..!' "! "'!!r   c                     |r\t        |t              r7t        |j                          \  }}dj	                  d |D              }||z  }n|}dj	                  | |f      } | |fS )Nz AND c              3   &   K   | ]	  }d |z    yw)z%s %%sNr   r1   s     r   r4   z#mogrify_requires.<locals>.<genexpr>a   s     *Gc8c>*Gs   z	 REQUIRE )r%   r(   zipitemsjoin)queryparamsr;   kvrequires_querys         r   mogrify_requiresrH   ]   sg    lD)**,-DAq$\\*GQ*GHNaKF)N  %!89&=r   c                 
    | |fS Nr   )rC   rD   r;   s      r   do_not_mogrify_requiresrK   i   s    &=r   c                    | j                  d||f       t        t        d | j                                     d   }d}t	        j
                  ||d         j                         j                         }|j                  d      S )NSHOW GRANTS FOR %s@%sc                     d| d   v S )NzON *.*r   r   xs    r   <lambda>zget_grants.<locals>.<lambda>o   s    AaD(8 r   r   z!(?<=\bGRANT\b)(.*?)(?=(?:\bON\b)), )	r   listfilterfetchallresearchgroupstripsplit)r   r   r    grants_linepatterngrantss         r   
get_grantsr^   m   sm    
NN*T4L9v8&//:KLMaPK2GYYwA/557==?F<<r   c                    | j                  d       | j                         }t        |t              rt	        |j                               }d|d   j                         v r-|r| j                  d||d       nA| j                  dd|i       n,|r| j                  d||d       n| j                  d	d|i       | j                         }t        |      dk(  rg S t        |d   t              r&|D cg c]  }t        |j                                }}g }|D ]   }|j                  |d   |d
   |d
   d       " |S c c}w )z Return a list of dict containing the plugin and auth_string for the
    specified username.
    If hostname is provided, return only the information about this particular
    account.
    SELECT VERSION()mariadbr   a?  select plugin, auth from (
                select plugin, password as auth from mysql.user where user=%(user)s
                and host=%(host)s
                union select plugin, authentication_string as auth from mysql.user where user=%(user)s
                and host=%(host)s) x group by plugin, auth
            )r   r    a  select plugin, auth from (
                select plugin, password as auth from mysql.user where user=%(user)s
                union select plugin, authentication_string as auth from mysql.user where user=%(user)s
                ) x group by plugin, auth
            r   zselect plugin, authentication_string as auth
                from mysql.user where user=%(user)s and host=%(host)s
                group by plugin, authentication_stringzselect plugin, authentication_string as auth
                from mysql.user where user=%(user)s
                group by plugin, authentication_string   )pluginplugin_auth_stringplugin_hash_string)r   r   r%   r(   rS   r)   lowerrU   lenr&   append)r   r   r    srv_typerowsrowexisting_auth_listrs           r   get_existing_authenticationrn   u   s^    NN%& H (D!)*HQK%%'' NN 
 -/ NN  $	! NN :DHRV;WY NN :<BD>K ??D
4yA~	 $q'4 /34cjjl#44  )!!d"#A$"#A$#( 	))  5s   0 D;c                    |rt        |       s|j                  d       |rdd|dS |j                  rdd |dS t        |       }|j	                  |       }|rt
        nt        }d}|rGt        | |      }|r9t        |      dk7  r|j                  d|z         d}n|d   d	   }d }d}|d   d
   }|r#|r!|j                  |       rd|||ff}nd|||ff}n|r:|s8|rd|||ff}n| j                  d|f       | j                         d   }d|||ff}nz|r|r	d||||ff}nm|r[|rY|dk(  r	d||||ff}n[|dk(  r	d||||ff}nM|	r2|dv rt        ||	      }n|j                  d|z         dz   |||ff}nd||||ff}n|rd|||ff}nd||ff}||fz   } | j                   ||   |r2|j                  |       s|j                  d       t        | ||||       |
#t!        |
      D ]  \  }}t#        | |||||        |t#        | ||dt%        | ||      |       d }|r5| j                  d||t'        j(                  |      f       t+        | ||      }|r| j                  d||f       d| |dS )NNuser attributes were specified but the server does not support user attributesmsgF)changedpassword_changed
attributesTrb   a	  An account with the username %s has a different password than the others existing accounts. Thus on_new_username can't decide which password to reuse so it will use your provided password instead. If no password is provided, the account will have an empty password!r   re   rc   z+CREATE USER %s@%s IDENTIFIED BY PASSWORD %sz=CREATE USER %s@%s IDENTIFIED WITH mysql_native_password AS %sz"CREATE USER %s@%s IDENTIFIED BY %s0SELECT CONCAT('*', UCASE(SHA1(UNHEX(SHA1(%s)))))z*CREATE USER %s@%s IDENTIFIED WITH %s AS %spamz-CREATE USER %s@%s IDENTIFIED WITH %s USING %sed25519z7CREATE USER %s@%s IDENTIFIED WITH %s USING PASSWORD(%s)caching_sha2_passwordsha256_passwordpasswordsalt-salt not handled for %s authentication pluginz*CREATE USER %s@%s IDENTIFIED WITH %s AS 0xz*CREATE USER %s@%s IDENTIFIED WITH %s BY %sz$CREATE USER %s@%s IDENTIFIED WITH %szCREATE USER %s@%smThe server version does not match the requirements for password_expire parameter. See module's documentation.*.*ALTER USER %s@%s ATTRIBUTE %sALTER USER %s@%s ACCOUNT LOCK)get_attribute_support	fail_json
check_modeget_user_implementationuse_old_user_mgmtrK   rH   rn   rg   warnsupports_identified_by_passwordr   r   r
   server_supports_password_expireset_password_expirer   privileges_grantr^   jsondumpsattributes_get)r   r   r    r!   r}   	encryptedrc   re   rd   r~   new_privru   r;   reuse_existing_passwordmodulepassword_expirepassword_expire_intervallockedimplold_user_mgmtmogrifyused_existing_passwordexisting_authquery_with_argsencrypted_passwordgenerated_hash_string query_with_args_and_tls_requiresdb_tableprivfinal_attributess                                 r   user_addr      sq   
 /7mn  e:VVTTT #6*D**62M)6%<LG #3FDA=!Q& ;
 >BB C */&%21%56J%K")-&&q)(3I//7KdTXZbMccO]`dfjlt_uuO	)BT4QYDZZONNMPX{[!'!21!5]`dfjl~_O	&FtU[]oHpp	&U?MPTVZ\bdvOwwOy WZ^`dfl  oA  ZB  BOEE(FPbim(n%  %TW]%] ^KNccgkmqsyfzzOJTSWY_asLttO	@4vBVV-d|;'6,'H$FNNG=>?33F; "Z [FD$AYZ'1 	ONHdVT44N	OtUJvtT4RT`a6tTZZPZE[8\])&$=6tE5K1K[kllr   c                     d}t        |       dk(  r5| d   dk(  r-t        | dd        j                  t        j                        rd}|S )NF)   r   *rb   T)rg   	frozensetissubsetstring	hexdigits)r}   ishashs     r   is_hashr     sG    F
8}x{c1Xab\"++F,<,<=FMr   c                    d}d}d}t        |       }|j                  |       }|r|st        | |      }n|g}d}|D ]  }|sVt        |      rJ| j	                  d       | j                         }| j	                  d       | j                         }| j	                  d|d   d|d   d|d   d|d   d		||f       | j                         d   }t        |t              r|j                  d
      }|r |}t        |      sO|j                  d       n<|r| j	                  d|f       n| j	                  d|f       | j                         d   }||k7  rDd}d}|j                  s2|r| j	                  d|||f       d}n	 | j	                  d|||f       d}d}t        |      r|j                  |       s|j                  d       d}!dt!        |j"                        v rdnd}"t%        | |||"      }#t'        | ||      }$|#dk(  r|dk(  s<|#dk(  r|dk(  s2|#|k(  r|d k(  s(|d!k(  r|$s!d}!|j                  st)        | ||||       d}d}|r|s| j	                  d"||f       | j                         }%d}!|%d   |k7  rd}!|r
|%d#   |k7  rd}!|	r|d$v r"|%d#   t+        ||	%      k7  rd}!n|r
|%d#   |k7  rd}!|!rd }&|r	d&||||ff}&nb|rY|d'k(  r	d(||||ff}&nR|d)k(  r	d*||||ff}&nD|	r2|d$v rt-        ||	%      }'n|j                  d+|z         d,'z   |||ff}&nd-||||ff}&nd.|||ff}&|j                  s | j                  |&  d}d}|
Wt/        | |||      }(|sL|sJt1        |(      D ]<  \  })}*d/|*v rd}|)|
vs|d0k7  sd1|*vsd2}|j                  st3        | |||)|*||       d}> |s9t1        |
      D ]+  \  })}*|)|(vsd3}|j                  st5        | |||)|*||       d}- t7        |
j9                               t7        |(j9                               z  }+|+D ]p  })g },g }-|r't;        t7        |
|)         t7        |(|)         z
        },n|r't;        t7        |
|)         t7        |(|)         z        }-nt;        t7        |
|)         t7        |(|)         z
        },t;        t7        |(|)         t7        |
|)         z
        }-d4|,v sd5|,v r.t;        t7        d/d1g      j=                  t7        |-                  }-d/|-v xr d/|,v}|,d/gk(  r|,j?                  d6       tA        |,      tA        |-      z   dkD  sd7|,d8|-}|j                  sBtA        |-      dkD  rt3        | |||)|-||       tA        |,      dkD  s\t5        | |||)|,||       od}s t/        | |||      }.|xs |(|.k7  }tC        |       }/i }0|r|/s|j                  d9       ntE        | ||      }1|1i }1i }2|jG                         D ]  \  }3}4|3|1vs	|1|3   |4k7  s|4|2|3<    |2rd:d;jI                  |2jG                         D 34cg c]  \  }3}4|3d<|4 c}4}3      z  }|j                  s6| j	                  d=||tK        jL                  |2      f       tE        | ||      }0n=|1|2fD 567ci c]&  }5|5jG                         D ]  \  }6}7|6|2vs|2|6   |6|7 ( }0}6}5}7|0r|0nd }0d}n|1}0n|/rtE        | ||      }0|sW|UtO        | ||      |k7  rE|j                  s0|r| j	                  d>||f       d?}n| j	                  d@||f       dA}n|rdB}ndC}d}|rtQ        |jS                  | ||            }8|8|k7  sdD}|j                  sq|sdE}9ndFdGjI                  tU        | ||            z  }9|#dHjI                  |9dIf      }:tW        |:||f|      }&ndHjI                  |9dJf      }:|:||ff}& | j                  |&  d} |||0dKS # t        j                  $ rI} | j                  d   dk(  r*| j	                  dd|||f       | j	                  d       d}n| Y d } ~ d } ~ ww xY wc c}4}3w c c}7}6}5w )LNFzUser unchangeda  
                    SELECT COLUMN_NAME FROM information_schema.COLUMNS
                    WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME IN ('Password', 'authentication_string')
                    ORDER BY COLUMN_NAME DESC LIMIT 1
                a  
                    SELECT COLUMN_NAME FROM information_schema.COLUMNS
                    WHERE TABLE_SCHEMA = 'mysql' AND TABLE_NAME = 'user' AND COLUMN_NAME IN ('Password', 'authentication_string')
                    ORDER BY COLUMN_NAME ASC  LIMIT 1
                zL
                    SELECT COALESCE(
                            CASE WHEN r   z = '' THEN NULL ELSE z, END,
                            CASE WHEN zu END
                        )
                    FROM mysql.user WHERE user = %s AND host = %s
                    asciizkencrypted was specified however it does not appear to be a valid hash expecting: *SHA1(SHA1(your_password))rq   zSELECT PASSWORD(%s)rv   TzPassword updatedzSET PASSWORD FOR %s@%s = %szPassword updated (old style)z<ALTER USER %s@%s IDENTIFIED WITH mysql_native_password AS %szPassword updated (new style)it  zjUPDATE mysql.user SET plugin = %s, authentication_string = %s, Password = '' WHERE User = %s AND Host = %smysql_native_passwordFLUSH PRIVILEGESzPassword forced updater   ra   )
maria_roledefaultneverintervalnowzRSELECT plugin, authentication_string FROM mysql.user WHERE user = %s AND host = %srb   ry   r|   z)ALTER USER %s@%s IDENTIFIED WITH %s AS %srw   z,ALTER USER %s@%s IDENTIFIED WITH %s USING %srx   z6ALTER USER %s@%s IDENTIFIED WITH %s USING PASSWORD(%s)r   z)ALTER USER %s@%s IDENTIFIED WITH %s AS 0xz)ALTER USER %s@%s IDENTIFIED WITH %s BY %sz#ALTER USER %s@%s IDENTIFIED WITH %sGRANTrootPROXYzPrivileges updatedzNew privileges grantedALLALL PRIVILEGESUSAGEzPrivileges updated: granted z
, revoked rp   zAttributes updated: %srR   z: r   r   zUser lockedzALTER USER %s@%s ACCOUNT UNLOCKzUser unlockedzUser will be lockedzUser will be unlockedzTLS requires updatedz
ALTER USERzGRANT %s ON *.* TO, z%s@%sz%s@%s REQUIRE NONE)rs   rr   rt   ru   ),r   r   user_get_hostnamesboolr   r   r%   bytesdecoder   r   r   r   Errorargsr   strr   get_password_expiration_policyis_password_expiredr   r	   r
   privileges_getr   privileges_revoker   setr7   rS   intersectionrh   rg   r   r   rA   rB   r   r   r+   r=   get_tls_requiresr^   rH   );r   r   r    r!   r}   r   rc   re   rd   r~   r   append_privssubtract_privsru   r;   r   r   r   r   roler   rs   rr   grant_optionr   r   	hostnamesrt   colAcolBcurrent_pass_hashr   eupdatemariadb_rolecurrent_password_policypassword_expiredcurrent_pluginr   r   	curr_privr   r   db_table_intersectgrant_privsrevoke_privs
after_privattribute_supportr   current_attributesattributes_to_changer3   valuedrE   rF   current_requires	pre_queryrC   s;                                                              r   user_modr     s}
    G
CL #6*D**62M&vt4	F	 fH~    
 (   
 (   7DGT!Wd1g ? BFtN %+OO$5a$8!/7(9(@(@(I%)1&"#56((  .[(  \$'<xkJ'Y\d[fg)/):1)=&$(::'+$,C!,,("NN+H4QUWiJjk"@C, &/mptvz  }O  pP  !Q&D #G  77?   &b  cF#,DMM0B#B4L&DVTSWdp&q#264F,2)7S,1o6P,0HH_`jMj$-2B(('dOMef'+$"G $NN ;=A4LJ#__.NFa F*!nQ&7;M&MII%a(,FPbim,nn!%#q(9=O(O
 "&%&QTXZ^`fhzS{&{O'*X[_aegm  pB  [C  +C9,*beikoqw  zL  eM  +M!%QQ4R\nuy4z1",,1`ci1i,j+VYn+nrvx|  E  rF  +F*UX\^bdjl~W*&KdTXZ`Ma&aO(("FNNO4#'  &vtT:FI  &/	&: 	+NHd$'+x/6>gT.A"6C#)#4#4 1&$hPTVbdn o&*G	+ "&/&9 'NHdy06%00,VT44Q]_ij"&' "%X]]_!5INN<L8M!M. '' !"&s8H+='>YxEXAY'Y"ZK# $(HX,>(?#iPXFYBZ(Z#[L #'s8H+='>YxEXAY'Y"ZK#'Ih,?(@3xPXGYCZ(Z#[L +/?;/N'+C'0B,C,P,PQTUaQb,c'd $+l#:#Ywk?YL7)+&&w/{#c,&77!;JUWcdC!,,|,q0-fdD(LZfhrs{+a/,VT4;Xdfpq"&O''T (dJGJ:)z"9G 2&9$  %u v%3FD$%G"%-)+&')$","2"2"4 :JC"448J38OSX8X49,S1: (2diik  lF  lF  lH  AI]g]`bgSRWAX  AI  7J  KC ",,'FtUYU_U_`tUuHvw+9&$+M( <NOc:d ,Q ,QQqrqxqxqz ,Qimijlm~  H\  \,@,C,O -.qD ,QA ,Q( ,Q @P+;UY("G'9$ #1&$#E *~fdD/QU[/[$$NN#BT4LQ'CNN#DtTlS)C/C1CG -T-B-B64QU-VW|+(C$$$ ,I 4sxx
6SWY]@^7_ _I+HHi%9:E&6utTlL&YOHHi1E%FGE&+dD\&9O0GM	fP	 s@P`pqqe %1$6$6 , $%66!9#4$*NN )U)@BTVZ\`(a%& %+NN3E$F*BC*+G %(,n AI,Qs$   ?_`4 +`:
`1(>`,,`1c                     |ry|rt        | |      }n|g}|D ]  }	 | j                  d||f        y# t        $ r | j                  d||f       Y :w xY w)NTzDROP USER IF EXISTS %s@%szDROP USER %s@%s)r   r   	Exception)r   r   r    r!   r   r   hostnames          r   user_deleter   [  su    &vt4	F	 @	@NN6x8HI@   	@NN,tX.>?	@s   3AAc                     | j                  d|f       | j                         }g }|D ]  }|j                  |d           |S )Nz+SELECT Host FROM mysql.user WHERE user = %sr   )r   rU   rh   )r   r   hostnames_rawr   hostname_raws        r   r   r   m  sM    
NN@4'JOO%MI% *a)* r   c                 
   i }|s| j                  d||f       n| j                  d|f       | j                         }d }|D ]8  }t        |t              rt	        |j                               }|st        j                  d|d         }nt        j                  d|d         }|/t        j                  d|d         }|s|rt        d|d   z        |j                  d	      j                  d
      }	|	D 
cg c]  }
 ||
j                                }	}
t        |	      }	|s$d|j                  d      v r|	j                  d       |j                  d      }|j                  |g       j                  |	       ; |S c c}
w )a   MySQL doesn't have a better method of getting privileges aside from the
    SHOW GRANTS query syntax, which requires us to then parse the returned string.
    Here's an example of the string that is returned from MySQL:

     GRANT USAGE ON *.* TO 'user'@'localhost' IDENTIFIED BY 'pass';

    This function makes the query and returns a dictionary containing the results.
    The dictionary format is the same as that returned by privileges_unpack() below.
    rM   zSHOW GRANTS FOR %sc                     | dk(  ry| S )Nr   r   r   rO   s    r   pickzprivileges_get.<locals>.pick  s      Hr   zYGRANT (.+) ON (.+) TO (['`"]).*\3@(['`"]).*\4( IDENTIFIED BY PASSWORD (['`"]).+\6)? ?(.*)r   zGRANT (.+) ON (.+) TO .*zGRANT (.+) TO (['`"]).*z*unable to parse the MySQL grant string: %srb   r   WITH GRANT OPTION   r      )r   rU   r%   r(   rS   r)   rV   matchr   rX   rZ   rY   normalize_col_grantsrh   
setdefaultextend)r   r   r    r   outputr]   r   grantr*   
privilegesrP   dbs               r   r   r   x  s    F.t=+dW5__F  &5 eT"(E((}  @E  FG  @H  IC((958DC; ((8%(CC##$PSXYZS[$[\\YYq\'',
/9:!d1779o:
: **5
"ciil2!!'*YYq\"b!((4M&5N M ;s   9F c                 R    dD ]!  }t        | |      \  }}|t        | ||      } # | S )zFix and sort grants on columns in privileges list

    Make ['SELECT (A, B)', 'INSERT (A, B)', 'DETELE']
    from ['SELECT (A', 'B)', 'INSERT (B', 'A)', 'DELETE'].
    See unit tests in tests/unit/plugins/modules/test_mysql_user.py
    )SELECTUPDATEINSERT
REFERENCES)has_grant_on_colhandle_grant_on_col)r   r   startends       r   r   r     sA     > E%j%8
s,ZDJ	E r   c                 j    d}d}t        |       D ]  \  }}d|z  |v r|}|d|v s|} n ||||fS y)z|Check if there is a statement like SELECT (colA, colB)
    in the privilege list.

    Return (start index, end index).
    Nz%s ())NN)	enumerate)r   r   r  r  nr   s         r   r  r    sh     E
CZ( 4E>T!EC S_ cz
 r   c                     ||k7  rZt        | d|       }dj                  | ||dz          }t        |      }|j                  |       |j	                  | |dz   d        |S t        |       }t        ||         ||<   |S )zNHandle cases when the privs like SELECT (colA, ...) is in the privileges list.NrR   rb   )rS   rB   sort_column_orderrh   r   )r   r  r  r   select_on_cols        r   r  r    s     |j%()		*U37";<)-8m$jq*+ M j!)&-8uMr   c                 4   | j                  d      }|d   }|d   j                  d      }|j                  d      }t        |      D ])  \  }}|j                         }|j                  d      ||<   + |j	                          |ddj                  |      dS )an  Sort column order in grants like SELECT (colA, colB, ...).

    MySQL changes columns order like below:
    ---------------------------------------
    mysql> GRANT SELECT (testColA, testColB), INSERT ON `testDb`.`testTable` TO 'testUser'@'localhost';
    Query OK, 0 rows affected (0.04 sec)

    mysql> flush privileges;
    Query OK, 0 rows affected (0.00 sec)

    mysql> SHOW GRANTS FOR testUser@localhost;
    +---------------------------------------------------------------------------------------------+
    | Grants for testUser@localhost                                                               |
    +---------------------------------------------------------------------------------------------+
    | GRANT USAGE ON *.* TO 'testUser'@'localhost'                                                |
    | GRANT SELECT (testColB, testColA), INSERT ON `testDb`.`testTable` TO 'testUser'@'localhost' |
    +---------------------------------------------------------------------------------------------+

    We should sort columns in our statement, otherwise the module always will return
    that the state has changed.
    (r   rb   r  r   `rR   )rZ   rstripr	  rY   sortrB   )	statementtmp	priv_namecolumnsicols         r   r  r     s    8 //#
CAI!fmmC G mmC GG$ $3iikYYs^
$ LLN $))G"455r   c           	      8   |dk(  rd}nd}i }g }| j                         j                  d      D ]  }|j                         j                  dd      }|d   j                  dd      }	|	d   j                  d	d      }
d
}t        |
      dkD  r |
d   dk(  s|
d   dk(  r|
d   d	z   }|
d   |	d<   t	        |	      D ]4  \  }}|j                  d      dk7  s||j                  d      ||	|<   6 |dj                  |	      z   |d<   d|d   v r|du rSt        j                  d|d         ||d   <   ||d      D ](  }|j                  t        j                  dd
|             * nt        j                  d|d   j                               ||d   <   ||d      D ](  }|j                  t        j                  dd
|             * n0|d   j                         j                  d      ||d   <   ||d      }t        ||d            ||d   <    |r
d|vrdg|d<   |S )a   Take a privileges string, typically passed as a parameter, and unserialize
    it into a dictionary, the same format as privileges_get() above. We have this
    custom format to avoid using YAML/JSON strings inside YAML playbooks. Example
    of a privileges string:

     mydb.*:INSERT,UPDATE/anotherdb.*:SELECT/yetanother.*:ALL

    The privilege USAGE stands for no privileges, so we add that in on *.* if it's
    not specified in the string, as MySQL will always provide this by default.
    r   "r  /:rb   r   .r    FUNCTION	PROCEDUREr   r  Tz,\s*(?=[^)]*(?:\(|$))z	\s*\(.*\)r   r   r   )rY   rZ   rsplitrg   r	  rB   rV   rh   subr8   r   )r   r   column_case_sensitiveensure_usagequoter   privsitempiecesdbprivpartsobject_typer  sides                 r   privileges_unpackr-  +  sM    v~FE

""3'  D$$S!,!!#q) q	Q'u:>uQx:5q[9P(S.KaF1I !( 	GGAtzz##%(-tzz#Fq		G  #((6"22q	&)$,$&HH-Evay$Qvay!q	* >ALLb!!<=> %'HH-EvayGX$Yvay!q	* >ALLb!!<=> !'q	 1 7 7 <F6!96!9%E 1q	1BCvayA DD V+ 	uMr   c                    |j                  dd      }|rPd|z  g}|s|j                  d       n|j                  d       dj                  |      }| j                  |||f       dj                  |D cg c]	  }|dvs| c}      }	|	d	k7  rXd
|	d|g}|s|j                  d       ||f}
n|j                  d       |f}
dj                  |      }| j                  ||
       | j                  d       y c c}w )N%%%zREVOKE GRANT OPTION ON %sz
FROM %s@%szFROM %sr   r   r   r  zREVOKE  ON r   )replacerh   rB   r   )r   r   r    r   r   r   r   rC   ppriv_stringrD   s              r   r   r   d  s    T*H,x78LL&LL#utTl+((tD!q/CADEKb&18<=LL&D\FLL#WFuf%
NN%& Es   4	C8>C8c                    |j                  dd      }dj                  |D cg c]	  }|dvs| c}      }d|d|g}	|s|	j                  d       ||f}
n|	j                  d       |}
t        |       }|r3|j	                  |       r"t        d	j                  |	      |
|      \  }	}
|	g}	d
|v r|	j                  d       d	j                  |	      }	t        |
t              r|
f}
	 | j                  |	|
       y c c}w # t        j                  t        j                  t        j                  f$ r/}t        d|dt        |
      d|	dt        |      d	      d }~ww xY w)Nr/  r0  r   r1  zGRANT r2  zTO %s@%szTO %sr   r   r   z0Error granting privileges, invalid priv string: z , params: z	, query: z , exception: r  )r3  rB   rh   r   r   rH   r%   r   r   r   ProgrammingErrorOperationalErrorInternalErrorr   )r   r   r    r   r   r;   r   r4  r5  rC   rD   r   r   s                r   r   r     sK    T*H((tD!q/CADEK!,h78E Z W"6*D..v6(%&,Ov$()HHUOE&#_uf%= E> ))<+H+H,JdJde _5@#f+uVYZ[V\!^ _ 	__s"   	C8C8%C= =2E/*EEc                 t    t        |       D cg c]  \  }}|d| }}}dj                  |      S c c}}w )zConverts privs dictionary to string of certain format.

    Args:
        priv (dict): Dict of privileges that needs to be converted to string.

    Returns:
        priv (str): String representation of input argument.
    r  r  )r   rB   )r   r3   val	priv_lists       r   convert_priv_dict_to_strr=    s:     7@oF(#sC%FIF88I Gs   4c                 <   d}| j                  |||f       | j                         }t        |t              rt	        |j                               }|sy|d   |d   |d   |d   d}| j                  d       | j                         }t        |t              rt	        |j                               }d	|d   j                         v rWd
}| j                  |||f       | j                         }t        |t              rt	        |j                               }|d   |d<   |S )zGet user resource limits.

    Args:
        cursor (cursor): DB driver cursor object.
        user (str): User name.
        host (str): User host name.

    Returns: Dictionary containing current resource limits.
    zSELECT max_questions AS MAX_QUERIES_PER_HOUR, max_updates AS MAX_UPDATES_PER_HOUR, max_connections AS MAX_CONNECTIONS_PER_HOUR, max_user_connections AS MAX_USER_CONNECTIONS FROM mysql.user WHERE User = %s AND Host = %sNr   rb   r      )MAX_QUERIES_PER_HOURMAX_UPDATES_PER_HOURMAX_CONNECTIONS_PER_HOURMAX_USER_CONNECTIONSr`   ra   z]SELECT max_statement_time AS MAX_STATEMENT_TIME FROM mysql.user WHERE User = %s AND Host = %sMAX_STATEMENT_TIME)r   r   r%   r(   rS   r)   rf   )r   r   r    rC   r*   current_limitsri   res_max_statement_times           r   get_resource_limitsrG    s   =E
 NN54,'
//
C #t3::<  !$A #A$'F #A	N NN%& H (D!)*HQK%%''AutTl+!'!2 ,d3%)*@*G*G*I%J"/Ea/H+,r   c                     |s|S i }t        |      D ]D  \  }}||vr| j                  d|z         	 t        |      }||j	                  |      k7  s@|||<   F |S # t        $ r | j                  d|z         Y >w xY w)a  Check and match limits.

    Args:
        module (AnsibleModule): Ansible module object.
        current (dict): Dictionary with current limits.
        desired (dict): Dictionary with desired limits.

    Returns: Dictionary containing parameters that need to change.
    z)resource_limits: key '%s' is unsupported.rq   z$Can't convert value '%s' to integer.)r   r   intr   get)r   currentdesiredneeds_to_changer3   r;  s         r   match_resource_limitsrN    s      Og& 'Sg !Ls!RS	Oc(C '++c""#&OC '   	O!G#!MN	Os   AA<;A<c                    t        |      }|j                  |      s| j                  d       |j                  d       d|j	                         d   j                         vrd|v r| j                  d       t        |||      }t        | ||      }|sy|r|ry	g }	t        |      D ]  \  }
}|	j                  |
d
|        d}|dd
j                  |	      z  z  }|j                  |||f       y	)a  Limit user resources.

    Args:
        module (AnsibleModule): Ansible module object.
        cursor (cursor): DB driver cursor object.
        user (str): User name.
        host (str): User host name.
        resource_limit (dict): Dictionary with desired limits.
        check_mode (bool): Run the function in check mode or not.

    Returns: True, if changed, False otherwise.
    zmThe server version does not match the requirements for resource_limits parameter. See module's documentation.rq   r`   ra   r   rD  z?MAX_STATEMENT_TIME resource limit is only supported by MariaDB.FTr   zALTER USER %s@%sz WITH %s)r   server_supports_alter_userr   r   r   rf   rG  rN  r   rh   rB   )r   r   r   r    resource_limitsr   r   rE  rM  r  r3   r;  rC   s                r   limit_resourcesrR    s    #6*D**62 Z 	[ NN%&)!,2244?2!bc(t<N+FNOTO: Co. )S

c3'() E	Z#((3-''E
NN54,'r   c                     |j                         dk(  rd}nD|j                         dk(  rd}n.|j                         dk(  rd|z  }n|j                         dk(  rd}| j                  d	z   ||f       y
)a1  Fuction to set passowrd expiration for user.

    Args:
        cursor (cursor): DB driver cursor object.
        user (str): User name.
        host (str): User hostname.
        password_expire (str): Password expiration mode.
        password_expire_days (int): Invterval of days password expires.
    r   zPASSWORD EXPIRE NEVERr   zPASSWORD EXPIRE DEFAULTr   zPASSWORD EXPIRE INTERVAL %d DAYr   zPASSWORD EXPIREzALTER USER %s@%s N)rf   r   )r   r   r    r   r   r  s         r   r   r   ?  sz     ')+					 I	--					 J	.59QR					 E	)%	
NN&2T4LAr   c                 z    |sd||ff}nd||ff} | j                   |  | j                         d   }t        |      S )a:  Function to get password policy for user.

    Args:
        cursor (cursor): DB driver cursor object.
        user (str): User name.
        host (str): User hostname.
        maria_role (bool, optional): mariadb or mysql. Defaults to False.

    Returns:
        policy (int): Current users password policy.
    z^SELECT IFNULL(password_lifetime, -1) FROM mysql.user             WHERE User = %s AND Host = %szSELECT JSON_EXTRACT(Priv, '$.password_lifetime') AS password_lifetime             FROM mysql.global_priv             WHERE User = %s AND Host = %sr   )r   r   rI  )r   r   r    r   r  policys         r   r   r   U  sX     +-14L9	+-14L9	 FNNI__q!Fv;r   c                 r    d||ff} | j                   |  | j                         d   }t        |      dk(  ryy)zFunction to check if password is expired

    Args:
        cursor (cursor): DB driver cursor object.
        user (str): User name.
        host (str): User hostname.

    Returns:
        expired (bool): True if expired, else False.
    zQSELECT password_expired FROM mysql.user             WHERE User = %s AND Host = %sr   YTF)r   r   r   )r   r   r    r  expireds        r   r   r   m  sF    +-14L9IFNNIoo"G
7|sr   c                 z    	 | j                  d       | j                          y# t        j                  $ r Y yw xY w)zChecks if the MySQL server supports user attributes.

    Args:
        cursor (cursor): DB driver cursor object.
    Returns:
        True if attributes are supported, False if they are not.
    z@SELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES LIMIT 0FT)r   r   r   r   )r   s    r   r   r     s=    YZ   s   !$ ::c                     | j                  d||f       | j                         }|r|d   rt        j                  |d         nd}|r|S dS )a-  Get attributes for a given user.

    Args:
        cursor (cursor): DB driver cursor object.
        user (str): User name.
        host (str): User host name.

    Returns:
        None if the user does not exist or the user has no attributes set, otherwise a dict of attributes set on the user
    zVSELECT attribute FROM INFORMATION_SCHEMA.USER_ATTRIBUTES WHERE user = %s AND host = %sr   N)r   r   r   loads)r   r   r    rm   js        r   r   r     sQ     NNknrtxmyzA!A$

1Q4DA 1tr   c                 B    t        |       }|dk(  rddlm} |S ddlm} |S )Nra   r   )r   )r   Pansible_collections.community.mysql.plugins.module_utils.implementations.mariadbr   Nansible_collections.community.mysql.plugins.module_utils.implementations.mysql)r   	db_engine	mariauser	mysqlusers       r   r   r     s&    )&1IIvtr   rJ   )F)NFF)T)2
__future__r   r   r   type__metaclass__r   r   rV   ansible.module_utils.sixr   >ansible_collections.community.mysql.plugins.module_utils.mysqlr   r   Sansible_collections.community.mysql.plugins.module_utils.implementations.mysql.hashr	   r
   r   r   r   r#   r+   r=   rH   rK   r^   rn   r   r   r   r   r   r   r   r  r  r  r-  r   r   r=  rG  rN  rR  r   r   r   r   r   r   r   r   r   <module>ri     s    B B    	 .		 	&&	;B @E`mF ]bzrz	$>B >0(6V6r':%_P5p!H)XB,0($*r   