*BSD News Article 38375


Return to BSD News archive

Xref: sserve comp.unix.bsd:15380 comp.os.386bsd.questions:14694 comp.unix.questions:58168
Newsgroups: comp.unix.bsd,comp.os.386bsd.questions,comp.unix.questions
Path: sserve!newshost.anu.edu.au!harbinger.cc.monash.edu.au!yarrina.connect.com.au!werple.apana.org.au!otis.apana.org.au!serval.net.wsu.edu!netnews.nwnet.net!oracle.pnl.gov!osi-east2.es.net!lll-winken.llnl.gov!uwm.edu!spool.mu.edu!cass.ma02.bull.com!as02.bull.oz.au!melb.bull.oz.au!zen!sjg
From: sjg@zen.void.oz.au (Simon J. Gerraty)
Subject: adduser.sh (Was: How to add user?)
Organization: Zen programming...
Message-ID: <1994Nov21.223523.29821@zen.void.oz.au>
References: <3ak0mr$q2v@crl.crl.com> <1994Nov19.070927.136197@slate.mines.colorado.edu>
Date: Mon, 21 Nov 1994 22:35:23 GMT
Lines: 422

I've cross posted this to the groups where the question comes up most often.

mbarkah@slate.mines.colorado.edu (Ade Barkah) writes:
>Peter Lam (petelam@crl.com) wrote:
>: Does anyone know how to add user in FreeBSD?  I tried adduser, but it 
>: can't find the file. Where is the procedure adduser(8)? How do I use it?

>Good question. I don't have it either (FreeBSD 2.0-a). Maybe
>it's in a package I haven't installed. Anyhow, to add users
>without adduser, you can use vipw and add the home directory
>manually.

and salin2lb@ink.org (JOE MCKENZIE) writes:
>I have found the man page for   adduser  on this FreeBSD 1.0 system, but 
>I cannot find the binary.

I've posted this before, but this version should not need any changes
for FreeBSD and includes the man page (extracted from the script).

I wrote an all singing all dancing add user script years ago for
some novice sysadmins, but this is the one I use myself.  I've used it
happily on NetBSD, SunOS, Solaris and HP-UX.

Enjoy - just don't pretend you wrote it.

#!/bin/sh
# This is a shell archive.
# remove everything above the "#!/bin/sh" line
# and feed to /bin/sh
# Use -c option to overwrite existing files
#
# Contents: 
#	adduser.sh
#	adduser.1
#
# packed by: <sjg@zen.void.oz.au> on Tue Nov 22 09:26:18 EST 1994
#
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f adduser.sh -a x$1 != x-c ; then
  echo shar: Will not over-write existing file \"adduser.sh\"
else
  echo shar: Extracting \"adduser.sh\" \(6866 characters\)
  sed 's/^X//' >adduser.sh << '!EOF'
X:
X#
X# NAME:
X#	adduser.sh - portable add user script
X#
X# SYNOPSIS:
X#	
X#	adduser.sh [-G "Group"] [-H "Homes"] [-S "Shell"] [-u "uid"] \\
X#		[-p "encrypted"] [-P "cleartext"][-l]
X#
X# DESCRIPTION:
X#	Simply adds users and their home directory.  It prompts for a
X#	"username" and "fullname" which become part of the passwd file
X#	entry for the new user.  It adds "username" to "Group"
X#	(creating it if necessary) and uses "uid" or the 'gid' of
X#	"Group" as a starting point for its search for an unused
X#	'uid'.  By default it will prompt for a passwd after adding
X#	each user, but '-p' can be used to set a pre-encrypted password
X#	or '-P' can be used to give a clear text password which the
X#	script will encrypt and then use for each new "username".
X#
X#	Most of the variables used are obvious.  "Homes" is the parent
X#	directory of new users home directories.
X#	
X#	The '-l' option causes the script to show the default values
X#	for the variables that it uses.  Most if not all can be set on
X#	a per machine basis by creating a file '.adduserrc' in the
X#	super users home directory or in the directory where
X#	'adduser.sh' is found.  If "Homes"/.adduserrc exists it will
X#	be processed after any others, so can be used to set defaults
X#	on a per project basis.
X#
X#	If the directory "Homes"/default exists, its contents are
X#	replicated in the new users home directory.
X#	
X# NOTES:
X#	The script handles shadow password files on Solaris 2.3, other
X#	machines may break.  It has been tested on NetBSD, SunOS,
X#	Solaris and HP-UX.
X#	
X# AUTHOR:
X#	Simon J. Gerraty <sjg@zen.void.oz.au>
X#
X
X# RCSid:
X#	$Id: adduser.sh,v 1.4 1994/11/21 22:25:40 sjg Exp $
X#
X#	@(#) Copyright (c) 1993 Simon J. Gerraty
X#
X#	This file is provided in the hope that it will
X#	be of use.  There is absolutely NO WARRANTY.
X#	Permission to copy, redistribute or otherwise
X#	use this file is hereby granted provided that 
X#	the above copyright notice and this notice are
X#	left intact. 
X#      
X#	Please send copies of changes and bug-fixes to:
X#	sjg@zen.void.oz.au
X#
X
XMyname=`basename $0 .sh`
XMydir=`dirname $0`
Xcase $Mydir in
X.)	Mydir=`pwd`;;
Xesac
X
XETC=/etc
X# for testing only
X#ETC=/tmp
X#VIPW="ed $ETC/passwd"
X
Xhost=`hostname 2>/dev/null`
Xhost=${host:-`uname -n`}
Xcase "$host" in
X*.*)
X  host=`IFS=.; set -- $host; echo $1`;;
Xesac
X
X# things that the rc file may override.
XHomes=/home/$host
XShell=/bin/csh
X[ -x /bin/ksh ] && Shell=/bin/ksh
XGroup=users
XPasswd='**'
X
X# look for an rc file
Xfor d in $HOME $Mydir 
Xdo
X  [ -s $d/.${Myname}rc ] && { . $d/.${Myname}rc; break; }
Xdone
X
XEXF=/tmp/e$$
XTF=/tmp/u$$
XTF2=/tmp/uu$$
X
Xcase `echo -n .` in
X-n*)	N=;C="\c";;
X*)	N=-n;C=;;
Xesac
X
XOS=`uname -s`
X
Xadd_path () { [ -d $1 ] && eval ${2:-PATH}="\$${2:-PATH}:$1"; }
X
Xget_id()
X{
X  file=$1
X  name=$2
X  min=${3:-1000}
X  max=`expr $min + ${4:-999}`
X  > $EXF
X  
X  id=`grep "^$name:" $file | cut -d: -f3`
X  case "$id" in
X  "")
X    # missing, must add it
X    i=$min
X    while [ $i -lt $max ]
X    do
X      n=`cut -d: -f1,3 $file | grep ":$i\$"`
X      case "$n" in
X      "")
X        # an empty slot - use it
X        id=$i
X        break;;
X      esac
X      i=`expr $i + 1`
X  done
X  ;;
X  *)
X    echo $id > $EXF;;
X  esac
X  echo $id
X}
X
Xmkdirs()
X{
X  case $1 in
X  /*)	pp=/;;
X  *)	pp=;;
X  esac
X  for p in `echo $1 | tr / " "`
X  do
X    case "$pp" in
X    "")	pp=$p;;
X    /)	pp=/$p;;
X    *)	pp=$pp/$p;;
X    esac
X    [ -d $pp ] || mkdir $pp || exit 1
X  done
X}
X
X
Xadd_group()
X{
X  echo "adding $1:*:$2: to $ETC/group"
X  echo "$1:*:$2:" >> $ETC/group
X}
X
Xupd_group()
X{
X  [ "$mygroup" ] || mygroup=`grep "^$1:" /etc/group | cut -d: -f4`
X  case ",$mygroup," in
X  ",,")				# empty
X    add=$2;;
X  *,$2,*)			# already there
X    add=;;
X  *)				# missing
X    add=,$2;;
X  esac
X  [ "$add" ] && sed "/^$1:/s/\$/$add/" $ETC/group > $ETC/group.$$ &&
X  	mv $ETC/group.$$ $ETC/group
X}
X
Xupd_passwd()
X{
X  EDITOR=ed
X  VISUAL=ed
X  export EDITOR VISUAL
X
X  echo "adding $1:$2:$3:$4:$5:$6:$7 to $ETC/passwd"
X  case "$OS" in
X  SunOS)
X    if test -f /etc/shadow; then
X      # we are assuming its Solaris
X      echo "$1:x:$3:$4:$5:$6:$7" > $TF
X      echo "$1:$2:6445::::::" > $TF2
X    fi
X    ;;
X  *BSD)	  # NetBSD at least, have 2 extra fields...
X    echo "$1:$2:$3:$4::0:0:$5:$6:$7" > $TF
X    ;;
X  *)
X    # most OS's just want this.
X    echo "$1:$2:$3:$4:$5:$6:$7" > $TF
X    ;;
X  esac
X
X  line=`grep -n '^+:' $ETC/passwd | cut -d: -f1`
X  ( sleep 1; echo ${line}-1r $TF; echo w; echo q;
X    # Solaris has a stupid shadow passwd implementation...
X    if test -f /etc/shadow && test "$OS" = SunOS
X    then
X      echo "$Myname: updating Solaris shadow passwd file" >&2
X      # this is a crok...
X      sleep 5
X      echo e
X      sleep 5
X      echo '$r' $TF2
X      echo w
X      echo q
X    fi
X  ) | ${VIPW:-vipw} 
X}
X
Xadd_user() 
X{
X  group=$1; shift
X  
X  eval set -- `echo "'$*'" | sed "s/:/' '/g"`
X  
X  gid=`get_id $ETC/group $group $4 256`
X  if [ "$gid" ]; then
X    [ -s $EXF ] || add_group $group $gid 
X    uid=`get_id $ETC/passwd $1 $3 1024`
X    if [ "$uid" ]; then
X      [ -s $EXF ] || upd_passwd "$1" "$2" "$uid" "$gid" "$5" "$6" "$7"; upd_group $group $1
X      [ -d $6 ] || { mkdirs $6 && chown $1 $6 && chgrp $group $6 && chmod 2775 $6; }
X    else
X      echo "$Myname: can't add user $1" >&2; exit 1
X    fi
X  else
X    echo "$Myname: can't add group $group" >&2; exit 1
X  fi
X}
X
Xrm_user()
X{
X  ( echo /^$1:/d; echo w; echo q ) | ${VIPW:-vipw}
X}
X
X# needs perl
Xencrypt() {
X  for d in /usr/libexec /usr/lib
X  do
X    [ -x $d/makekey ] && { makekey=$d/makekey; break; }
X  done
X  perl -e "print pack('a8a2', '$1', '${2:-$$}')" | ${makekey:-makekey}
X}
X
X# ok, time to get to work...
Xset -- `getopt H:S:G:u:p:P:l $*`
X
Xadd_path /sbin
Xadd_path /usr/sbin
Xadd_path /usr/ucb
Xadd_path /usr/etc
X
Xfor i in $*
Xdo
X  case "$i" in
X  --)	shift; break;;
X  -H)	Homes=$2; shift 2;
X	# pick up group defaults...
X	test -s $Homes/.${Myname}rc && . $Homes/.${Myname}rc
X        ;;
X  -S)	Shell=$2; shift 2;;
X  -G)	Group=$2; shift 2;;
X  -u)	uid=$2; shift 2;;
X  -p)	Passwd="$2"; shift 2;;
X  -P)	Passwd=`encrypt $2`; shift 2;;
X  -l)	list=yes;;
X  esac
Xdone
X
Xgid=`get_id $ETC/group $Group 100 1000`
X[ "$uid" ] || uid=$gid
X
Xcase "$Passwd" in
X""|none)	Passwd=;;
Xnologin)	Passwd='*';;
Xesac
X
Xif [ "$list" = yes ]; then
X  echo "Defaults:"
X  for v in Group Homes Shell
X  do
X    eval echo "\	$v=\$$v"
X  done
X  [ "x$Passwd" = "x*" ] && echo "	Passwd=prompt" || echo "	Passwd=$Passwd"
X  [ "$uid" ] && echo "	Initial uid=$uid"
X  echo
Xfi
Xecho Enter username and fullname - spaces in fullname are ok, no quotes needed.
Xecho An empty line terminates input.
Xecho
X
Xecho $N "username fullname: $C"
Xwhile read uname fname
Xdo
X  [ "$uname" ] || exit 0
X  add_user $Group "$uname:$Passwd:$uid:$gid:$fname:$Homes/$uname:$Shell"
X  [ "x$Passwd" = "x**" ] && passwd $uname
X  if [ -d $Homes/default ]; then
X    echo "cd $Homes/default && find . -print | cpio -pdm $Homes/$uname" | su $uname
X  fi
X  echo $N "username fullname: $C"
Xdone
!EOF
  if test 6866 -ne `wc -c < adduser.sh`; then
    echo shar: \"adduser.sh\" unpacked with wrong size!
  fi
  chmod +x adduser.sh
fi
if test -f adduser.1 -a x$1 != x-c ; then
  echo shar: Will not over-write existing file \"adduser.1\"
else
  echo shar: Extracting \"adduser.1\" \(1814 characters\)
  sed 's/^X//' >adduser.1 << '!EOF'
X.\" extracted from adduser.sh 22 November 1994 by cmt2doc.pl
X.TH ADDUSER L "22 November 1994" "FreeWare" "LOCAL COMMANDS"
X.PD .8v
X.SH NAME
X.nf
Xadduser.sh \- portable add user script
X.fi
X
X.SH SYNOPSIS
X.nf
X\fBadduser\fR.sh [\fB\-G\fR \fIGroup\fR] [\fB\-H\fR \fIHomes\fR] [\fB\-S\fR \fIShell\fR] [\fB\-u\fR \fIuid\fR] \\
X	[\fB\-p\fR \fIencrypted\fR] [\fB\-P\fR \fIcleartext\fR][\fB\-l\fR]
X.fi
X
X.SH DESCRIPTION
X
XSimply adds users and their home directory.  It prompts for a
X\fIusername\fR and \fIfullname\fR which become part of the passwd file
Xentry for the new user.  It adds \fIusername\fR to \fIGroup\fR
X(creating it if necessary) and uses \fIuid\fR or the \fBgid\fR of
X\fIGroup\fR as a starting point for its search for an unused
X\fBuid\fR.  By default it will prompt for a passwd after adding
Xeach user, but \fB\-p\fR can be used to set a pre-encrypted password
Xor \fB\-P\fR can be used to give a clear text password which the
Xscript will encrypt and then use for each new \fIusername\fR.
X
XMost of the variables used are obvious.  \fIHomes\fR is the parent
Xdirectory of new users home directories.
X
XThe \fB\-l\fR option causes the script to show the default values
Xfor the variables that it uses.  Most if not all can be set on
Xa per machine basis by creating a file \fB.adduserrc\fR in the
Xsuper users home directory or in the directory where
X\fBadduser.sh\fR is found.  If \fIHomes\fR/.adduserrc exists it will
Xbe processed after any others, so can be used to set defaults
Xon a per project basis.
X
XIf the directory \fIHomes\fR/default exists, its contents are
Xreplicated in the new users home directory.
X
X.SH NOTES
X
XThe script handles shadow password files on Solaris 2.3, other
Xmachines may break.  It has been tested on NetBSD, SunOS,
XSolaris and HP-UX.
X
X.SH AUTHOR
X.nf
XSimon J. Gerraty <sjg@zen.void.oz.au>
!EOF
  if test 1814 -ne `wc -c < adduser.1`; then
    echo shar: \"adduser.1\" unpacked with wrong size!
  fi
  
fi
exit 0
-- 
Simon J. Gerraty        <sjg@zen.void.oz.au>

#include <disclaimer>   /* imagine something _very_ witty here */