Advertisement
Guest User

Untitled

a guest
May 10th, 2017
641
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 11.20 KB | None | 0 0
  1. #!/usr/bin/perl -wT
  2.  
  3. use strict;
  4. use CGI;
  5. use CGI::Carp 'fatalsToBrowser';
  6. use POSIX qw(strftime);
  7. use Mail::Mailer qw(sendmail);
  8. use Net::NIS;
  9. use Net::LDAPS;
  10. use Net::LDAP qw(LDAP_SUCCESS LDAP_ALREADY_EXISTS);
  11. use Unicode::Map8;
  12. use Unicode::String qw(utf16);
  13.  
  14. $CGI::POST_MAX = 1024 * 100;    # max 100K posts
  15. $CGI::DISABLE_UPLOADS = 1;  # no uploads
  16. $ENV{PATH} = '/bin:/usr/bin';
  17.  
  18. use constant ROOTDN   => 'OU=User Accounts,DC=internal,DC=XXXX,DC=com';
  19. use constant DOMAIN   => 'internal.XXXX.com';
  20. use constant SERVER   => ['wdc01.' . DOMAIN, 'wdc02.' . DOMAIN, 'wdc03.' . DOMAIN];
  21. use constant ADMIN    => 'XXXXX';
  22. use constant ADMPW    => 'YYYYY';
  23. use constant NORMAL_ACCOUNT   => 0x200;
  24. # the JavaScript code for validating web form
  25. use constant JSCRIPT  => '
  26.  
  27. // has the user entered mail and username already?
  28. var mail_changed = false;
  29. var user_changed = false;
  30.  
  31. // verify that mandatory fields have been filled out
  32. function check(aForm) {
  33.     if (aForm.first.value.length < 2) {
  34.         alert("Please enter first name!");
  35.         aForm.first.focus();
  36.         return false;
  37.     }
  38.     if (aForm.last.value.length < 2) {
  39.         alert("Please enter last name!");
  40.         aForm.last.focus();
  41.         return false;
  42.     }
  43.     if (aForm.user.value.length < 3) {
  44.         alert("Please enter username!");
  45.         aForm.user.focus();
  46.         return false;
  47.     }
  48.     if (aForm.password.value.length < 8) {
  49.         alert("Please enter random password!");
  50.         aForm.password.focus();
  51.         return false;
  52.     }
  53.     if (aForm.mail.value.length < 5) {
  54.         alert("Please enter user mail address!");
  55.         aForm.mail.focus();
  56.         return false;
  57.     }
  58.     return true;
  59. }
  60.  
  61. // generate mail address and username - unless user has entered them already
  62. function generate(aForm) {
  63.     if (aForm.first.value.length < 2 ||
  64.         aForm.last.value.length < 2)
  65.         return;
  66.  
  67.     // use the 1st letter of first name + last name to generate user name
  68.     if (! user_changed)
  69.         aForm.user.value =
  70.             aForm.first.value.substring(0, 1).toLowerCase() +
  71.             aForm.last.value.substring(0, 7).toLowerCase();
  72.  
  73.     // use first name + last name to generate the mail address
  74.     if (! mail_changed)
  75.         aForm.mail.value =
  76.             ("XXXX" == aForm.company.value ? "" : "ext-") +
  77.             aForm.first.value + "." + aForm.last.value;
  78. }
  79.    
  80. ';
  81.  
  82. my @CITIES = qw(Bochum Berlin Bayern);
  83. my @COMPANIES = qw(
  84.     XXXX
  85.     YYYY_Consulting
  86.     ZZZZ
  87. );
  88.  
  89.  
  90. my @VOWELS = split //, 'AEUaeiou34';
  91. my @CONSONANTS = split //, 'CDFGHJKLMNPQRSTVWXbcdfhjkmnprstvwx25679';
  92.  
  93. sub genpass($) {
  94.         my ($len, $pass);
  95.         $len = shift;
  96.  
  97.         do {
  98.                 $pass = '';
  99.                 do {
  100.                         $pass .= $CONSONANTS[rand @CONSONANTS];
  101.                         $pass .= $VOWELS[rand @VOWELS];
  102.                 } while (length $pass < $len);
  103.  
  104.                 # escape here when generating 2-chars salt
  105.                 last if $len < 8;
  106.  
  107.         # make sure the password contains 2 digit and 2 letters
  108.         } while ($pass =~ tr/0-9// < 2 ||
  109.                  $pass =~ tr/a-z// < 2 ||
  110.                  $pass =~ tr/A-Z// < 2);
  111.  
  112.         return $pass;
  113. }
  114.  
  115. my ($query, $cookie, %defaults, %passwd, $maxuid, $ldap, $result, $mta,
  116.     $charmap, $unipwd, $rot13, $user, $first, $last, $mail, $city, $company,
  117.     $pass, $crypt, $inform, $fullname, $dn, $date, $home, $pst, $gid);
  118.  
  119. $query = new CGI;
  120.  
  121. # untaint user input
  122. $first = $1         if $query->param('first') =~ /(\w[\w -]{1,10}\w)/;
  123. $last = $1          if $query->param('last') =~ /(\w[\w -]{1,10}\w)/;
  124. $user = $1          if $query->param('user') =~ /(\w{3,12})/;
  125. $password = $1          if $query->param('password') =~ /(\w{8})/;
  126. $mail   = "\L$1\@XXXX.com"  if $query->param('mail') =~ /([\w.-]{3,30})/;
  127. $inform = "\L$1\@XXXX.com"  if $query->param('inform') =~ /([\w.-]{3,30})/;
  128.  
  129. for (@COMPANIES) {
  130.     if ($query->param('company') =~ /($_)/) {
  131.         $company = $1;
  132.         last;
  133.     }
  134. }
  135.  
  136. for (@CITIES) {
  137.     if ($query->param('city') =~ /($_)/) {
  138.         $city = $1;
  139.         last;
  140.     }
  141. }
  142.  
  143. unless ($user and $password and $first and $last and
  144.     $city and $company and $mail) {
  145.  
  146.     print $query->header,
  147.         $query->start_html(-title => 'Create new user / Enter data',
  148.                    -script => JSCRIPT),
  149.         '<p><img src="/XXXX.png" width=241 height=50 alt="XXXX"></p>';
  150.  
  151.     # retrieve saved values from the cookie
  152.     %defaults = $query->cookie('defaults');
  153.     $defaults{company} = 'XXXX' unless $defaults{company};
  154.     $defaults{city} = 'Bochum' unless $defaults{city};
  155.  
  156.     print $query->start_multipart_form(-onsubmit => 'return check(this)'),
  157.         '<table cellpadding=4>',
  158.             '<tr><td colspan=2>Optional batch file:</td></tr>',
  159.             '<tr><td colspan=2>',
  160.         $query->filefield(-name => 'uploaded_file',
  161.                 -size => 14),
  162.         '</td></tr>',
  163.             '<tr><td colspan=2><hr></td></tr>',
  164.             '<tr><td>First name:</td><td>',
  165.         $query->textfield(-name => 'first',
  166.                   -onchange => 'generate(this.form);',
  167.                   -size => 12),
  168.         '</td></tr>',
  169.             '<tr><td>Last name:</td><td>',
  170.         $query->textfield(-name => 'last',
  171.                   -onchange => 'generate(this.form);',
  172.                   -size => 12),
  173.         '</td></tr>',
  174.             '<tr><td>Username:</td><td>',
  175.         $query->textfield(-name => 'user',
  176.                   -onchange => 'user_changed = true;',
  177.                   -size => 12,
  178.                   -maxlength => 8),
  179.         '</td></tr>',
  180.             '<tr><td>Password:</td><td>',
  181.         $query->textfield(-name => 'password',
  182.                   -value => genpass(8),
  183.                   -override => 1,
  184.                   -size => 12),
  185.         '</td></tr>',
  186.             '<tr><td>Company:</td><td>',
  187.         $query->scrolling_list(-name => 'company',
  188.                        -onchange => 'generate(this.form);',
  189.                    -values => \@COMPANIES,
  190.                    #-default => 'XXXX',
  191.                    -default => $defaults{company},
  192.                    -size => 6),
  193.         '</td></tr>',
  194.             '<tr><td>City:</td><td>',
  195.         $query->scrolling_list(-name => 'city',
  196.                    -values => \@CITIES,
  197.                    #-default => 'Bochum',
  198.                    -default => $defaults{city},
  199.                    -size => 4),
  200.         '</td></tr>',
  201.             '<tr><td colspan=2>User mail address:</td></tr>',
  202.         '<tr><td colspan=2>',
  203.         $query->textfield(-name => 'mail',
  204.                   -style => 'text-align: right',
  205.                   -onchange => 'mail_changed = true;',
  206.                   -size => 24),
  207.         '@XXXX.com</td></tr>',
  208.             '<tr><td colspan=2>Also send password to:</td></tr>',
  209.             '<tr><td colspan=2>(this input is optional)</td></tr>',
  210.         '<tr><td colspan=2>',
  211.         $query->textfield(-name => 'inform',
  212.                   -style => 'text-align: right',
  213.                   -value => $defaults{inform},
  214.                   -size => 24),
  215.         '@XXXX.com</td></tr>',
  216.         '<tr><td>&nbsp;</td><td>',
  217.         $query->submit(-value => 'Create user'),
  218.         '</td></tr>',
  219.         $query->end_form;
  220. } else {
  221.     # save the entered values for a day
  222.     %defaults = (company => $company,
  223.              city => $city,
  224.              inform => $query->param('inform'));
  225.  
  226.     print $query->header(-cookie => $query->cookie(-name => 'defaults',
  227.                                -value => \%defaults,
  228.                                -expires =>'+1d')),
  229.         $query->start_html(-title => 'Create new user / Data submitted'),
  230.         '<p><img src="/XXXX.png" width=241 height=50 alt="XXXX"></p>';
  231.  
  232.     # create the new user in active directory
  233.     ($rot13 = ADMPW) =~ y/A-Za-z/N-ZA-Mn-za-m/;
  234.     $ldap = Net::LDAPS->new(SERVER) or
  235.         die('Can not connect to LDAP server');
  236.     $ldap->bind(ADMIN . '@' . DOMAIN, password => $rot13) or
  237.         die('Can not bind to LDAP server as ' . ADMIN);
  238.  
  239.     $fullname = "$first $last";
  240.     $dn = "cn=$user," . ROOTDN;
  241.     $charmap = Unicode::Map8->new('latin1') or die $!;
  242.     $unipwd = $charmap->tou(qq{"$password"})->byteswap()->utf16();
  243.  
  244.     $result = $ldap->add($dn,
  245.         attr => [
  246.             objectClass => 'user',
  247.             sAMAccountName  => $user,
  248.             userPrincipalName => $user . '@' . DOMAIN,
  249.             givenName   => $first,
  250.             sn      => $last,
  251.             displayName => "$last $first ($company/$city)",
  252.             description => $fullname,
  253.             mail        => $mail,
  254.             l       => $city,
  255.             physicalDeliveryOfficeName => $city,
  256.             company     => $company,
  257.             # Must set password later because of policy
  258.             #unicodePwd => $unipwd,
  259.             homeDrive   => 'H:',
  260.             homeDirectory   =>
  261.                 "\\\\internal.XXXX.com\\home\\$user",
  262.         ]
  263.     );
  264.     if (LDAP_SUCCESS != $result->code) {
  265.         if (LDAP_ALREADY_EXISTS == $result->code) {
  266.             print "<p>User $user already exists!</p>\n",
  267.                 $query->end_html;
  268.             exit;
  269.         }
  270.         die 'Failed to add user: ', $result->error;
  271.     }
  272.  
  273.     $result = $ldap->modify($dn, replace => { unicodePwd => $unipwd } );
  274.     $result->code && die 'Failed to modify user: ', $result->error;
  275.  
  276.     $result = $ldap->modify($dn, replace => { pwdLastSet => 0 } );
  277.     $result->code && die 'Failed to modify user: ', $result->error;
  278.  
  279.     $result = $ldap->modify($dn,
  280.         replace => { userAccountControl => NORMAL_ACCOUNT } );
  281.     $result->code && die 'Failed to enable user: ', $result->error;
  282.  
  283.     $ldap->unbind();
  284.  
  285. #goto SKIPMAIL;
  286.  
  287.     # send the mail to the new user and the inform person
  288.     $mta = Mail::Mailer->new();
  289.     die "Can not send mail: $!\n" unless $mta->open({
  290.         From    => q{"XXXX IT" <it@XXXX.com>},
  291.         To      => $mail,
  292.         # send a copy to IT and eventually to contact person
  293.         Cc      => join(',', 'it@XXXX.com', $inform),
  294.         Subject => "IT-INFOS: Windows account infos for $first $last",
  295.     });
  296.  
  297.     print $mta qq{
  298.  
  299. Dear $first $last,
  300.  
  301.  
  302. the XXXX Windows account infos for you are:
  303.  
  304. User name: INTERNAL\\$user
  305. Password: $password
  306.  
  307. Your home directory
  308. \\\\internal.XXXX.com\\home\\$user
  309. will be mounted as drive H:
  310.  
  311.  
  312. Regards,
  313. XXXX IT team
  314.  
  315.  
  316. PS: If you have received the account infos
  317.     for $first $last because
  318.     you are listed as the contact person
  319.     for him/her, then please forward the login
  320.     data and treat it as highly confidential!
  321. };
  322.     $mta->close();
  323.  
  324. #SKIPMAIL:
  325.  
  326.     # print instructions for creating Unix dirs
  327.     $date = strftime '%F', localtime;
  328.     $home = "/mnt/nas02/hom01/home/$user";
  329.     $pst = "/mnt/nas02/pst01/home_pst/$user";
  330.     # use group XXXX (5675) for internals
  331.     # and XXXX_ext (5579) for externals
  332.     $gid = ($company eq 'XXXX' ? '5675' : '5579');
  333.  
  334.     # find the max uid in NIS
  335.     tie %passwd, 'Net::NIS', 'passwd.byname' or
  336.         die "Cannot tie to passwd YP map: $yperr\n";
  337.  
  338.     $maxuid = 0;
  339.     while (my ($key, $value) = each %passwd) {
  340.         my $uid = (split ':', $value)[2];
  341.         $maxuid = $uid if $uid > $maxuid;
  342.     }
  343.     $maxuid++;
  344.  
  345.         $crypt = crypt($pass, genpass(2));
  346.  
  347.         printf '<p>The user <b>%s</b> with password <b>%s</b> ' .
  348.                 'has been created in Active Directory under %s</p> ' .
  349.                 '<p>Please <b>ssh root@XXX01</b> and issue the commands:</p>',
  350.                 $user, $pass, ROOTDN;
  351.  
  352.         print qq{
  353. <p><b>echo '${user}:$crypt:${maxuid}:${gid}:${first} ${last},joined $date,,,,:/home/$user:/bin/bash' >> /var/nis/passwd</b></p>
  354. <p><b>make -C /var/yp</b><br></p>};
  355.  
  356.         # apache ALL=(ALL) NOPASSWD: /bin/mkdir, /bin/chmod, /bin/chown
  357.         system('sudo', '/bin/mkdir', '-p', $home) and die $?;
  358.         system('sudo', '/bin/chmod', '2700', $home) and die $?;
  359.         system('sudo', '/bin/chown', "${maxuid}:$gid", $home) and die $?;
  360.  
  361.         system('sudo', '/bin/mkdir', '-p', $pst) and die $?;
  362.         system('sudo', '/bin/chmod', '2700', $pst) and die $?;
  363.         system('sudo', '/bin/chown', "${maxuid}:$gid", $pst) and die $?;
  364.  
  365.         printf qq{<hr><p><a href="%s">Add another user</a></p>}, $query->url(-absolute => 1);
  366. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement