syncing examples
[sfrench/samba-autobuild/.git] / examples / LDAP / smbldap-tools / smbldap-useradd.pl
1 #!/usr/bin/perl 
2
3 #  This code was developped by IDEALX (http://IDEALX.org/) and
4 #  contributors (their names can be found in the CONTRIBUTORS file).
5 #
6 #                 Copyright (C) 2002 IDEALX
7 #
8 #  This program is free software; you can redistribute it and/or
9 #  modify it under the terms of the GNU General Public License
10 #  as published by the Free Software Foundation; either version 2
11 #  of the License, or (at your option) any later version.
12 #
13 #  This program is distributed in the hope that it will be useful,
14 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #  GNU General Public License for more details.
17 #
18 #  You should have received a copy of the GNU General Public License
19 #  along with this program; if not, write to the Free Software
20 #  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 #  USA.
22
23 # Purpose of smbldap-useradd : user (posix,shadow,samba) add
24
25 use strict;
26 use smbldap_tools;
27 use smbldap_conf;
28
29 #####################
30
31 use Getopt::Std;
32 my %Options;
33
34 my $ok = getopts('axnmwPG:u:g:d:s:c:k:A:B:C:D:E:F:H:?', \%Options);
35
36 if ( (!$ok) || (@ARGV < 1) || ($Options{'?'}) ) {
37         print "Usage: $0 [-awmugdsckGPABCDEFH?] username\n";
38         print "  -a     is a Windows User (otherwise, Posix stuff only)\n";
39         print "  -w     is a Windows Workstation (otherwise, Posix stuff only)\n";
40         print "  -x     creates rid and primaryGroupID in hex instead of decimal\n";
41         print "  -u     uid\n";
42         print "  -g     gid\n";
43         print "  -G     supplementary comma-separated groups\n";
44         print "  -n     do not create a group\n";
45         print "  -d     home\n";
46         print "  -s     shell\n";
47         print "  -c     gecos\n";
48         print "  -m     creates home directory and copies /etc/skel\n";
49         print "  -k     skeleton dir (with -m)\n";
50         print "  -P     ends by invoking smbldap-passwd.pl\n";
51         print "  -A     can change password ? 0 if no, 1 if yes\n";
52         print "  -B     must change password ? 0 if no, 1 if yes\n";
53         print "  -C     sambaHomePath (SMB home share, like '\\\\PDC-SRV\\homes')\n";
54         print "  -D     sambaHomeDrive (letter associated with home share, like 'H:')\n";
55         print "  -E     sambaLogonScript (DOS script to execute on login)\n";
56         print "  -F     sambaProfilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo')\n";
57         print "  -H     sambaAcctFlags (samba account control bits like '[NDHTUMWSLKI]')\n";
58         print "  -?     show this help message\n";
59         exit (1);
60 }
61
62 # cause problems when dealing with getpwuid because of the
63 # negative ttl and ldap modification
64 my $nscd_status = system "/etc/init.d/nscd status >/dev/null 2>&1";
65
66 if ($nscd_status == 0) {
67    system "/etc/init.d/nscd stop > /dev/null 2>&1";
68 }
69
70 # Read options
71 my $userUidNumber = $Options{'u'};
72 if (!defined($userUidNumber)) { 
73         # find first unused uid starting from $UID_START
74         while (defined(getpwuid($UID_START))) {
75                 $UID_START++;
76         }
77         $userUidNumber = $UID_START;
78 } elsif (getpwuid($userUidNumber)) { die "Uid already exists.\n"; }
79
80 if ($nscd_status == 0) {
81    system "/etc/init.d/nscd start > /dev/null 2>&1";
82 }
83
84
85 # as rid we use 2 * uid + 1000
86 my $userRid = 2 * $userUidNumber + 1000;
87 if (defined($Options{'x'})) {
88     $userRid= sprint("%x", $userRid);
89 }
90
91 my $createGroup = 0;
92 my $userGidNumber = $Options{'g'};
93 # gid not specified ? 
94 if (!defined($userGidNumber)) {
95     # windows machine => $_defaultComputerGid
96     if (defined($Options{'w'})) {
97         $userGidNumber = $_defaultComputerGid;
98 #    } elsif (!defined($Options{'n'})) {
99         # create new group (redhat style)
100         # find first unused gid starting from $GID_START
101 #       while (defined(getgrgid($GID_START))) {
102 #               $GID_START++;
103 #       }
104 #       $userGidNumber = $GID_START;
105
106 #       $createGroup = 1;
107
108     } else {
109         # user will have gid = $_defaultUserGid
110         $userGidNumber = $_defaultUserGid;
111     }
112 } else {
113     my $gid;
114     if (($gid = parse_group($userGidNumber)) < 0) {
115         print "$0: unknown group $userGidNumber\n";
116         exit (6);
117     }
118     $userGidNumber = $gid;
119 }
120
121 # as grouprid we use 2 * gid + 1001
122 my $userGroupRid = 2 * $userGidNumber + 1001;
123 if (defined($Options{'x'})) {
124     $userGroupRid = sprint("%x", $userGroupRid);
125 }
126 # Read only first @ARGV
127 my $userName = $ARGV[0];
128
129 # user must not exist in LDAP (should it be nss-wide ?)
130 my ($rc, $dn) = get_user_dn2($userName);
131 if ($rc and defined($dn)) {
132     print "$0: user $userName exists\n";
133     exit (9);
134 } elsif (!$rc) {
135     print "$0: error in get_user_dn2\n";
136     exit(10);
137 }
138
139 my $userHomeDirectory;
140 my $tmp;
141 if (!defined($userHomeDirectory = $Options{'d'}))
142 {
143     $userHomeDirectory = $_userHomePrefix."/".$userName;
144 }
145 $_userLoginShell = $tmp if (defined($tmp = $Options{'s'}));
146 $_userGecos = $tmp if (defined($tmp = $Options{'c'}));
147 $_skeletonDir = $tmp if (defined($tmp = $Options{'k'}));
148
149 ########################
150
151 # MACHINE ACCOUNT
152 if (defined($tmp = $Options{'w'})) {
153    
154     # add a trailing dollar if missing
155     if ($userName =~ /[^\$]$/s) {
156         $userName .= "\$";
157     }
158
159     #print "About to create machine $userName:\n";
160
161     if (!add_posix_machine ($userName, $userUidNumber, $userGidNumber)) {
162         die "$0: error while adding posix account\n";
163     }
164
165     if (!$with_smbpasswd) {
166         if (!add_samba_machine_mkntpwd($userName, $userUidNumber)) {
167             die "$0: error while adding samba account\n";
168         }
169     } else {
170         if (!add_samba_machine($userName)) {
171             die "$0: error while adding samba account\n";
172         }
173
174         my $tmpldif =
175 "dn: uid=$userName,$computersdn
176 changetype: modify
177 sambaAcctFlags: [W          ]
178
179 ";
180         die "$0: error while modifying accountflags of $userName\n"
181             unless (do_ldapmodify($tmpldif) == 0);
182         undef $tmpldif;
183     }
184
185     exit 0;
186 }
187
188 #######################
189
190 # USER ACCOUNT
191
192 # add posix account first
193
194 my $tmpldif =
195 "dn: uid=$userName,$usersdn
196 objectclass: inetOrgPerson
197 objectclass: posixAccount
198 cn: $userName
199 sn: $userName
200 uid: $userName
201 uidNumber: $userUidNumber
202 gidNumber: $userGidNumber
203 homeDirectory: $userHomeDirectory
204 loginShell: $_userLoginShell
205 gecos: $_userGecos
206 description: $_userGecos
207 userPassword: {crypt}x
208
209 ";
210
211 die "$0: error while adding posix user $userName\n"
212     unless (do_ldapadd($tmpldif) == 0);
213
214 undef $tmpldif;
215
216 #if ($createGroup) {
217 #    group_add($userName, $userGidNumber);
218 #}
219
220 group_add_user($userGidNumber, $userName);
221
222 my $grouplist;
223 # adds to supplementary groups
224 if (defined($grouplist = $Options{'G'})) {
225     add_grouplist_user($grouplist, $userName);
226 }
227
228 # If user was created successfully then we should create his/her home dir
229 if (defined($tmp = $Options{'m'})) {
230    unless ( $userName =~ /\$$/ ) {
231     if ( !(-e $userHomeDirectory) ) {
232         system "mkdir $userHomeDirectory 2>/dev/null";
233         system "cp -a $_skeletonDir/.[a-z,A-Z]* $_skeletonDir/* $userHomeDirectory 2>/dev/null";
234         system "chown -R $userUidNumber:$userGidNumber $userHomeDirectory 2>/dev/null";
235         system "chmod 700 $userHomeDirectory 2>/dev/null"; 
236     }
237    }
238 }
239
240
241 # Add Samba user infos
242 if (defined($Options{'a'})) {
243     if (!$with_smbpasswd) {
244
245         my $winmagic = 2147483647;
246         my $valpwdcanchange = 0;
247         my $valpwdmustchange = $winmagic;
248         my $valacctflags = "[UX]";
249
250         if (defined($tmp = $Options{'A'})) {
251             if ($tmp != 0) {
252                 $valpwdcanchange = "0";
253             } else {
254                 $valpwdcanchange = "$winmagic";
255             }
256         }
257
258         if (defined($tmp = $Options{'B'})) {
259             if ($tmp != 0) {
260                 $valpwdmustchange = "0";
261             } else {
262                 $valpwdmustchange = "$winmagic";
263             }
264         }
265
266         if (defined($tmp = $Options{'H'})) {
267             $valacctflags = "$tmp";
268         }
269
270         my $tmpldif =
271 "dn: uid=$userName,$usersdn
272 changetype: modify
273 objectClass: inetOrgPerson
274 objectclass: posixAccount
275 objectClass: sambaSAMAccount
276 sambaPwdLastSet: 0
277 sambaLogonTime: 0
278 sambaLogoffTime: 2147483647
279 sambaKickoffTime: 2147483647
280 sambaPwdCanChange: $valpwdcanchange
281 sambaPwdMustChange: $valpwdmustchange
282 displayName: $_userGecos
283 sambaAcctFlags: $valacctflags
284 sambaSID: $smbldap_conf::SID-$userRid
285
286 ";
287         
288         die "$0: error while adding samba account to posix user $userName\n"
289             unless (do_ldapmodify($tmpldif) == 0);
290
291         undef $tmpldif;
292     } else {
293         my $FILE="|smbpasswd -s -a $userName >/dev/null" ;
294         open (FILE, $FILE) || die "$!\n";
295         print FILE <<EOF;
296 x
297 x
298 EOF
299     ;
300         close FILE;
301         if ($?) {
302             print "$0: error adding samba account\n";
303             exit (10);
304         }
305     } # with_smbpasswd
306
307     my $valscriptpath = "$userName.cmd";
308     my $valprofilepath = "$_userProfile$userName";
309     my $valsmbhome = "$_userSmbHome";
310     my $valhomedrive = "$_userHomeDrive";
311
312 if (defined($tmp = $Options{'C'})) {
313     $valsmbhome = "$tmp";
314 }
315
316 if (defined($tmp = $Options{'D'})) {
317     $tmp = $tmp.":" unless ($tmp =~ /:/);
318     $valhomedrive = "$tmp";
319 }
320
321 if (defined($tmp = $Options{'E'})) {
322     $valscriptpath = "$tmp";
323 }
324
325 if (defined($tmp = $Options{'F'})) {
326     $valprofilepath = "$tmp";
327 }
328
329     my $tmpldif =
330 "dn: uid=$userName,$usersdn
331 changetype: modify
332 sambaSID: $smbldap_conf::SID-$userRid
333 sambaPrimaryGroupSID: $smbldap_conf::SID-$userGroupRid
334 sambaHomeDrive: $valhomedrive
335 sambaHomePath: $valsmbhome
336 sambaProfilePath: $valprofilepath
337 sambaLogonScript: $valscriptpath
338 sambaLMPassword: XXX
339 sambaNTPassword: XXX
340
341 ";
342
343     die "$0: error while modifying samba account of user $userName\n"
344             unless (do_ldapmodify($tmpldif) == 0);
345     undef $tmpldif;
346 }
347
348 if (defined($Options{'P'})) {
349     exec "/usr/local/sbin/smbldap-passwd.pl $userName"
350 }
351
352 exit 0;
353
354 ########################################
355
356 =head1 NAME
357
358        smbldap-useradd.pl - Create a new user or update default new 
359                             user information
360
361 =head1 SYNOPSIS
362
363        smbldap-useradd.pl [-c comment] [-d home_dir]
364                [-g initial_group] [-G group[,...]]
365                [-m [-k skeleton_dir]]
366                [-s shell] [-u uid [ -o]] [-P]
367                [-A canchange] [-B mustchange] [-C smbhome]
368                [-D homedrive] [-E scriptpath] [-F profilepath]
369                [-H acctflags] login
370
371 =head1 DESCRIPTION
372
373    Creating New Users
374        The smbldap-useradd.pl command creates a new user account using
375        the values specified on the  command  line  and  the default
376        values from the system.
377        The new user account will be entered into the system
378        files as needed, the home directory  will  be  created, and 
379        initial  files copied, depending on the command line options.
380
381        You have to use smbldap-passwd to set the user password.
382        For Samba users, rid is 2*uidNumber+1000, and primaryGroupID
383        is 2*gidNumber+1001. Thus you may want to use
384        smbldap-useradd.pl -a -g "Domain Admins" -u 500 Administrator
385        to create a sambaDomainName administrator (admin rid is 0x1F4 = 500 and
386        grouprid is 0x200 = 512)
387
388        Without any option, the account created will be an Unix (Posix)
389        account. The following options may be used to add information:
390
391        -a     The user will have a Samba account (and Unix).
392
393        -w     Creates an account for a Samba machine (Workstation), so that 
394               it can join a sambaDomainName.
395
396        -x     Creates rid and primaryGroupID in hex (for Samba 2.2.2 bug). Else
397               decimal (2.2.2 patched from cvs or 2.2.x, x > 2)
398
399        -c comment
400               The new user's comment field (gecos).
401
402        -d home_dir
403               The new user will be created using home_dir as the value for the
404               user's login directory.  The default is to append the login name
405               to default_home and use that as the login directory name.
406
407        -g initial_group
408               The group name or number of the user's initial login group.  The
409               group  name must exist.  A group number must refer to an already
410               existing group.  The default group number is 1.
411
412        -G group,[...]
413               A list of supplementary groups which the user is also  a  member
414               of.   Each  group is separated from the next by a comma, with no
415               intervening whitespace.  The groups  are  subject  to  the  same
416               restrictions as the group given with the -g option.  The default
417               is for the user to belong only to the initial group.
418
419        -m     The user's home directory will be created if it does not  exist.
420               The  files  contained in skeleton_dir will be copied to the home
421               directory if the -k option is used,  otherwise  the  files  conĀ­
422               tained  in /etc/skel will be used instead.  Any directories conĀ­
423               tained in skeleton_dir or  /etc/skel  will  be  created  in  the
424               user's  home  directory as well.  The -k option is only valid in
425               conjunction with the -m option.  The default is  to  not  create
426               the directory and to not copy any files.
427
428        -s shell
429               The name of the user's login shell.  The  default  is  to  leave
430               this  field blank, which causes the system to select the default
431               login shell.
432
433        -u uid The numerical value of  the  user's  ID.   This  value  must  be
434               unique,  unless  the  -o option is used.  The value must be non-
435               negative.  The default is to use the smallest ID  value  greater
436               than 1000 and greater than every other user.
437
438        -P     ends by invoking smbldap-passwd.pl
439
440        -A     can change password ? 0 if no, 1 if yes
441
442        -B     must change password ? 0 if no, 1 if yes
443
444        -C     sambaHomePath (SMB home share, like '\\\\PDC-SRV\\homes')
445
446        -D     sambaHomeDrive (letter associated with home share, like 'H:')
447
448        -E     sambaLogonScript, relative to the [netlogon] share (DOS script to execute on login, like 'foo.bat')
449
450        -F     sambaProfilePath (profile directory, like '\\\\PDC-SRV\\profiles\\foo')
451
452        -H     sambaAcctFlags, spaces and trailing bracket are ignored (samba account control bits like '[NDHTUMWSLKI]')
453
454 =head1 SEE ALSO
455
456        useradd(1)
457
458 =cut
459
460 #'