--- loncom/interface/lonuserutils.pm	2019/08/26 01:28:51	1.184.4.5
+++ loncom/interface/lonuserutils.pm	2023/09/02 22:27:50	1.184.4.10.2.3
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Utility functions for managing LON-CAPA user accounts
 #
-# $Id: lonuserutils.pm,v 1.184.4.5 2019/08/26 01:28:51 raeburn Exp $
+# $Id: lonuserutils.pm,v 1.184.4.10.2.3 2023/09/02 22:27:50 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -510,7 +510,7 @@ END
 ";
     } elsif ($mode eq 'modifycourse') {
         $auth_checks .= "
-    if (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '') {
+    if ((current.argfield !== null) && (current.argfield !== undefined) && (current.argfield !== '') && (vf.elements[current.argfield].value == null || vf.elements[current.argfield].value == '')) {
 ";
     }
     if ( ($mode eq 'createcourse') || ($mode eq 'modifycourse') ) {
@@ -532,7 +532,7 @@ END
 END
     } else {
         my ($numrules,$intargjs) =
-            &passwd_validation_js('vf.elements[current.argfield].value',$domain);
+            &Apache::loncommon::passwd_validation_js('vf.elements[current.argfield].value',$domain);
         $auth_checks .= (<<END);
     foundatype=1;
     if (current.argfield == null || current.argfield == '') {
@@ -543,13 +543,15 @@ END
             case 'krb':
                 alertmsg = '$alert{'krb'}';
                 break;
-            case 'loc':
             case 'int':
                 alertmsg = '$alert{'ipass'}';
                 break;
             case 'fsys':
                 alertmsg = '$alert{'ipass'}';
                 break;
+            case 'loc':
+                alertmsg = '';
+                break;
             default:
                 alertmsg = '';
         }
@@ -650,137 +652,6 @@ END
     return $result;
 }
 
-sub passwd_validation_js {
-    my ($currpasswdval,$domain) = @_;
-    my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
-    my ($min,$max,@chars,$numrules,$intargjs,%alert);
-    $numrules = 0;
-    $min = $Apache::lonnet::passwdmin;
-    if (ref($passwdconf{'chars'}) eq 'ARRAY') {
-        if ($passwdconf{'min'} =~ /^\d+$/) {
-            if ($passwdconf{'min'} > $min) {
-                $min = $passwdconf{'min'};
-            }
-        }
-        if ($passwdconf{'max'} =~ /^\d+$/) {
-            $max = $passwdconf{'max'};
-            $numrules ++;
-        }
-        @chars = @{$passwdconf{'chars'}};
-        if (@chars) {
-            $numrules ++;
-        }
-    }
-    if ($min > 0) {
-        $numrules ++;
-    }
-    if (($min > 0) || ($max ne '') || (@chars > 0)) {
-        my $alertmsg = &mt('Initial password did not satisfy requirement(s):').'\n\n';
-        if ($min) {
-            $alert{'min'} = &mt('minimum [quant,_1,character]',$min).'\n';
-        }
-        if ($max) {
-            $alert{'max'} = &mt('maximum [quant,_1,character]',$max).'\n';
-        }
-        my (@charalerts,@charrules);
-        if (@chars) {
-            if (grep(/^uc$/,@chars)) {
-                push(@charalerts,&mt('contain at least one upper case letter'));
-                push(@charrules,'uc');
-            }
-            if (grep(/^lc$/,@chars)) {
-                push(@charalerts,&mt('contain at least one lower case letter'));
-                push(@charrules,'lc');
-            }
-            if (grep(/^num$/,@chars)) {
-                push(@charalerts,&mt('contain at least one number'));
-                push(@charrules,'num');
-            }
-            if (grep(/^spec$/,@chars)) {
-                push(@charalerts,&mt('contain at least one non-alphanumeric'));
-                push(@charrules,'spec');
-            }
-        }
-        $intargjs = qq|            var rulesmsg = '';\n|.
-                    qq|            var currpwval = $currpasswdval;\n|;
-            if ($min) {
-                $intargjs .= qq|
-            if (currpwval.length < $min) {
-                rulesmsg += ' - $alert{min}';
-            }
-|;
-            }
-            if ($max) {
-                $intargjs .= qq|
-            if (currpwval.length > $max) {
-                rulesmsg += ' - $alert{max}';
-            }
-|;
-            }
-            if (@chars > 0) {
-                my $charrulestr = '"'.join('","',@charrules).'"';
-                my $charalertstr = '"'.join('","',@charalerts).'"';
-                $intargjs .= qq|            var brokerules = new Array();\n|.
-                             qq|            var charrules = new Array($charrulestr);\n|.
-                             qq|            var charalerts = new Array($charalertstr);\n|;
-                my %rules;
-                map { $rules{$_} = 1; } @chars;
-                if ($rules{'uc'}) {
-                    $intargjs .= qq|
-            var ucRegExp = /[A-Z]/;
-            if (!ucRegExp.test(currpwval)) {
-                brokerules.push('uc');
-            }
-|;
-                }
-                if ($rules{'lc'}) {
-                    $intargjs .= qq|
-            var lcRegExp = /[a-z]/;
-            if (!lcRegExp.test(currpwval)) {
-                brokerules.push('lc');
-            }
-|;
-                }
-                if ($rules{'num'}) {
-                     $intargjs .= qq|
-            var numRegExp = /[0-9]/;
-            if (!numRegExp.test(currpwval)) {
-                brokerules.push('num');
-            }
-|;
-                }
-                if ($rules{'spec'}) {
-                     $intargjs .= q|
-            var specRegExp = /[!"#$%&'()*+,\-.\/:;<=>?@[\\^\]_`{\|}~]/;
-            if (!specRegExp.test(currpwval)) {
-                brokerules.push('spec');
-            }
-|;
-                }
-                $intargjs .= qq|
-            if (brokerules.length > 0) {
-                for (var i=0; i<brokerules.length; i++) {
-                    for (var j=0; j<charrules.length; j++) {
-                        if (brokerules[i] == charrules[j]) {
-                            rulesmsg += ' - '+charalerts[j]+'\\n';
-                            break;
-                        }
-                    }
-                }
-            }
-|;
-            }
-            $intargjs .= qq|
-            if (rulesmsg != '') {
-                rulesmsg = '$alertmsg'+rulesmsg;
-                alert(rulesmsg);
-                return false;
-            }
-|;
-    }
-    return ($numrules,$intargjs);
-}
-
 ###############################################################
 ###############################################################
 sub upload_manager_javascript_forward_associate {
@@ -3661,6 +3532,8 @@ END
         setSections(formname,'$crstype');
         if (seccheck == 'ok') {
             opener.document.$callingform.newsecs.value = formname.sections.value;
+        } else {
+            return;
         }
 END
     } else {
@@ -4933,6 +4806,16 @@ sub upfile_drop_add {
                     my (%userres,%authres,%roleres,%idres);
                     my $singlesec = '';
                     if ($role eq 'st') {
+                        if (($context eq 'domain') && ($changeauth eq 'Yes') && (!$newuser)) {
+                            if ((&Apache::lonnet::allowed('mau',$userdomain)) &&
+                                (&Apache::lonnet::homeserver($username,$userdomain) ne 'no_host')) {
+                                if ((($amode =~ /^krb4|krb5|internal$/) && $password ne '') ||
+                                     ($amode eq 'localauth')) {
+                                    $authresult =
+                                        &Apache::lonnet::modifyuserauth($userdomain,$username,$amode,$password);
+                                }
+                            }
+                        }
                         my $sec;
                         if (ref($userinfo{$i}{'sections'}) eq 'ARRAY') {
                             if (@secs > 0) {
@@ -4974,16 +4857,16 @@ sub upfile_drop_add {
                                     }
                                 }
                             }
-                            if (!$multiple) {
-                                ($userresult,$authresult,$roleresult,$idresult) = 
-                                    &modifyuserrole($context,$setting,
-                                                    $changeauth,$cid,$userdomain,$username, 
-                                                    $id,$amode,$password,$fname,
-                                                    $mname,$lname,$gen,$singlesec,
-                                                    $env{'form.forceid'},$desiredhost,
-                                                    $email,$role,$enddate,$startdate,
-                                                    $checkid,$inststatus);
-                            }
+                        }
+                        if (!$multiple) {
+                            ($userresult,$authresult,$roleresult,$idresult) = 
+                                &modifyuserrole($context,$setting,
+                                                $changeauth,$cid,$userdomain,$username, 
+                                                $id,$amode,$password,$fname,
+                                                $mname,$lname,$gen,$singlesec,
+                                                $env{'form.forceid'},$desiredhost,
+                                                $email,$role,$enddate,$startdate,
+                                                $checkid,$inststatus);
                         }
                     }
                     if ($multiple) {
@@ -5103,7 +4986,11 @@ sub passwdrule_alerts {
             my %passwdconf = &Apache::lonnet::get_passwdconf($domain);
             $warning = '<b>'.&mt('Password requirement(s) unmet for one or more users:').'</b><ul>';
             if ($showrules{'min'}) {
-                $warning .= '<li>'.&mt('minimum [quant,_1,character]',$passwdconf{'min'}).'</li>';
+                my $min = $passwdconf{'min'};
+                if ($min eq '') {
+                    $min = $Apache::lonnet::passwdmin;
+                }
+                $warning .= '<li>'.&mt('minimum [quant,_1,character]',$min).'</li>';
             }
             if ($showrules{'max'}) {
                 $warning .= '<li>'.&mt('maximum [quant,_1,character]',$passwdconf{'max'}).'</li>';
@@ -5995,6 +5882,70 @@ sub can_modify_userinfo {
     return %canmodify;
 }
 
+sub can_change_internalpass {
+    my ($uname,$udom,$crstype,$permission) = @_;
+    my $canchange;
+    if (&Apache::lonnet::allowed('mau',$udom)) {
+        $canchange = 1;
+    } elsif ((ref($permission) eq 'HASH') && ($permission->{'mip'}) &&
+             ($udom eq $env{'request.role.domain'})) {
+        unless ($env{'course.'.$env{'request.course.id'}.'.internal.nopasswdchg'}) {
+            my ($cnum,$cdom) = &get_course_identity();
+            if ((&Apache::lonnet::is_course_owner($cdom,$cnum)) && ($udom eq $env{'user.domain'})) {
+                my @userstatuses = ('default');
+                my %userenv = &Apache::lonnet::userenvironment($udom,$uname,'inststatus');
+                if ($userenv{'inststatus'} ne '') {
+                    @userstatuses =  split(/:/,$userenv{'inststatus'});
+                }
+                my $noupdate = 1;
+                my %passwdconf = &Apache::lonnet::get_passwdconf($cdom);
+                if (ref($passwdconf{'crsownerchg'}) eq 'HASH') {
+                    if (ref($passwdconf{'crsownerchg'}{'for'}) eq 'ARRAY') {
+                        foreach my $status (@userstatuses) {
+                            if (grep(/^\Q$status\E$/,@{$passwdconf{'crsownerchg'}{'for'}})) {
+                                undef($noupdate);
+                                last;
+                            }
+                        }
+                    }
+                }
+                if ($noupdate) {
+                    return;
+                }
+                my %owned = &Apache::lonnet::courseiddump($cdom,'.',1,'.',
+                                                          $env{'user.name'}.':'.$env{'user.domain'},
+                                                          undef,undef,undef,'.');
+                my %roleshash = &Apache::lonnet::get_my_roles($uname,$udom,'userroles',
+                                                              ['active','future']);
+                foreach my $key (keys(%roleshash)) {
+                    my ($name,$domain,$role) = split(/:/,$key);
+                    if ($role eq 'st') {
+                        next if (($name eq $cnum) && ($domain eq $cdom));
+                        if ($owned{$domain.'_'.$name}) {
+                            if (ref($owned{$domain.'_'.$name}) eq 'HASH') {
+                                if ($owned{$domain.'_'.$name}{'nopasswdchg'}) {
+                                    $noupdate = 1;
+                                    last;
+                                }
+                            }
+                        } else {
+                            $noupdate = 1;
+                            last;
+                        }
+                    } else {
+                        $noupdate = 1;
+                        last;
+                    }
+                }
+                unless ($noupdate) {
+                    $canchange = 1;
+                }
+            }
+        }
+    }
+    return $canchange;
+}
+
 sub check_usertype {
     my ($dom,$uname,$rules,$curr_rules,$got_rules) = @_;
     my $usertype;
@@ -6117,10 +6068,16 @@ sub get_permission {
             }
         }
         if ($env{'request.course.id'}) {
-            my $user = $env{'user.name'}.':'.$env{'user.domain'};
+            my $user;
+            if (($env{'user.name'} ne '') && ($env{'user.domain'} ne '')) {
+                $user = $env{'user.name'}.':'.$env{'user.domain'};
+            }
             if (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.courseowner'} eq
                                   $user)) {
                 $permission{'owner'} = 1;
+                if (&Apache::lonnet::allowed('mip',$env{'request.course.id'})) {
+                    $permission{'mip'} = 1;
+                }
             } elsif (($user ne '') && ($env{'course.'.$env{'request.course.id'}.'.internal.co-owners'} ne '')) {
                 if (grep(/^\Q$user\E$/,split(/,/,$env{'course.'.$env{'request.course.id'}.'.internal.co-owners'}))) {
                     $permission{'co-owner'} = 1;
@@ -6157,8 +6114,9 @@ sub get_permission {
         }
     }
     my $allowed = 0;
-    foreach my $perm (values(%permission)) {
-        if ($perm) { $allowed=1; last; }
+    foreach my $key (keys(%permission)) {
+        next if (($key eq 'owner') || ($key eq 'co-owner'));
+        if ($permission{$key}) { $allowed=1; last; }
     }
     return (\%permission,$allowed);
 }
@@ -6367,7 +6325,7 @@ sub verify_authen {
         $finish = "document.$formname.submit();";
     }
     my ($numrules,$intargjs) =
-        &passwd_validation_js('argpicked',$domain);
+        &Apache::loncommon::passwd_validation_js('argpicked',$domain);
     my $outcome = <<"ENDSCRIPT";
 
 function auth_check() {
@@ -6571,7 +6529,7 @@ sub selfenrollment_administration {
         }
     }
     if ($settings{'internal.selfenrollmgrdc'} ne '') {
-        my @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
+        @in_domain = split(/,/,$settings{'internal.selfenrollmgrdc'});
         my @diffs = &Apache::loncommon::compare_arrays(\@in_domain,$possconfigs);
         unless (@diffs) {
             return (\@in_course,\@in_domain);