1 # ===================================================================== 2 # updateUser: W-TW user account updater. 3 # 4 # Copyright (c) 2009,2010 Carlo Strozzi 5 # 6 # This program is free software; you can redistribute it and/or modify 7 # it under the terms of the GNU General Public License as published by 8 # the Free Software Foundation; version 2 dated June, 1991. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program; if not, write to the Free Software 17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 # 19 # ===================================================================== 20 21 # ===================================================================== 22 # Local variables and functions 23 # ===================================================================== 24 25 cgi.group = () 26 cgi.group.literal = () 27 cgi.auth.userid = () 28 cgi.auth.groups = () 29 cgi.grep.userid = () 30 cgi.auth.passwd = () 31 cgi.auth.firstname = () 32 cgi.auth.lastname = () 33 cgi.auth.fullname = () 34 cgi.auth.email = () 35 cgi.auth.openid = () 36 cgi.grep.openid = () 37 cgi.auth.gui = () 38 cgi.checksum = () 39 40 # Fields that must be cleared if set to empty in the input form 41 # should not default to null. 42 cgi.auth.other = $nil 43 44 tpl.var.checksum = () 45 group_editor = () 46 auth_groups = () 47 not_own = () 48 49 tmp2 = /dev/null 50 51 # ===================================================================== 52 # Main program 53 # ===================================================================== 54 55 csaGetArgs POST 56 57 #~ $REMOTE_ADDR 192.168.1.2 && csaExit.env 58 59 . $CSA_ROOT/lib/group-stuff.rc 60 61 # Set early template vars as appropriate. 62 tpl.var.tw.group = $'tbl_group.g_name' 63 tpl.var.tw.descr = $'tbl_group.g_descr' 64 tpl.var.tw.auth.userid = $'cgi.auth.userid' 65 66 #~ $REMOTE_ADDR 192.168.1.2 || csaExit.fault --back 0036 67 68 . $CSA_ROOT/lib/tpl-stuff.rc 69 70 csaTrue $CSA_AUTH_OK || csaExit.needauth 71 72 # Only *authenticated* global editors may edit other people's accounts, 73 # and even then, they can only enable/disable those accounts and assign 74 # them to different authorization groups, as well as granting/revoking 75 # the group-level editor status to them. 76 77 # This must be checked *before* a user is granted group-level editor 78 # privileges! 79 80 if (!~ $'cgi.auth.userid' $CSA_AUTH_USER) { 81 ~ ,$TNS_AUTH_GRP, *,editor,* || csaExit.needauth 82 not_own = true 83 } else { 84 ~ $'cgi.auth.email' () && csaExit.fault --back 1015 85 if (!~ $'cgi.auth.email' DELETE) { 86 ~ $'cgi.auth.passwd' . && csaExit.fault --back 1031 87 ~ $'cgi.auth.openid' . && csaExit.fault --back 1046 88 ~ $'cgi.auth.passwd' - && csaExit.fault --back 1033 89 ~ $'cgi.auth.firstname' . && csaExit.fault --back 1035 90 } 91 92 # Accept empty name/surname only if allowed. This test is currently 93 # disabled as this field cannot be verified and therefore it tells us 94 # nothing useful regarding the real identity of the requestor. The 95 # e-mail address is the sole piece of information that can be verified, 96 # to some extent. 97 98 #if (!csaTrue $TNS_SELFREG_ANONYMOUS) { 99 # ~ $'tpl.var.tw.auth.fullname' () && csaExit.fault 1032 100 #} 101 102 # Prevent self-suspending of accounts. Re-enabling will be 103 # doable only by a non-suspended global editor, because 104 # suspended accounts may not log into their profile management. 105 106 ~ $'cgi.auth.gui' -* && cgi.auth.gui = () 107 } 108 109 ~ $'cgi.auth.userid' . && csaExit.fault --back 1030 110 111 makeFullName --sreg $'cgi.auth.firstname' $'cgi.auth.lastname' 112 tpl.var.tw.auth.fullname = $CSA_RESULT 113 114 # Only *global* editors can change authorization groups for the 115 # account being edited. If such groups include "editor" it must 116 # be regarded as group-level editor for the current group. 117 118 if (~ ,$TNS_AUTH_GRP, *,editor,*) { 119 * = $'cgi.auth.groups' 120 while (!~ $#* 0) { 121 # Skip "editor" if this is going to end up in auth+dat !!! 122 if (csaIsConfirmed && ~ $1 editor) { 123 group_editor = true 124 } else { 125 if (~ $auth_groups *[a-z]*) { 126 ~ $auth_groups *, || auth_groups = $auth_groups, 127 } 128 auth_groups = $auth_groups$1 129 } 130 shift 131 } 132 } else cgi.auth.groups = () 133 134 # Set default auth groups if still unset. 135 ~ $auth_groups () && auth_groups = user 136 137 # Normalize as usual, it won't hurt. 138 #~ $auth_groups ,* || auth_groups = ,$auth_groups 139 #~ $auth_groups *, || auth_groups = $auth_groups, 140 141 # Grant further privileges if appropriate. 142 . $CSA_ROOT/lib/group-editor.rc 143 144 # Set Principal Lock Semaphore(s) (PLS). No lock on 'group+dat' 145 # is really needed until the requested action is confirmed. PLS 146 # on 'auth+dat' *is* needed, as otherwise races may indeed occur. 147 148 csaLock $TNS_USER_TABLE || csaExit.fault 149 150 # Fetch the requested auth record. 151 csa-tbl2rc --input $TNS_USER_TABLE \ 152 --key $'cgi.auth.userid' --prefix tbl_auth. > $tmp1 || 153 csaExit.fault 0003 csa-tbl2rc 154 155 . $tmp1 156 157 csaSum --file $tmp1 158 tpl.var.checksum = $CSA_RESULT 159 160 # Make sure the requested record hasn't changed in the meantime. 161 # (old logic, leave as comment for a while). 162 #if (csaIsInteractive && !~ $'tpl.var.checksum' $'cgi.checksum') { 163 # #~ $'cgi.checksum' () && csaExit.fault --back 1026 164 # csaExit.fault --back 0026 165 #} 166 167 # Make sure the requested record hasn't changed in the meantime. 168 if (!~ $'tpl.var.checksum' $'cgi.checksum') { 169 csaIsInteractive && CSA_EXIT_SCRIPT = ($CSA_EXIT_SCRIPT back) 170 csaExit.fault 0026 171 } 172 173 # Display target user's gravatar. This must be in MD5 format so I 174 # cannot rely on CSA_CMD_MD, because this could be anything. 175 * = `{echo -n $'tbl_auth.u_email' | md5sum} 176 ~ $1 () && csaExit.fault 0003 md5sum # just in case. 177 tpl.var.tw.auth.email.md5 = $1 178 179 # Test whether target account is global editor, and retain such status 180 # if that's the case. 181 182 if (~ ,$'tbl_auth.u_group', *,editor,*) { 183 184 # Global editor status is "sticky" and overrides anything else, 185 # with no need to specify any extra groups. This status can only 186 # be granted/removed manually by a sysadmin. Any slave applications 187 # relying on the Secondary Session File (SSF) that are to be 188 # accessible by global editors will have to account for the fact that 189 # these users always belong *only* into the (global) "editor" group. 190 191 auth_groups = editor 192 193 group_editor = () 194 195 tpl.var.tw.auth.group = $auth_groups 196 197 } else { 198 199 # Target account isn't a global editor. 200 201 tpl.var.tw.auth.group = $auth_groups 202 203 if (~ ,$CSA_SESSION(9)^, *,editor,*) { 204 205 # If the invoking user is a global editor, then the status 206 # of group editor is displayed for the target account only 207 # if explicitly specified. 208 209 ~ ,$'cgi.auth.groups', *,editor,* && group_editor = true 210 211 } else { 212 213 # If the invoking user is NOT a global editor, then it means 214 # that she can only be editing her own record, and no change 215 # in authorization groups is allowed, therefore the displayed 216 # value will be based solely on the previous status. 217 218 ~ ,$'tbl_group.g_editor', *,$'cgi.auth.userid',* && 219 group_editor = true 220 } 221 222 csaTrue $group_editor && 223 !~ ,$'tpl.var.tw.auth.group', *,editor,* && 224 tpl.var.tw.auth.group = editor,$'tpl.var.tw.auth.group' 225 } 226 227 # Make sure target user-id really exists, even if it's us, as it may 228 # have been deleted in the meantime by someone else, or by the sysadmin. 229 # If the user no longer exists, and it's us, then perform immediate log-off. 230 231 if (!grep -qe '^'$'cgi.grep.userid'$tab $TNS_USER_TABLE) { 232 REQUEST_METHOD = DELETE 233 . $CSA_ROOT/rpclib/logOut 234 } 235 236 # Complain if no name was provided, unless this is either an account 237 # deletion request or an update of an already existing account with 238 # no name. 239 if (!~ $'cgi.auth.email' DELETE) { 240 ~ $'tbl_auth.k_user' () && 241 !~ $'tpl.var.tw.auth.fullname' *,* && csaExit.fault --back 1035 242 } 243 244 ~ $'cgi.auth.gui' () && cgi.auth.gui = $'tbl_auth.u_gui' 245 246 #~ $REMOTE_ADDR 192.168.1.2 && csaExit.env 247 248 if (!csaIsConfirmed) { 249 250 csaSetClear tpl.var.tw.auth.email cgi.auth.email 251 csaSetClear tpl.var.tw.auth.openid cgi.auth.openid 252 csaSetClear tpl.var.tw.auth.gui cgi.auth.gui 253 csaSetClear tpl.var.tw.auth.other cgi.auth.other 254 255 if (csaTrue $not_own) { 256 tpl.if.tw.local.2 = '(::DEL:)' 257 tpl.fi.tw.local.2 = '(:DEL::)' 258 } else { 259 csaSetClear tpl.var.tw.auth.passwd cgi.auth.passwd 260 tpl.if.tw.local.1 = '(::DEL:)' 261 tpl.fi.tw.local.1 = '(:DEL::)' 262 } 263 264 if (csaIsFullPath --exists --quiet \ 265 $CSA_TPL_ROOT/tw-edit-user-confirm.txt) { 266 # custom update confirmation template. 267 tpl.include.html.body = $CSA_TPL_ROOT/tw-edit-user-confirm.txt 268 } else { 269 # default update confirmation template. 270 tpl.include.html.body = $tw_dstem/tw-edit-user-confirm.txt 271 } 272 273 if (!~ $'tpl.var.tw.auth.email' DELETE) { 274 tpl.if.tw.local.3 = '(::DEL:)' 275 tpl.fi.tw.local.3 = '(:DEL::)' 276 } 277 278 # PRG confirmation page must be regarded as a view. 279 tpl.if.tw.ispage = '(::DEL:)' 280 tpl.fi.tw.ispage = '(:DEL::)' 281 tpl.if.tw.printable = '(::DEL:)' 282 tpl.fi.tw.printable = '(:DEL::)' 283 tpl.if.tw.isview = () 284 tpl.fi.tw.isview = () 285 286 csaExit.ok $tpl_file 287 } 288 289 # In any case create target OpenID table if it does not yet exist. 290 if (!csaIsFullPath --exists --quiet $CSA_ROOT/var/pages/openid+dat) { 291 maketable --input \ 292 $CSA_ROOT/lib/openid.xrf > $CSA_ROOT/var/pages/openid+dat || 293 csaExit.fault 0003 maketable 294 } 295 296 if (~ $'cgi.auth.email' DELETE) { 297 tbl_upd.k_user = $'cgi.auth.userid' 298 tbl_upd.u_group = user 299 tbl_upd.u_passwd = x 300 tbl_upd.u_name = x 301 tbl_upd.u_sname = x 302 tbl_upd.u_email = x 303 tbl_upd.u_gui = default 304 tbl_upd.u_other = x 305 306 } else { 307 308 tbl_upd.k_user = $'cgi.auth.userid' 309 tbl_upd.u_group = $auth_groups 310 tbl_upd.u_gui = $'cgi.auth.gui' 311 312 if (!csaTrue $not_own) { 313 tbl_upd.u_passwd = $'cgi.auth.passwd' 314 tbl_upd.u_name = $'cgi.auth.firstname' 315 tbl_upd.u_sname = $'cgi.auth.lastname' 316 tbl_upd.u_email = $'cgi.auth.email' 317 tbl_upd.u_other = $'cgi.auth.other' 318 } 319 } 320 321 # Set PLS also on 'group+dat' on confirmation. 322 csaLock $CSA_ROOT/var/pages/$CSA_LANG/group+dat || csaExit.fault 323 324 csaOpen --fast $TNS_USER_TABLE || csaExit.fault 325 tmp2 = $CSA_RESULT 326 envtotable --match '^tbl_upd__2e[a-z]' \ 327 --strip-names '^tbl_upd__2e' | updtable --stdin \ 328 --key-columns k_user $TNS_USER_TABLE | sorttable > $tmp2 329 330 csaStatus || csaExit.fault 0003 envtotable/updtable/sorttable 331 332 #csaMkTemp debug; prtable -l300 < $tmp2 > $debug; csaExit.pcdata $debug 333 334 csaOpen --fast $CSA_ROOT/var/pages/$CSA_LANG/group+dat || csaExit.fault 335 tmp2 = $CSA_RESULT 336 awktable -H -i $CSA_ROOT/var/pages/$CSA_LANG/group+dat -- ' 337 "," $g_editor "," ~ /,'$'cgi.auth.userid','/ { 338 gsub(/,+'$'cgi.auth.userid','+/,",",$g_editor) 339 sub(/^,*'$'cgi.auth.userid'^'(,+|$)/,"",$g_editor) 340 sub(/,+'$'cgi.auth.userid','*$/,"",$g_editor) 341 sub(/^,+/,"",$g_editor); sub(/,+$/,"",$g_editor) 342 gsub(/,+/,",",$g_editor) 343 } 344 "'$group_editor'" == "true" && \ 345 "'$'cgi.auth.email'"' != "DELETE" && \ 346 $k_group == "'$'cgi.group'"' { 347 $g_editor = "'$'cgi.auth.userid','" $g_editor 348 } {print} 349 ' > $tmp2 || csaExit.fault 0003 awktable 350 351 #csaMkTemp debug; prtable -l300 < $tmp2 > $debug; csaExit.pcdata $debug 352 353 # Don't use "--fast" here, otherwise if we take the next "else" 354 # clause and no OpenID URL was entered, the OpenID table will 355 # be zeroed upon commit! 356 357 csaOpen --relaxed $CSA_ROOT/var/pages/openid+dat || csaExit.fault 358 tmp2 = $CSA_RESULT 359 360 if (~ $'cgi.auth.email' DELETE) { 361 362 grep -v -e $tab$'cgi.auth.userid'^'$' \ 363 $CSA_ROOT/var/pages/openid+dat > $tmp2 || csaExit.fault 0003 grep 364 365 } else { 366 367 if (~ $'cgi.auth.openid' http://* https://*) { 368 369 # Note: no two users are allowed to have the same OpenID URL. 370 # If this happens it must have been entered on purpose by 371 # the requestor so I'll always retain the older entry, on a 372 # first come, first serve basis. 373 374 awktable '-vid_='$'cgi.auth.openid' -H -i \ 375 $CSA_ROOT/var/pages/openid+dat -- ' 376 $openid_url == id_ {dup_ = $openid_url}{print} 377 END {if (dup_=="") print id_, "'$'cgi.auth.userid'"'}' | 378 sorttable > $tmp2 379 380 csaStatus || csaExit.fault 0003 awktable/sorttable 381 } 382 } 383 384 #csaMkTemp debug; prtable -l300 < $tmp2 > $debug; csaExit.pcdata $debug 385 386 csaLoadLib csaEmaillib.rc || csaExit.fault # before csaCommit . 387 388 # We won't use csaExit.ok at the end, so explicit commit is necessary. 389 csaCommit || csaExit.fault 390 391 # Notify user about the change, unless it's us. 392 393 if (csaTrue $not_own && ~ $'cgi.auth.email' *'@'*.*) { 394 395 # If no custom email template exists then use default. 396 if (!csaIsFullPath --exists --quiet \ 397 $CSA_TPL_ROOT/tw-account-updated-email.txt) { 398 tpl_email = (--file-root $tw_dstem tw-account-updated-email.txt) 399 } else tpl_email = tw-account-updated-email.txt 400 401 TNS_EMAIL_TO = $'cgi.auth.email' \ 402 tpl.var.tw.auth.userid = $'cgi.auth.userid' { csaSendMail $tpl_email } 403 } 404 405 # Immediately log this user out if she deleted her own account. 406 if (!csaTrue $not_own && ~ $'cgi.auth.email' DELETE) { 407 REQUEST_METHOD = DELETE 408 . $CSA_ROOT/rpclib/logOut 409 } 410 411 ~ ,$CSA_SESSION(9)^, *,editor,* || csaExit.location \ 412 $CSA_RPC_URI/$CSA_LANG/$'cgi.group'/$TNS_GROUP_HOME(2) 413 414 csaExit.location $CSA_RPC_URI/$CSA_LANG/$'cgi.group'/tw-users 415 416 #EOF