prva verzija za lenny
authorIvan Rako <irako@nekkar.carnet.hr>
Wed, 20 May 2009 14:46:56 +0000 (16:46 +0200)
committerValentin Vidic <vvidic@nekkar.carnet.hr>
Wed, 20 May 2009 14:46:56 +0000 (16:46 +0200)
32 files changed:
Makefile [new file with mode: 0644]
README.CARNet [new file with mode: 0644]
changelog.CARNet [new symlink]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/conffiles [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/dirs [new file with mode: 0644]
debian/docs [new file with mode: 0644]
debian/install [new file with mode: 0644]
debian/postinst [new file with mode: 0755]
debian/rules [new file with mode: 0755]
dqblk_rpc.h [new file with mode: 0644]
dqblk_v1.h [new file with mode: 0644]
dqblk_v2.h [new file with mode: 0644]
dqblk_xfs.h [new file with mode: 0644]
manual.txt [new symlink]
mntopt.h [new file with mode: 0644]
quota.h [new file with mode: 0644]
quotaio.h [new file with mode: 0644]
quotaio_generic.h [new file with mode: 0644]
quotaio_v1.h [new file with mode: 0644]
quotaio_v2.h [new file with mode: 0644]
quotaio_xfs.h [new file with mode: 0644]
quotasys.h [new file with mode: 0644]
sysadm.man [new file with mode: 0644]
sysadmin.c [new file with mode: 0644]
sysadmin.h [new file with mode: 0644]
sysadmin.html [new file with mode: 0644]
test.c [new file with mode: 0644]
users [new file with mode: 0644]
version.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..ea48209
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+#
+# Makefile for sysadmin, 12 Mar 1997
+# CARNet System Admin Utility v1.24
+#
+# Written by Zlatko Calusic
+# SRCE, University Computing Centre, Croatia
+#
+
+SHELL  = /bin/sh
+CC     = gcc
+COPTS  = -s -O2 -Wall
+
+all: sysadmin.c sysadmin.h
+       @echo "CARNet System Admin Utility v1.26, 05 Apr 2002"
+       @echo "Written by Zlatko Calusic"
+       @echo "SRCE, University Computing Centre, Croatia"
+       @echo "CARNet, Croatian Academic and Research Network"
+       @echo ""
+       @echo "If you compile on Digital Unix V4.0, add -DDU4 -lsecurity!!!"
+       @echo ""
+       @rm -f sysadmin
+       env PROG_ENV=POSIX $(CC) $(COPTS) sysadmin.c -o sysadmin ### -DDU4 -lsecurity
+
+debug: sysadmin.c sysadmin.h
+       @rm -f sysadmin
+       env PROG_ENV=POSIX $(CC) -g -DDEBUG -Wall -Wno-implicit -Wstrict-prototypes -pedantic sysadmin.c -o sysadmin ### -DDU4 -lsecurity
+
+clean:
+       @rm -f sysadmin
+       rm -f *.o sysadmin core *~
+
+love:
+       @echo "Not war!"
diff --git a/README.CARNet b/README.CARNet
new file mode 100644 (file)
index 0000000..b00abe5
--- /dev/null
@@ -0,0 +1,21 @@
+CARNet sysadmin
+~~~~~~~~~~~~~~~
+
+Ovo je CARNetov paket za pojednostavljeno baratanje osnovnim funkcijama
+OS-a: dodavanje i brisanje korisnika, postavljanje quoti, i restartanje
+sustava.  Preko konfiguracijske datoteke /etc/sysadmin/users moguce je
+razlicitim korisnicima omoguciti pokretanje i tako izbjeci koristenje
+root ljuske za uobicajene zadatke.
+
+Program radi na Linuxu i Solarisu.  U izvornom kodu postoje reference na
+Digital Unix (sada Tru64) i cak Ultrix, ali nije provjereno rade li ti
+dijelovi koda.
+
+Zapise o pokretanjima programa mozete naci u /var/log/sysadmin.log.
+
+Ukoliko zelite izbjeci provjeru ulogiravanja sa konzole, u datoteku
+/etc/sysadmin/config upisite:
+
+no_console_check
+
+Zoran Dzelajlija <jelly+paketi@srce.hr>, Sat,  6 Dec 2003 18:09:53 +0000
diff --git a/changelog.CARNet b/changelog.CARNet
new file mode 120000 (symlink)
index 0000000..6a28af6
--- /dev/null
@@ -0,0 +1 @@
+changelog
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..1051266
--- /dev/null
@@ -0,0 +1,41 @@
+sysadmin-cn (1.26.2) stable; urgency=low
+
+  * Prva verzija za lenny
+  * deb-src package
+
+ -- Ivan Rako <Ivan.Rako@CARNet.hr>  Wed, 20 May 2009 13:38:25 +0200
+
+sysadmin (1.26-1) testing unstable; urgency=low
+
+  * Dignuta Debian revizija da bi radio upgrade sa woodyja.
+
+ -- Zoran Dzelajlija <jelly+paketi@srce.hr>  Sat, 21 Feb 2004 00:55:47 +0100
+
+sysadmin (1.26) unstable; urgency=low
+
+  * Quota na Linuxu:
+    + bez podrske za image mountane sa -o loop, samo pravi device.
+  * Opcija za izbjegavanje provjere konzole.
+
+ -- Zoran Dzelajlija <jelly+paketi@srce.hr>  Sat,  6 Dec 2003 15:18:53 +0100
+
+sysadmin (1.25.1) stable unstable; urgency=low
+
+  * If /etc/default/useradd exists, don't force shell (Linux).
+
+ -- Zoran Dzelajlija <jelly+paketi@srce.hr>  Fri, 30 May 2003 11:36:11 +0200
+
+sysadmin (1.25-1) testing unstable; urgency=low
+
+  * Renamed package to sysadmin-cn.
+
+ -- Zoran Dzelajlija <jelly+paketi@srce.hr>  Mon, 29 Apr 2002 16:10:12 +0200
+
+sysadmin (1.25) testing unstable; urgency=low
+
+  * First linux release.
+  * Linux port has no quota support.
+  * Maybe fixed race condition with useradd and passwd on Linux?
+
+ -- Zoran Dzelajlija <jelly+paketi@srce.hr>  Sun, 28 Apr 2002 21:27:28 +0200
+
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..b8626c4
--- /dev/null
@@ -0,0 +1 @@
+4
diff --git a/debian/conffiles b/debian/conffiles
new file mode 100644 (file)
index 0000000..bdb6438
--- /dev/null
@@ -0,0 +1 @@
+etc/sysadmin/users
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..a9972ef
--- /dev/null
@@ -0,0 +1,16 @@
+Source: sysadmin-cn
+Section: admin
+Priority: optional
+Maintainer: Ivan Rako <Ivan.Rako@CARNet.hr>
+Build-Depends: debhelper (>= 4)
+Standards-Version: 3.6.1.0
+
+Package: sysadmin-cn
+Replaces: sysadmin
+Conflicts: sysadmin
+Provides: sysadmin
+Depends: libc6, quota (>= 3.09)
+Architecture: any
+Description: tty-based system administration tool.
+ sysadmin is a simple menu driven tool for usual system administration
+ tasks, including user and group management and system shutdown.
diff --git a/debian/dirs b/debian/dirs
new file mode 100644 (file)
index 0000000..e1c0b76
--- /dev/null
@@ -0,0 +1,4 @@
+etc/sysadmin
+usr/bin
+usr/share/sysadmin
+var/log
diff --git a/debian/docs b/debian/docs
new file mode 100644 (file)
index 0000000..aa4064e
--- /dev/null
@@ -0,0 +1,3 @@
+README.CARNet
+changelog.CARNet
+manual.txt
diff --git a/debian/install b/debian/install
new file mode 100644 (file)
index 0000000..0db8436
--- /dev/null
@@ -0,0 +1,3 @@
+users etc/sysadmin
+sysadm.man usr/share/sysadmin
+sysadmin usr/bin
diff --git a/debian/postinst b/debian/postinst
new file mode 100755 (executable)
index 0000000..c43bc52
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh -e
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+CONFIG=/etc/sysadmin/users
+OLDCONFIG=/etc/adminusers
+LOG=/var/log/sysadmin.log
+OLDLOG=/var/adm/adminlog
+
+if [ "$1" == "configure" ]; then
+
+       if [ "$2" ] && dpkg --compare-versions "$2" le "1.24" ; then
+       echo ""
+       echo "CN: Warning: configuration files have moved since 1.24!"
+       echo "CN: DO read /usr/share/doc/sysadmin-cn/README.CARNet for details."
+       fi
+
+       # Move files to right places.
+       if [ -f $OLDCONFIG ]; then
+               mv $OLDCONFIG $CONFIG
+               echo "CN: Moved $OLDCONFIG to $CONFIG."
+       fi
+       if [ -f $OLDLOG ]; then
+               mv $OLDLOG $LOG
+               echo "CN: moved $OLDLOG to $LOG."
+       fi
+
+       # Create users file if none exists.
+       if [ ! -e $CONFIG ]; then
+               touch $CONFIG
+               chmod 600 $CONFIG
+       fi
+
+fi
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..7e32f42
--- /dev/null
@@ -0,0 +1,86 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+# Sample debian/rules that uses debhelper.
+# This file was originally written by Joey Hess and Craig Small.
+# As a special exception, when this file is copied by dh-make into a
+# dh-make output file, you may use that output file without restriction.
+# This special exception was added by Craig Small in version 0.37 of dh-make.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+configure: configure-stamp
+configure-stamp:
+       dh_testdir
+       # Add here commands to configure the package.
+
+       touch configure-stamp
+
+
+build: build-stamp
+
+build-stamp: configure-stamp 
+       dh_testdir
+
+       # Add here commands to compile the package.
+       $(MAKE)
+
+       touch build-stamp
+
+clean:
+       dh_testdir
+       dh_testroot
+       rm -f build-stamp configure-stamp
+
+       # Add here commands to clean up after the build process.
+       -$(MAKE) clean
+
+       dh_clean 
+
+install: build
+       dh_testdir
+       dh_testroot
+       dh_clean -k 
+       dh_installdirs
+
+       # Add here commands to install the package into debian/openssh-cn.
+       # $(MAKE) install DESTDIR=$(CURDIR)/debian/openssh-cn
+
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+       dh_testdir
+       dh_testroot
+       dh_installchangelogs -k
+       dh_installdocs
+#      dh_installexamples
+       dh_install
+#      dh_installmenu
+#      dh_installdebconf       
+#      dh_installlogrotate
+#      dh_installemacsen
+#      dh_installpam
+#      dh_installmime
+#      dh_installinit
+#      dh_installcron
+#      dh_installinfo
+       dh_installman
+#      dh_link
+       dh_strip
+#      dh_compress
+       dh_fixperms
+#      dh_perl
+#      dh_python
+       dh_shlibdeps
+       dh_gencontrol
+       dh_makeshlibs
+       dh_installdeb
+       dh_md5sums
+       dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install configure
diff --git a/dqblk_rpc.h b/dqblk_rpc.h
new file mode 100644 (file)
index 0000000..f5a666a
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ *     Headerfile for rpc quotafile format
+ */
+
+#ifndef _DQBLK_RPC_H
+#define _DQBLK_RPC_H
+
+/* Values used for communication through network */
+#define Q_RPC_GETQUOTA 0x0300  /* get limits and usage */
+#define Q_RPC_SETQUOTA 0x0400  /* set limits and usage */
+#define Q_RPC_SETUSE   0x0500  /* set usage */
+#define Q_RPC_SETQLIM  0x0700  /* set limits */
+
+#define RPC_DQBLK_SIZE_BITS 10
+#define RPC_DQBLK_SIZE (1 << RPC_DQBLK_SIZE_BITS)
+
+/* Operations above this format */
+extern struct quotafile_ops quotafile_ops_rpc;
+
+#endif
diff --git a/dqblk_v1.h b/dqblk_v1.h
new file mode 100644 (file)
index 0000000..fe3d683
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ *     Headerfile for old quotafile format
+ */
+
+#ifndef _DQBLK_V1_H
+#define _DQBLK_V1_H
+
+/* Values of quota calls */
+#define Q_V1_RSQUASH   0x1000
+#define Q_V1_GETQUOTA  0x300
+#define Q_V1_SETQUOTA  0x400
+#define Q_V1_SETUSE    0x500
+#define Q_V1_SETQLIM   0x700
+#define Q_V1_GETSTATS  0x800
+
+struct quotafile_ops;          /* Will be defined later in quotaio.h */
+
+/* Operations above this format */
+extern struct quotafile_ops quotafile_ops_1;
+
+#endif
diff --git a/dqblk_v2.h b/dqblk_v2.h
new file mode 100644 (file)
index 0000000..c5932b3
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *
+ *     Header file for disk format of new quotafile format
+ *
+ */
+
+#ifndef _DQBLK_V2_H
+#define _DQBLK_V2_H
+
+#include <sys/types.h>
+
+#define Q_V2_GETQUOTA  0x0D00  /* Get limits and usage */
+#define Q_V2_SETQUOTA  0x0E00  /* Set limits and usage */
+#define Q_V2_SETUSE    0x0F00  /* Set only usage */
+#define Q_V2_SETQLIM   0x0700  /* Set only limits */
+#define Q_V2_GETINFO   0x0900  /* Get information about quota */
+#define Q_V2_SETINFO   0x0A00  /* Set information about quota */
+#define Q_V2_SETGRACE  0x0B00  /* Set just grace times in quotafile information */
+#define Q_V2_SETFLAGS  0x0C00  /* Set just flags in quotafile information */
+#define Q_V2_GETSTATS  0x1100  /* get collected stats (before proc was used) */
+
+/* Structure for format specific information */
+struct v2_mem_dqinfo {
+       uint dqi_flags;         /* Flags set in quotafile */
+       uint dqi_blocks;        /* Number of blocks in file */
+       uint dqi_free_blk;      /* Number of first free block in the list */
+       uint dqi_free_entry;    /* Number of first block with free entry in the list */
+       uint dqi_used_entries;  /* Number of entries in file - updated by scan_dquots */
+       uint dqi_data_blocks;   /* Number of data blocks in file - updated by scan_dquots */
+};
+
+struct v2_mem_dqblk {
+       loff_t dqb_off;         /* Offset of dquot in file */
+};
+
+struct quotafile_ops;          /* Will be defined later in quotaio.h */
+
+/* Operations above this format */
+extern struct quotafile_ops quotafile_ops_2;
+
+#endif
diff --git a/dqblk_xfs.h b/dqblk_xfs.h
new file mode 100644 (file)
index 0000000..8b03d98
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *     Headerfile for XFS quota format
+ */
+
+#ifndef _DQBLK_XFS_H
+#define _DQBLK_XFS_H
+
+#include "quotaio_xfs.h"
+
+#define Q_XFS_QUOTAON  Q_XQUOTAON
+#define Q_XFS_QUOTAOFF Q_XQUOTAOFF
+#define Q_XFS_GETQUOTA Q_XGETQUOTA
+#define Q_XFS_SETQLIM  Q_XSETQLIM
+#define Q_XFS_GETQSTAT Q_XGETQSTAT
+#define Q_XFS_QUOTARM  Q_XQUOTARM
+
+#define xfs_mem_dqinfo fs_quota_stat
+#define xfs_kern_dqblk fs_disk_quota
+
+struct quotafile_ops;          /* Will be defined later in quotaio.h */
+
+/* Operations above this format */
+extern struct quotafile_ops quotafile_ops_xfs;
+
+#endif
diff --git a/manual.txt b/manual.txt
new file mode 120000 (symlink)
index 0000000..64ca5ac
--- /dev/null
@@ -0,0 +1 @@
+../../sysadmin/sysadm.man
\ No newline at end of file
diff --git a/mntopt.h b/mntopt.h
new file mode 100644 (file)
index 0000000..81f023c
--- /dev/null
+++ b/mntopt.h
@@ -0,0 +1,25 @@
+#ifndef _MNTOPT_H
+#define _MNTOPT_H
+
+#include <mntent.h>
+
+/* filesystem type */
+#define MNTTYPE_EXT2           "ext2"  /* 2nd Extended file system */
+#define MNTTYPE_EXT3           "ext3"  /* ext2 + journaling */
+#define MNTTYPE_MINIX          "minix" /* MINIX file system */
+#define MNTTYPE_UFS            "ufs"   /* UNIX file system */
+#define MNTTYPE_UDF            "udf"   /* OSTA UDF file system */
+#define MNTTYPE_REISER         "reiserfs"      /* Reiser file system */
+#define MNTTYPE_XFS            "xfs"   /* SGI XFS file system */
+#define MNTTYPE_AUTOFS         "autofs"        /* Automount mountpoint */
+
+/* mount options */
+#define MNTOPT_NOQUOTA         "noquota"       /* don't enforce quota */
+#define MNTOPT_QUOTA           "quota" /* enforce user quota */
+#define MNTOPT_USRQUOTA                "usrquota"      /* enforce user quota */
+#define MNTOPT_GRPQUOTA                "grpquota"      /* enforce group quota */
+#define MNTOPT_RSQUASH         "rsquash"       /* root as ordinary user */
+#define MNTOPT_BIND            "bind"          /* binded mount */
+#define MNTOPT_LOOP            "loop"          /* loopback mount */
+
+#endif
diff --git a/quota.h b/quota.h
new file mode 100644 (file)
index 0000000..a39a9ae
--- /dev/null
+++ b/quota.h
@@ -0,0 +1,128 @@
+#ifndef _QUOTA_H
+#define _QUOTA_H
+
+#include <sys/types.h>
+
+typedef u_int32_t qid_t;       /* Type in which we store ids in memory */
+typedef u_int64_t qsize_t;     /* Type in which we store size limitations */
+
+#define MAXQUOTAS 2
+#define USRQUOTA  0            /* element used for user quotas */
+#define GRPQUOTA  1            /* element used for group quotas */
+
+/*
+ * Definitions for the default names of the quotas files.
+ */
+#define INITQFNAMES { \
+       "user",    /* USRQUOTA */ \
+       "group",   /* GRPQUOTA */ \
+       "undefined", \
+}
+
+/*
+ * Definitions of magics and versions of current quota files
+ */
+#define INITQMAGICS {\
+       0xd9c01f11,     /* USRQUOTA */\
+       0xd9c01927      /* GRPQUOTA */\
+}
+
+/* Size of blocks in which are counted size limits in generic utility parts */
+#define QUOTABLOCK_BITS 10
+#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
+
+/* Conversion routines from and to quota blocks */
+#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10))
+#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10))
+#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
+
+/*
+ * Command definitions for the 'quotactl' system call.
+ * The commands are broken into a main command defined below
+ * and a subcommand that is used to convey the type of
+ * quota that is being manipulated (see above).
+ */
+#define SUBCMDMASK  0x00ff
+#define SUBCMDSHIFT 8
+#define QCMD(cmd, type)  (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
+
+#define Q_6_5_QUOTAON  0x0100  /* enable quotas */
+#define Q_6_5_QUOTAOFF 0x0200  /* disable quotas */
+#define Q_6_5_SYNC     0x0600  /* sync disk copy of a filesystems quotas */
+
+#define Q_SYNC     0x800001    /* sync disk copy of a filesystems quotas */
+#define Q_QUOTAON  0x800002    /* turn quotas on */
+#define Q_QUOTAOFF 0x800003    /* turn quotas off */
+#define Q_GETFMT   0x800004    /* get quota format used on given filesystem */
+#define Q_GETINFO  0x800005    /* get information about quota files */
+#define Q_SETINFO  0x800006    /* set information about quota files */
+#define Q_GETQUOTA 0x800007    /* get user quota structure */
+#define Q_SETQUOTA 0x800008    /* set user quota structure */
+
+/*
+ * Quota structure used for communication with userspace via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define QIF_BLIMITS    1
+#define QIF_SPACE      2
+#define QIF_ILIMITS    4
+#define QIF_INODES     8
+#define QIF_BTIME      16
+#define QIF_ITIME      32
+#define QIF_LIMITS     (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE      (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES      (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL                (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct if_dqblk {
+       u_int64_t dqb_bhardlimit;
+       u_int64_t dqb_bsoftlimit;
+       u_int64_t dqb_curspace;
+       u_int64_t dqb_ihardlimit;
+       u_int64_t dqb_isoftlimit;
+       u_int64_t dqb_curinodes;
+       u_int64_t dqb_btime;
+       u_int64_t dqb_itime;
+       u_int32_t dqb_valid;
+};
+
+/*
+ * Structure used for setting quota information about file via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define IIF_BGRACE     1
+#define IIF_IGRACE     2
+#define IIF_FLAGS      4
+#define IIF_ALL                (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct if_dqinfo {
+       u_int64_t dqi_bgrace;
+       u_int64_t dqi_igrace;
+       u_int32_t dqi_flags;
+       u_int32_t dqi_valid;
+};
+
+/* Quota format identifiers */
+#define QFMT_VFS_OLD 1
+#define QFMT_VFS_V0  2
+
+/* Flags supported by kernel */
+#define V1_DQF_RSQUASH 1
+
+/* Ioctl for getting quota size */
+#include <sys/ioctl.h>
+#ifndef FIOQSIZE
+       #if defined(__alpha__) || defined(__powerpc__) || defined(__sh__) || defined(__sparc__) || defined(__sparc64__)
+               #define FIOQSIZE _IOR('f', 128, loff_t)
+       #elif defined(__arm__) || defined(__mc68000__) || defined(__s390__)
+               #define FIOQSIZE 0x545E
+        #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__ia64__) || defined(__parisc__) || defined(__cris__) || defined(__hppa__)
+               #define FIOQSIZE 0x5460
+       #elif defined(__mips__) || defined(__mips64__)
+               #define FIOQSIZE 0x6667
+       #endif
+#endif
+
+long quotactl __P((int, const char *, qid_t, caddr_t));
+
+#endif /* _QUOTA_ */
diff --git a/quotaio.h b/quotaio.h
new file mode 100644 (file)
index 0000000..7216156
--- /dev/null
+++ b/quotaio.h
@@ -0,0 +1,59 @@
+/*
+ *
+ *     Header of IO operations for quota utilities
+ *
+ */
+
+#ifndef _QUOTAIO_H
+#define _QUOTAIO_H
+
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "quota.h"
+
+/* Latest known versions */
+#define INITKNOWNVERSIONS {\
+       0,\
+       0\
+}
+
+#define QUOTAFORMATS 4
+
+#define INITQFBASENAMES {\
+       "quota",\
+       "aquota",\
+       "",\
+       ""\
+}
+
+#define INITQFMTNAMES {\
+       "vfsold",\
+       "vfsv0",\
+       "rpc",\
+       "xfs"\
+}
+
+/* Values for format handling */
+#define QF_UNKNOWN -3          /* Format cannot be detected from filename */
+#define QF_TOONEW -2           /* Quota format is too new to handle */
+#define QF_ERROR -1            /* There was error while detecting format (maybe unknown format...) */
+#define QF_VFSOLD 0            /* Old quota format */
+#define QF_VFSV0 1             /* New quota format - version 0 */
+#define QF_RPC 2               /* RPC should be used on given filesystem */
+#define QF_XFS 3               /* XFS quota format */
+
+/*
+ * Definitions for disk quotas imposed on the average user
+ * (big brother finally hits Linux).
+ *
+ * The following constants define the default amount of time given a user
+ * before the soft limits are treated as hard limits (usually resulting
+ * in an allocation failure). The timer is started when the user crosses
+ * their soft limit, it is reset when they go below their soft limit.
+ */
+#define MAX_IQ_TIME  604800    /* (7*24*60*60) 1 week */
+#define MAX_DQ_TIME  604800    /* (7*24*60*60) 1 week */
+
+#endif /* _QUOTAIO_H */
diff --git a/quotaio_generic.h b/quotaio_generic.h
new file mode 100644 (file)
index 0000000..47d36a8
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ *     Header file for communication with kernel generic interface
+ *
+ */
+
+#ifndef _QUOTAIO_GENERIC_H
+#define _QUOTAIO_GENERIC_H
+
+#include "quotaio.h"
+
+/* Get info from kernel to handle */
+int vfs_get_info(struct quota_handle *h);
+
+/* Set info in kernel from handle */
+int vfs_set_info(struct quota_handle *h, int flags);
+
+/* Get dquot from kernel */
+int vfs_get_dquot(struct dquot *dquot);
+
+/* Set dquot in kernel */
+int vfs_set_dquot(struct dquot *dquot, int flags);
+
+#endif
diff --git a/quotaio_v1.h b/quotaio_v1.h
new file mode 100644 (file)
index 0000000..aa9448e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *     Headerfile for old quotafile format
+ */
+
+#ifndef _QUOTAIO_V1_H
+#define _QUOTAIO_V1_H
+
+#include <sys/types.h>
+
+#define V1_DQBLK_SIZE_BITS 10
+#define V1_DQBLK_SIZE (1 << V1_DQBLK_SIZE_BITS)        /* Size of one quota block in bytes in old format */
+
+#define V1_DQOFF(__id) ((loff_t) ((__id) * sizeof(struct v1_disk_dqblk)))
+
+/* Structure of quota on disk */
+struct v1_disk_dqblk {
+       u_int32_t dqb_bhardlimit;       /* absolute limit on disk blks alloc */
+       u_int32_t dqb_bsoftlimit;       /* preferred limit on disk blks */
+       u_int32_t dqb_curblocks;        /* current block count */
+       u_int32_t dqb_ihardlimit;       /* maximum # allocated inodes */
+       u_int32_t dqb_isoftlimit;       /* preferred limit on inodes */
+       u_int32_t dqb_curinodes;        /* current # allocated inodes */
+       time_t dqb_btime;       /* time limit for excessive disk use */
+       time_t dqb_itime;       /* time limit for excessive files */
+} __attribute__ ((packed));
+
+/* Structure used for communication with kernel */
+struct v1_kern_dqblk {
+       u_int32_t dqb_bhardlimit;       /* absolute limit on disk blks alloc */
+       u_int32_t dqb_bsoftlimit;       /* preferred limit on disk blks */
+       u_int32_t dqb_curblocks;        /* current block count */
+       u_int32_t dqb_ihardlimit;       /* maximum # allocated inodes */
+       u_int32_t dqb_isoftlimit;       /* preferred inode limit */
+       u_int32_t dqb_curinodes;        /* current # allocated inodes */
+       time_t dqb_btime;       /* time limit for excessive disk use */
+       time_t dqb_itime;       /* time limit for excessive files */
+};
+
+struct v1_dqstats {
+       u_int32_t lookups;
+       u_int32_t drops;
+       u_int32_t reads;
+       u_int32_t writes;
+       u_int32_t cache_hits;
+       u_int32_t allocated_dquots;
+       u_int32_t free_dquots;
+       u_int32_t syncs;
+};                                                                               
+#endif
diff --git a/quotaio_v2.h b/quotaio_v2.h
new file mode 100644 (file)
index 0000000..2482156
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *
+ *     Header file for disk format of new quotafile format
+ *
+ */
+
+#ifndef _QUOTAIO_V2_H
+#define _QUOTAIO_V2_H
+
+#include <sys/types.h>
+#include "quota.h"
+
+#define V2_DQINFOOFF   sizeof(struct v2_disk_dqheader) /* Offset of info header in file */
+#define V2_DQBLKSIZE_BITS      10
+#define V2_DQBLKSIZE   (1 << V2_DQBLKSIZE_BITS)        /* Size of block with quota structures */
+#define V2_DQTREEOFF   1       /* Offset of tree in file in blocks */
+#define V2_DQTREEDEPTH 4       /* Depth of quota tree */
+#define V2_DQSTRINBLK  ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk))     /* Number of entries in one blocks */
+#define V2_GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
+#define V2_GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)(buf)) + sizeof(struct v2_disk_dqdbheader)))
+#define INIT_V2_VERSIONS { 0, 0}
+
+struct v2_disk_dqheader {
+       u_int32_t dqh_magic;    /* Magic number identifying file */
+       u_int32_t dqh_version;  /* File version */
+} __attribute__ ((packed));
+
+/* Flags for version specific files */
+#define V2_DQF_MASK  0x0000    /* Mask for all valid ondisk flags */
+
+/* Header with type and version specific information */
+struct v2_disk_dqinfo {
+       u_int32_t dqi_bgrace;   /* Time before block soft limit becomes hard limit */
+       u_int32_t dqi_igrace;   /* Time before inode soft limit becomes hard limit */
+       u_int32_t dqi_flags;    /* Flags for quotafile (DQF_*) */
+       u_int32_t dqi_blocks;   /* Number of blocks in file */
+       u_int32_t dqi_free_blk; /* Number of first free block in the list */
+       u_int32_t dqi_free_entry;       /* Number of block with at least one free entry */
+} __attribute__ ((packed));
+
+/*
+ *  Structure of header of block with quota structures. It is padded to 16 bytes so
+ *  there will be space for exactly 18 quota-entries in a block
+ */
+struct v2_disk_dqdbheader {
+       u_int32_t dqdh_next_free;       /* Number of next block with free entry */
+       u_int32_t dqdh_prev_free;       /* Number of previous block with free entry */
+       u_int16_t dqdh_entries; /* Number of valid entries in block */
+       u_int16_t dqdh_pad1;
+       u_int32_t dqdh_pad2;
+} __attribute__ ((packed));
+
+/* Structure of quota for one user on disk */
+struct v2_disk_dqblk {
+       u_int32_t dqb_id;       /* id this quota applies to */
+       u_int32_t dqb_ihardlimit;       /* absolute limit on allocated inodes */
+       u_int32_t dqb_isoftlimit;       /* preferred inode limit */
+       u_int32_t dqb_curinodes;        /* current # allocated inodes */
+       u_int32_t dqb_bhardlimit;       /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+       u_int32_t dqb_bsoftlimit;       /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+       u_int64_t dqb_curspace; /* current space occupied (in bytes) */
+       u_int64_t dqb_btime;    /* time limit for excessive disk use */
+       u_int64_t dqb_itime;    /* time limit for excessive inode use */
+} __attribute__ ((packed));
+
+/* Structure of quota for communication with kernel */
+struct v2_kern_dqblk {
+       unsigned int dqb_ihardlimit;
+       unsigned int dqb_isoftlimit;
+       unsigned int dqb_curinodes;
+       unsigned int dqb_bhardlimit;
+       unsigned int dqb_bsoftlimit;
+       qsize_t dqb_curspace;
+       time_t dqb_btime;
+       time_t dqb_itime;
+};
+
+/* Structure of quotafile info for communication with kernel */
+struct v2_kern_dqinfo {
+       unsigned int dqi_bgrace;
+       unsigned int dqi_igrace;
+       unsigned int dqi_flags;
+       unsigned int dqi_blocks;
+       unsigned int dqi_free_blk;
+       unsigned int dqi_free_entry;
+};
+
+/* Structure with gathered statistics from kernel */
+struct v2_dqstats {
+       u_int32_t lookups;
+       u_int32_t drops;
+       u_int32_t reads;
+       u_int32_t writes;
+       u_int32_t cache_hits;
+       u_int32_t allocated_dquots;
+       u_int32_t free_dquots;
+       u_int32_t syncs;
+       u_int32_t version;
+};
+
+#endif
diff --git a/quotaio_xfs.h b/quotaio_xfs.h
new file mode 100644 (file)
index 0000000..e7b7e14
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+#ifndef _QUOTAIO_XFS_H
+#define _QUOTAIO_XFS_H
+
+#include <asm/types.h>
+
+#define XQM_CMD(cmd)   ( ('X'<<8)+(cmd) )
+#define IS_XQM_CMD(cmd)        ( ((int)(cmd)>>8) == 'X' )
+
+/*
+ * Disk quota - quotactl(2) commands for XFS Quota Manager (XQM).
+ */
+#define Q_XQUOTAON   XQM_CMD(0x1)      /* enable quota accounting/enforcement */
+#define Q_XQUOTAOFF  XQM_CMD(0x2)      /* disable quota accounting/enforcement */
+#define Q_XGETQUOTA  XQM_CMD(0x3)      /* get disk limits & usage */
+#define Q_XSETQLIM   XQM_CMD(0x4)      /* set disk limits only */
+#define Q_XGETQSTAT  XQM_CMD(0x5)      /* returns fs_quota_stat_t struct */
+#define Q_XQUOTARM   XQM_CMD(0x6)      /* free quota files' space */
+
+/*
+ * fs_disk_quota structure:
+ *
+ * This contains the current quota information regarding a user/proj/group.
+ * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of
+ * 512 bytes.
+ */
+#define FS_DQUOT_VERSION       1       /* fs_disk_quota.d_version */
+typedef struct fs_disk_quota {
+       __s8 d_version;         /* version of this structure */
+       __s8 d_flags;           /* XFS_{USER,PROJ,GROUP}_QUOTA */
+       __u16 d_fieldmask;      /* field specifier */
+       __u32 d_id;             /* user, project, or group ID */
+       __u64 d_blk_hardlimit;  /* absolute limit on disk blks */
+       __u64 d_blk_softlimit;  /* preferred limit on disk blks */
+       __u64 d_ino_hardlimit;  /* maximum # allocated inodes */
+       __u64 d_ino_softlimit;  /* preferred inode limit */
+       __u64 d_bcount;         /* # disk blocks owned by the user */
+       __u64 d_icount;         /* # inodes owned by the user */
+       __s32 d_itimer;         /* zero if within inode limits */
+       /* if not, we refuse service */
+       __s32 d_btimer;         /* similar to above; for disk blocks */
+       __u16 d_iwarns;         /* # warnings issued wrt num inodes */
+       __u16 d_bwarns;         /* # warnings issued wrt disk blocks */
+       __s32 d_padding2;       /* padding2 - for future use */
+       __u64 d_rtb_hardlimit;  /* absolute limit on realtime blks */
+       __u64 d_rtb_softlimit;  /* preferred limit on RT disk blks */
+       __u64 d_rtbcount;       /* # realtime blocks owned */
+       __s32 d_rtbtimer;       /* similar to above; for RT disk blks */
+       __u16 d_rtbwarns;       /* # warnings issued wrt RT disk blks */
+       __s16 d_padding3;       /* padding3 - for future use */
+       char d_padding4[8];     /* yet more padding */
+} fs_disk_quota_t;
+
+/*
+ * These fields are sent to Q_XSETQLIM to specify fields that need to change.
+ */
+#define FS_DQ_ISOFT    (1<<0)
+#define FS_DQ_IHARD    (1<<1)
+#define FS_DQ_BSOFT    (1<<2)
+#define FS_DQ_BHARD    (1<<3)
+#define FS_DQ_RTBSOFT  (1<<4)
+#define FS_DQ_RTBHARD  (1<<5)
+#define FS_DQ_LIMIT_MASK       (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \
+                                FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD)
+/*
+ * These timers can only be set in super user's dquot. For others, timers are
+ * automatically started and stopped. Superusers timer values set the limits
+ * for the rest.  In case these values are zero, the DQ_{F,B}TIMELIMIT values
+ * defined below are used. 
+ * These values also apply only to the d_fieldmask field for Q_XSETQLIM.
+ */
+#define FS_DQ_BTIMER   (1<<6)
+#define FS_DQ_ITIMER   (1<<7)
+#define FS_DQ_RTBTIMER         (1<<8)
+#define FS_DQ_TIMER_MASK       (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER)
+
+/*
+ * Various flags related to quotactl(2).  Only relevant to XFS filesystems.
+ */
+#define XFS_QUOTA_UDQ_ACCT     (1<<0)  /* user quota accounting */
+#define XFS_QUOTA_UDQ_ENFD     (1<<1)  /* user quota limits enforcement */
+#define XFS_QUOTA_GDQ_ACCT     (1<<2)  /* group quota accounting */
+#define XFS_QUOTA_GDQ_ENFD     (1<<3)  /* group quota limits enforcement */
+
+#define XFS_USER_QUOTA         (1<<0)  /* user quota type */
+#define XFS_PROJ_QUOTA         (1<<1)  /* (IRIX) project quota type */
+#define XFS_GROUP_QUOTA                (1<<2)  /* group quota type */
+
+/*
+ * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
+ * Provides a centralized way to get meta infomation about the quota subsystem.
+ * eg. space taken up for user and group quotas, number of dquots currently
+ * incore.
+ */
+#define FS_QSTAT_VERSION       1       /* fs_quota_stat.qs_version */
+
+/*
+ * Some basic infomation about 'quota files'.
+ */
+typedef struct fs_qfilestat {
+       __u64 qfs_ino;          /* inode number */
+       __u64 qfs_nblks;        /* number of BBs 512-byte-blks */
+       __u32 qfs_nextents;     /* number of extents */
+} fs_qfilestat_t;
+
+typedef struct fs_quota_stat {
+       __s8 qs_version;        /* version number for future changes */
+       __u16 qs_flags;         /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+       __s8 qs_pad;            /* unused */
+       fs_qfilestat_t qs_uquota;       /* user quota storage information */
+       fs_qfilestat_t qs_gquota;       /* group quota storage information */
+       __u32 qs_incoredqs;     /* number of dquots incore */
+       __s32 qs_btimelimit;    /* limit for blks timer */
+       __s32 qs_itimelimit;    /* limit for inodes timer */
+       __s32 qs_rtbtimelimit;  /* limit for rt blks timer */
+       __u16 qs_bwarnlimit;    /* limit for num warnings */
+       __u16 qs_iwarnlimit;    /* limit for num warnings */
+} fs_quota_stat_t;
+
+#endif /* _QUOTAIO_XFS_H */
diff --git a/quotasys.h b/quotasys.h
new file mode 100644 (file)
index 0000000..10d52b9
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *
+ *     Headerfile of quota interactions with system - filenames, fstab...
+ *
+ */
+
+#ifndef _QUOTASYS_H
+#define _QUOTASYS_H
+
+#include <sys/types.h>
+#include <mntopt.h>
+#include "quota.h"
+
+#define MAXNAMELEN 64          /* Maximal length of user/group name */
+#define MAXTIMELEN 40          /* Maximal length of time string */
+#define MAXNUMLEN 32           /* Maximal length of number */
+#define MAXMNTPOINTS 256       /* Maximal number of mountpoints with quota */
+
+/* Flags for formatting time */
+#define TF_ROUND 0x1           /* Should be printed time rounded? */
+
+/* Flags for IO initialization */
+#define IOI_LOCALONLY  0x1     /* Operate only on local quota */
+#define IOI_READONLY   0x2     /* Only readonly access */
+#define IOI_OPENFILE   0x4     /* Open file even if kernel has quotas turned on */
+
+#define KERN_KNOWN_QUOTA_VERSION (6*10000 + 5*100 + 1)
+
+/* Interface versions */
+#define IFACE_VFSOLD 1
+#define IFACE_VFSV0 2
+#define IFACE_GENERIC 3
+
+/* Kernel quota format and supported interface */
+extern int kernel_formats, kernel_iface;
+
+/*
+ *     Exported functions
+ */
+/* Convert quota type to written form */
+char *type2name(int);
+
+/* Convert username to uid */
+uid_t user2uid(char *);
+
+/* Convert groupname to gid */
+gid_t group2gid(char *);
+
+/* Convert user/groupname to id */
+int name2id(char *name, int qtype);
+
+/* Convert uid to username */
+int uid2user(uid_t, char *);
+
+/* Convert gid to groupname */
+int gid2group(gid_t, char *);
+
+/* Convert id to user/group name */
+int id2name(int id, int qtype, char *buf);
+
+/* Possible default passwd handling */
+#define PASSWD_FILES 0
+#define PASSWD_DB 1
+/* Parse /etc/nsswitch.conf and return type of default passwd handling */
+int passwd_handling(void);
+
+/* Convert quota format name to number */
+int name2fmt(char *str);
+
+/* Convert quota format number to name */
+char *fmt2name(int fmt);
+
+/* Convert kernel to utility format numbers */
+int kern2utilfmt(int fmt);
+
+/* Convert utility to kernel format numbers */
+int util2kernfmt(int fmt);
+
+/* Convert time difference between given time and current time to printable form */
+void difftime2str(time_t, char *);
+
+/* Convert time to printable form */
+void time2str(time_t, char *, int);
+
+/* Convert number and units to time in seconds */
+int str2timeunits(time_t, char *, time_t *);
+
+/* Convert number in quota blocks to short printable form */
+void space2str(qsize_t, char *, int);
+
+/* Convert number to short printable form */
+void number2str(unsigned long long, char *, int);
+
+/* Check to see if particular quota is to be enabled */
+int hasquota(struct mntent *mnt, int type);
+
+/* Flags for get_qf_name() */
+#define NF_EXIST  1    /* Check whether file exists */
+#define NF_FORMAT 2    /* Check whether file is in proper format */
+/* Get quotafile name for given entry */
+int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename);
+
+/* Detect newest quota format with existing file */
+int detect_quota_files(struct mntent *mnt, int type, int fmt);
+
+/* Create NULL-terminated list of handles for quotafiles for given mountpoints */
+struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt,
+                                        int ioflags, int mntflags);
+/* Dispose given list of handles */
+int dispose_handle_list(struct quota_handle **hlist);
+
+/* Check whether given device name matches quota handle device */
+int devcmp_handle(const char *dev, struct quota_handle *h);
+
+/* Check whether two quota handles have same device */
+int devcmp_handles(struct quota_handle *a, struct quota_handle *b);
+
+/* Check kernel supported quotafile format */
+void init_kernel_interface(void);
+
+/* Check whether is quota turned on on given device for given type */
+int kern_quota_on(const char *dev, int type, int fmt);
+
+/* Flags for init_mounts_scan() */
+#define MS_NO_MNTPOINT 0x01    /* Specified directory needn't be mountpoint */
+#define MS_NO_AUTOFS 0x02      /* Ignore autofs mountpoints */
+#define MS_QUIET 0x04          /* Be quiet with error reporting */
+/* Initialize mountpoints scan */
+int init_mounts_scan(int dcnt, char **dirs, int flags);
+
+/* Return next mountpoint for scan */
+struct mntent *get_next_mount(void);
+
+/* Free all structures associated with mountpoints scan */
+void end_mounts_scan(void);
+
+#endif /* _QUOTASYS_H */
diff --git a/sysadm.man b/sysadm.man
new file mode 100644 (file)
index 0000000..274b283
--- /dev/null
@@ -0,0 +1,101 @@
+Sveucilisni racunski centar SRCE
+Hrvatska akademska i istrazivacka mreza
+
+
+             Upute za upotrebu CARNet administracijskog programa
+
+Uvod:
+
+CARNet administracijski program omogucuje minimalnu administraciju racunala
+
+ - dodavanje korisnika        - promjenu ogranicenja disk. prostora (quota)
+ - brisanje korisnika         - operacije nad grupama korisnika
+ - promjenu lozinki           - kreiranje direktorija za rad grupa
+ - zaustavljanje stroja
+
+Program se u uobicajenoj konfiguraciji moze koristiti samo sa sistemske
+konzole.  Na vlastiti rizik mozete u datoteku /etc/sysadmin/config
+upisati
+
+no_console_check
+
+i tada program vise nece provjeravati je li administrator ulogiran sa
+konzole.
+
+Postupci:
+
+1. Dodavanje korisnika
+       
+Odabire se opcija 1 -- Dodavanje korisnika
+Nakon toga se upisuje login korisnika koji se dodaje, te njegovo
+ime i prezime. Program se automatski vraca u glavni meni.
+
+Nakon sto je korisnik dodan potrebno mu je postaviti lozinku (password),
+sto se radi naredbom 3 -- Promjena lozinke korisnika
+
+2. Brisanje korisnika
+
+Odabire se opcija 2 -- Brisanje korisnika
+Nakon toga se treba upisati login koji se brise. 
+
+3. Promjena lozinke korisnika
+
+Odabire se opcija 3 -- Promjena lozinke korisnika
+Nakon toga se upisuje login kojem se mijenja password, te novi password
+koji se utipkava naslijepo 2 puta, zbog provjere.
+
+4. Promjena quote korisnika
+
+Odabire se opcija 4 -- Promjena quote korisnika
+Nakon toga se unosi login kojem se mijenja ogranicenje diskovnog prostora.
+Unose se jos dva broja, jedan koji odredjuje mekani (soft) limit i tvrdi
+(hard) limit. Oba broja moraju biti u kilobajtima (KB). Ukoliko se za
+vrijednost soft limita unese nula (0), program smatra da korisniku zelite
+ukinuti ogranicenje.
+
+5. Operacije nad grupama korisnika
+
+Odabire se opcija 5 -- Operacije nad grupama korisnika
+Dobije se novi izbornik s 5 opcija:
+1 -- Kreiranje nove grupe (mora se napraviti prije nego sto dodajemo
+korisnike u grupu).
+2 -- Dodavanje korisnika u grupu
+3 -- Brisanje korisnika iz grupe
+4 -- Brisanje grupe
+5 -- Kreiranje direktorija (u koji grupa moze pisati)
+     Zgodno za timski rad (npr. kreiranje WWW podataka). Direktorij mora biti
+     na korisnickom disku!
+6 -- Brisanje direktorija
+     Da bi se direktorij mogao obrisati, treba biti prazan!
+7 -- Povratak u osnovni izbornik
+
+6. Zaustavljanje i gasenje racunala
+
+Odabire se opcija 6 -- Zaustavljanje i gasenje racunala
+Ovom naredbom se prekida rad racunala i ono se zaustavlja.
+Program pita za poruku koja ce se ispisati korisnicima i
+za vrijeme nakon kojeg ce se racunalo ugasiti ("grace period").
+Vrijeme treba biti izmedju 1 i 60 minuta. Ukoliko ovdje unesemo
+npr. 0 (ili vise od 60), prekinuti cemo sekvencu.
+Nakon sto se racunalo zaustavi, potrebno je ugasiti racunalo
+na glavnom prekidacu. Da se racunalo zaustavilo vidi se po
+ispisu poruka na ekranu. 
+
+7. Pomoc
+
+Odabire se opcija 7 -- Pomoc
+Upravo je citate :)
+
+8. Izlazak iz administracijskog programa
+
+Odabire se opcija 8 -- Izlazak iz administracijskog programa
+
+-------------------------------------------------------------------------------
+Autor programa je Zlatko Calusic
+
+U slucaju nejasnoca ili problema pisite odrzavatelju na
+Zoran Dzelajlija <jelly+paketi@srce.hr>.  Zlatko vec jako
+dugo nema veze sa ovim programom, iako mu je drago da se
+ovaj hack iz 1997. jos uvijek koristi.
+-------------------------------------------------------------------------------
+Zadnja izmjena: Sun Dec  7 20:12:56 CET 2003
diff --git a/sysadmin.c b/sysadmin.c
new file mode 100644 (file)
index 0000000..e700d9f
--- /dev/null
@@ -0,0 +1,1487 @@
+/*
+ *
+ *     CARNet System Admin Utility v1.26, 2003-12-05
+ *
+ *     v1.00, 24 Jun 1996, first release
+ *     v1.10, 17 Oct 1996, directories with ownership of specific group can be created and
+ *                         deleted, accounts 'srce' & 'admin' can be added (only)
+ *     v1.15, 30 Oct 1996, admin program is now setuid!!! it gives off privileges
+ *                         when not needed
+ *     v1.20, 30 Nov 1996, name changed, logging incorporated, access list, tty checking
+ *     v1.21, 17 Dec 1996, shutdown asks for message and grace period, fixed all
+ *                         relative paths (security!), main menu slightly rearranged
+ *     v1.22, 25 Feb 1997, Digital Unix 4.0 only: use user{add,del}(), fix checking for console
+ *     v1.23, 10 Mar 1997, Again problems with OSF/DU and console checking
+ *     v1.24, 12 Mar 1997, Rewritten code for console checking (I *hate* bloody Digital!!!)
+ *     v1.25, 2002-04-28, Initial port to Debian GNU/Linux, limited functionality
+ *      v1.26, 2003-12-05, quota for Linux.  Only new style quotactl() on i386.
+ *
+ *     Written by Zlatko Calusic
+ *     Linux port Zoran Dzelajlija
+ *
+ *     SRCE, University Computing Centre, Croatia
+ *     CARNet, Croatian Academic and Research Network
+ *
+ */
+
+/* prototypes */
+
+#include "sysadmin.h"
+
+/* globals */
+
+char loginname[MAXLOGIN], group[MAXGROUP], username[MAXNAME], string[MAXSTR];
+char directory[MAXDIR], command[MAXCOMMAND], message[MAXMESS];
+int saveduid, grace;
+FILE *logfile;
+int conscheck = 1;
+
+char *authdir, *group_fallback_dir;
+
+
+/* body */
+
+void logger(char *fmt, ...)
+{
+    char *cptr, *whenptr;
+    va_list arg;
+    time_t when;
+
+    time(&when);
+    whenptr = ctime(&when);
+    if ((cptr = strchr(whenptr, '\n')))
+       *cptr = 0;
+    fprintf(logfile, "%s  ", whenptr);
+    va_start(arg, fmt);
+    while (*fmt)
+    {
+       while (*fmt && *fmt != '%')
+           fputc(*fmt++, logfile);
+       fmt++;
+       switch(*fmt++)
+       {
+           case 's':
+               fprintf(logfile, "%s", va_arg(arg, char *));
+               break;
+           case 'd':
+               fprintf(logfile, "%d", va_arg(arg, int));
+               break;
+           default:
+               goto donefmt;
+       }
+    }  
+  donefmt:
+    va_end(arg);
+    fputc('\n', logfile);
+    fflush(logfile);
+    return;
+}
+
+void priv(int pvar)
+{
+    int retval;
+
+    switch (pvar)
+    {
+       case ON:
+           retval = seteuid(0);
+           break;
+       case OFF:
+       default:
+           retval = seteuid(saveduid);
+    }
+    if (retval < 0)
+    {
+       fputs("\nInterna greska, izlazak iz programa!\n", stderr);
+       waitkey();
+       exit(0);
+    }
+    return;
+}
+
+int lockpw(void)
+{
+#if defined(ultrix)
+    if (!system("/bin/sh /etc/lockpw"))
+       return OK;
+    else
+       return ERROR;
+#elif defined(__osf__)
+    if (!mkdir("/etc/ptmp", 0700))
+       return OK;
+    else
+       return ERROR;
+#endif
+    return OK;
+}
+
+void unlockpw(void)
+{
+#if defined(ultrix)
+    system("/bin/sh /etc/unlockpw");
+#elif defined(__osf__)
+    rmdir("/etc/ptmp");
+#endif
+    return;
+}
+
+void consexit(void)
+{
+    fputs("\nProgram se moze pokrenuti samo s konzole.\nIzlazak iz programa!\n", stderr);
+    exit(1);
+}
+
+int getch(void)
+{
+    int ch = getchar();
+
+    if (ch != EOF && ch != '\n')
+       getchar();
+    return ch;
+}
+
+void clear(void)
+{
+#if defined(__SVR4) || defined(__osf__) || defined(__linux__)
+    system("/usr/bin/clear");
+#elif defined(ultrix)
+    system("/usr/ucb/clear");
+#endif
+    return;
+}
+
+void waitkey(void)
+{
+    printf("\nPritisnite <RETURN> za nastavak...");
+    while (getch() != '\n');
+    return;
+}
+
+void enter(char *var, int size)
+{
+    char *ptr;
+
+    fgets(var, size, stdin);
+    if ((ptr = strchr(var, '\n')))
+       *ptr = 0;
+    putchar('\n');
+    return;
+}
+       
+void getuser(char *text)
+{
+    printf("%s\n\nUnesite korisnicko ime (login) > ", text);
+    enter(loginname, MAXLOGIN);
+    return;
+}
+
+void getgroup(char *text)
+{
+    if (*text)
+       printf("%s\n\n", text);
+    printf("Unesite ime grupe > ");
+    enter(group, MAXGROUP);
+    return;
+}
+
+int getname(void)
+{
+    int count = 0;
+
+    printf("Unesite ime i prezime korisnika > ");
+    enter(username, MAXNAME);
+    do
+    {
+       if (!isalnum(username[count]) && username[count] != ' ' && username[count] != '.' && username[count] != '-')
+       {
+           fputs("Unijeli ste nedozvoljene znakove u imenu korisnika!\n", stderr);
+           return ERROR;
+       }
+       count++;
+    } while (username[count]);
+    return OK;
+}
+
+int getdir(void)
+{
+    int len;
+    printf("Unesite puni put do direktorija > ");
+    enter(directory, MAXDIR);
+    if (strchr(directory, '.') || strstr(directory, "//"))
+    {
+       fputs("Unijeli ste nedozvoljene znakove!\n", stderr);
+       return ERROR;
+    }
+    len = strlen(directory);
+    if (strstr(directory, group_fallback_dir) != directory
+       || !strcmp(directory, group_fallback_dir))
+    {
+       fprintf(stderr, "Direktorij mora biti podredjen %s direktoriju.\n",
+               group_fallback_dir);
+       return ERROR;
+    }
+    if (directory[len] == '/')
+       directory[len] = 0;
+    return OK;
+}
+
+int getquota(int *soft, int *hard)
+{
+    printf("Unesite donji limit (soft) u KB > ");
+    enter(string, MAXSTR);
+    *soft = atoi(string);
+    if (*soft < 0 || *soft > MAXQUOTA)
+       goto error;
+    if (!*soft)
+    {
+       *hard = 0;
+       return OK;
+    }
+    printf("Unesite gornji limit (hard) u KB > ");
+    enter(string, MAXSTR);
+    *hard = atoi(string);
+    if (*hard >= 0 && *hard <= MAXQUOTA)
+       return OK;
+  error:
+    fputs("Unijeli ste nedozvoljenu vrijednost!\n", stderr);
+    return ERROR;
+}
+
+int testuser(int flag) {
+#if defined(__linux__)
+    char *forbidden[] = { "root", "daemon", "bin", "sys", "sync", "games", "man",
+                         "lp", "mail", "news", "uucp", "proxy", "majordom",
+                         "postgres",/* "www-data",*/ "backup", "msql", "operator",
+                         "list", "irc", "gnats", "nobody", "snort", "ntop",
+                         "mysql", "telnetd", "gdm", "freerad", "" };
+#elif defined(__SVR4)
+    char *forbidden[] = { "root", "daemon", "bin", "sys", "adm", "lp",
+                         "smtp", "uucp", "nuucp", "listen", "nobody", "noaccess", "ftp",
+                         "gopher", "http", "" };
+#elif defined(__osf__)
+    char *forbidden[] = { "root", "nobody", "nobodyV", "daemon", "bin",
+                         "uucp", "uucpa", "auth", "cron", "lp", "tcb", "adm", "ris", "ftp",
+                         "gopher", "http", "" };
+#elif defined(ultrix)
+    char *forbidden[] = { "root", "field", "nobody", "operator", "ris",
+                         "daemon", "sys", "bin", "uucp", "uucpa", "sso", "news", "sccs",
+                         "ingres", "ftp", "gopher", "http", "" };
+#endif
+    int count = 0;
+
+    if (!*loginname)
+       return ERROR;
+    if ((int) strlen(loginname) > 8) {
+       fputs("Maksimalna duzina korisnickog imena je 8 znakova!\n", stderr);
+       return ERROR;
+    }
+    do {
+       if (!islower(loginname[count]) && !isdigit(loginname[count])) {
+           fputs("Unijeli ste nedozvoljene znakove u korisnickom imenu!\n", stderr);
+           return ERROR;
+       }
+       count++;
+    } while (loginname[count]);
+    count = 0;
+    if (flag == ALL && (!strcmp(loginname, "srce") || !strcmp(loginname, "admin")))
+       goto fuckoff;
+    if (authdir) {
+       struct passwd *pwd;
+       pwd = getpwnam(loginname);
+       if (pwd && pwd->pw_dir)
+           if (strstr(pwd->pw_dir, authdir) != pwd->pw_dir)
+               goto fuckoff;
+    }
+    while (*forbidden[count]) {
+       if (!strcmp(forbidden[count], loginname)) {
+         fuckoff:
+           fputs("Nemate ovlasti za unesenog korisnika!\n", stderr);
+           return ERROR;
+       }
+       count++;
+    }
+    return OK;
+}              
+
+int testgroup(void)
+{
+#if defined(__linux__)
+    char *forbidden[] = {"root", "daemon", "bin", "sys", "adm", "tty",
+                       "disk", "lp", "mail", "news", "uucp", "proxy",
+                       "kmem", "dialout", "fax", "voice", "cdrom", "tape",
+                       "sudo", "audio", "dip", "majordom", "postgres",
+                       "backup", "msql", "operator", "list", "irc",
+                       "gnats", "shadow", "utmp", "video", "games",
+                       "nogroup", "snort", "mysql", "telnetd", "gdm",
+                       "freerad", "viruser", "" };
+#elif defined(__SVR4)
+    char *forbidden[] = { "root", "other", "bin", "sys", "adm", "uucp",
+                         "mail", "tty", "lp", "nuucp", "staff", "daemon", "sysadmin",
+                         "nobody", "noaccess", "wheel", "viruser", "" };
+#elif defined(__osf__)
+    char *forbidden[] = { "system", "daemon", "uucp", "mem", "kmem", "bin",
+                         "sec", "mail", "terminal", "tty", "news", "opr", "auth", "lp", "lpr",
+                         "backup", "cron", "sysadmin", "tape", "tcb", "adm", "operator",
+                         "ris", "nobody", "nogroup", "wheel", "" };
+#elif defined(ultrix)
+    char *forbidden[] = { "system", "daemon", "uucp", "rsrv3", "bin", "tty",
+                         "kmem", "authread", "news", "rsrv9", "staff", "ris", "guest",
+                         "operator", "admin", "nobody", "wheel", "" };
+#endif
+    int count = 0;
+
+    if (!*group)
+       return ERROR;
+    if ((int) strlen(group) > 8) {
+       fputs("Maksimalna duzina imena grupe je 8 znakova!\n", stderr);
+       return ERROR;
+    } do {
+       if (!islower(group[count])) {
+           fputs("Unijeli ste nedozvoljene znakove u imenu grupe!\n", stderr);
+           return ERROR;
+       }
+       count++;
+    } while (group[count]);
+    count = 0;
+    while (*forbidden[count]) {
+       if (!strcmp(forbidden[count], group)) {
+           fputs("Nemate ovlasti za unesenu grupu!\n", stderr);
+           return ERROR;
+       }
+       count++;
+    }
+    if (authdir) {
+       struct group *grp = getgrnam(group);
+       if (grp && grp->gr_mem) {
+           struct passwd *pwd;
+           for (; *grp->gr_mem; grp->gr_mem++) {
+               pwd = getpwnam(*grp->gr_mem);
+               if (pwd && pwd->pw_dir) {
+                   if (strstr(pwd->pw_dir, authdir) != pwd->pw_dir) {
+                       fputs("Nemate ovlasti za unesenu grupu!\n", stderr);
+                       return ERROR;
+                   } else
+                       break;
+               }
+           }
+       }
+    }
+    return OK;
+}
+
+int system_default_shell_check(void)
+{
+    #ifndef __linux__
+    return 0;
+    #endif
+
+    struct stat statp;
+    statp.st_mode = 0;
+    
+    (void) stat("/etc/default/useradd", &statp);
+    /* regular file? */
+    if (! statp.st_mode) return 0;
+    if (S_ISREG(statp.st_mode)) {
+        /* XXX maybe check file contents */
+        return 1;
+    } else {
+        return 0;
+    }
+}
+
+void adduser(void)
+{
+    char fullhm[200];
+    char *shellopt="";
+    int l;
+    getuser("Dodavanje korisnika:");
+    if (testuser(NOTALL) == OK && getname() == OK) {
+       strncpy(fullhm, authdir ? authdir : HM, 199);
+       l = strlen(fullhm);
+       if (fullhm[l - 1] != '/') {
+           fullhm[l] = '/';
+           fullhm[l + 1] = '\0';
+       }
+       strncat(fullhm, loginname, 199);
+       logger("USER ADD: user %s, fullname %s", loginname, username);
+#if defined(__SVR4) || defined (__linux__)
+        if (!system_default_shell_check()) {
+            shellopt = "-s " DEFAULTSHELL;
+        }
+       sprintf(command, "/usr/sbin/useradd -m -d %s %s" \
+               " -c \"%s\" %s", fullhm, shellopt, username, loginname);
+       printf("%s\n", command);
+       priv(ON);
+       if (!system(command)) {
+           priv(OFF);
+           #if defined (__linux__)
+           /* Avoid race */
+           sync();
+           #endif /* __linux__ */
+           sprintf(command, "/usr/bin/passwd %s", loginname);
+           priv(ON);
+           system(command);
+       }
+#elif defined(__osf__)
+#if defined(DU4)
+       sprintf(command, "/usr/sbin/useradd -m -s " DEFAULTSHELL \
+               " -c \"%s\" %s", username, loginname);
+       priv(ON);
+       if (!system(command)) {
+           struct pr_passwd *pr;
+  
+           if (!(pr = getprpwnam(loginname))) {
+               perror("getprpwnam");
+               goto problems;
+           }
+           pr->uflg.fg_lock = 1;
+           pr->uflg.fg_min = 1;
+           pr->ufld.fd_min = 0;
+           pr->uflg.fg_expire = 1;
+           pr->ufld.fd_expire = 0;
+           pr->uflg.fg_lifetime = 1;
+           pr->ufld.fd_lifetime = 0;
+           pr->uflg.fg_max_tries = 1;
+           pr->ufld.fd_max_tries = 0;
+           if (!putprpwnam(loginname, pr)) {
+               perror("putprpwnam");
+               goto problems;
+           }
+           sprintf(command, "/usr/bin/passwd %s", loginname);
+           system(command);
+       }
+#else
+       sprintf(command, "/usr/sbin/sysadm.adduser %s \"%s\"", loginname, username);
+       priv(ON);
+       system(command);
+#endif /* DU4 */
+#elif defined(ultrix)
+       sprintf(command, "/usr/etc/sysadm.adduser %s \"%s\"", loginname, username);
+       priv(ON);
+       system(command);
+#endif
+#if defined(DU4)
+      problems:
+#endif
+       priv(OFF);
+    }
+    waitkey();
+    return;
+}
+
+void rmuser(void)
+{
+    getuser("Brisanje korisnika:");
+    if (testuser(ALL) == OK) {
+       logger("USER REMOVE: user %s", loginname);
+#if defined(__SVR4) || defined(__linux__)
+       sprintf(command, "/usr/sbin/userdel -r %s", loginname);
+#elif defined(__osf__)
+    #if defined(DU4)
+       sprintf(command, "/usr/sbin/userdel -r %s", loginname);
+    #else      
+       sprintf(command, "/usr/sbin/sysadm.removeuser %s", loginname);
+    #endif
+#elif defined(ultrix)
+       sprintf(command, "/usr/etc/sysadm.removeuser %s", loginname);
+#endif
+       priv(ON);
+       system(command);
+       priv(OFF);
+    }
+    waitkey();
+    return;
+}
+
+void chpass(void)
+{
+    getuser("Promjena korisnicke lozinke:");
+    if (testuser(NOTALL) == OK) {
+       logger("PASSWD CHANGE: user %s", loginname);
+       sprintf(command, "/usr/bin/passwd %s", loginname);
+       priv(ON);
+       system(command);
+       priv(OFF);
+    }
+    waitkey();
+    return;
+}
+
+void chquota(void)
+{
+    int soft, hard;
+    struct passwd *pwd;
+#if defined(__SVR4)
+    struct dqblk qval;
+    struct quotctl qstr;
+    struct stat statbuf;
+#elif defined(ultrix)
+    struct dqblk qval;
+    struct stat statbuf;
+#elif defined(__linux__)
+  #if defined(__i386__)
+    struct if_dqblk qval; /* sys/quota.h is wrong for 2.4.23/i386 */
+  #elif defined(__sparc__)
+    struct dqblk qval;    /* 2.4.23/sparc is different */
+  #endif
+    struct stat statbuf;
+    struct mntent *mntp;
+    FILE *fp;
+    int dev;
+    char devname[MAXDIR], mountpoint[MAXDIR], greska[MAXDIR];
+    time_t now;
+    devname[0] = '\0';
+#endif
+
+    getuser("Promjena korisnicke quote:");
+    if (testuser(ALL) != OK) {
+       priv(OFF);
+       waitkey();
+       return;
+    }
+
+    if (!(pwd = getpwnam(loginname))) {
+        fputs("Ne postoji uneseni korisnik!\n", stderr);
+        waitkey();
+        return;
+    }
+
+#if defined(__linux__)
+       priv(ON);
+       if (stat(pwd->pw_dir, &statbuf) < 0) {
+           priv(OFF);
+           fputs("Korisnik nema maticni direktorij!\n", stderr);
+           waitkey();
+           return;
+       } else {
+           priv(OFF);
+           dev = statbuf.st_dev;
+       }
+       
+       priv(ON);
+       if (!(fp = setmntent("/etc/mtab", "r"))) {
+           priv(OFF);
+           perror("setmntent");
+           waitkey();
+           return;
+       }       
+       while (feof(fp) == 0) {
+           mntp = getmntent(fp);
+           if (!mntp) break;
+           /* ignore special fs' like proc, devfs... */
+           if (strncmp(mntp->mnt_fsname, "/dev", 4))
+               continue;
+           if (stat(mntp->mnt_fsname, &statbuf) < 0) {
+               priv(OFF);
+               perror("stat");
+               endmntent(fp);
+               waitkey();
+               return;
+           }
+           if (statbuf.st_rdev == dev) {
+               strncpy(devname, mntp->mnt_fsname, MAXDIR);
+               strncpy(mountpoint, mntp->mnt_dir, MAXDIR);
+               break;
+           }
+       }
+       endmntent(fp);
+       priv(OFF);
+       
+       if(! strlen(devname))
+       {
+           fputs("Nije pronadjen device na kojem je korisnikov direktorij!\n", stderr);
+           waitkey();
+           return;
+       }
+
+    #ifdef __i386__
+    /* get previous quota values and update times */
+    priv(ON);
+    if (!quotactl(QCMD(Q_GETQUOTA, USRQUOTA), devname, pwd->pw_uid, (caddr_t) &qval)) {
+        priv(OFF);
+        time(&now);
+        if (qval.dqb_bsoftlimit && (
+                               #if defined (__i386__)
+                               qval.dqb_curspace
+                               #elif defined (__sparc__)
+                               qval.dqb_curblocks
+                               #endif
+                                    /1024) >= qval.dqb_bsoftlimit) {
+            if (!qval.dqb_btime)
+                qval.dqb_btime = now + MAX_DQ_TIME;
+        }
+        else
+            qval.dqb_btime = 0;
+        if (qval.dqb_isoftlimit && qval.dqb_curinodes >= qval.dqb_isoftlimit) {
+            if (!qval.dqb_itime)
+                qval.dqb_itime = now + MAX_DQ_TIME;
+        }
+        else
+                qval.dqb_itime = 0;
+    } else {
+        priv(OFF);
+        fputs("Ne mogu utvrditi trenutne vrijednosti quote!\n", stderr);
+        waitkey();
+        return;
+    }
+    #endif
+#endif
+
+    if (getquota(&soft, &hard) == OK) {
+       logger("QUOTA CHANGE: user %s, soft %d, hard %d", loginname, soft, hard);
+#ifdef __SVR4
+       int i, count, fd;
+#endif
+       if (!soft)
+           fputs("Korisnik ce imati neogranicen pristup diskovnom prostoru!\n", stderr);
+#if defined(__linux__)
+       #if defined(__i386__)
+       /* Actually most of these are u_int64_t. */
+       qval.dqb_bsoftlimit = (u_int32_t) soft;
+       qval.dqb_bhardlimit = (u_int32_t) hard;
+       qval.dqb_isoftlimit = qval.dqb_ihardlimit = (u_int32_t) 0;
+       qval.dqb_btime = (time_t) now + MAX_DQ_TIME;
+       qval.dqb_itime = (time_t) now + MAX_IQ_TIME;
+       #if defined(__i386__)
+       /* Set limits and times */
+       qval.dqb_valid = QIF_LIMITS | QIF_TIMES;
+       #endif
+       priv(ON);
+         if (!
+         #if defined (__i386__)
+           quotactl(QCMD(Q_SETQUOTA, USRQUOTA), devname, pwd->pw_uid, (caddr_t) &qval) 
+         #elif defined (__sparc__)
+           quotactl(QCMD(Q_SETQLIM, USRQUOTA), devname, pwd->pw_uid, (caddr_t) &qval) 
+         #endif
+         )
+       #elif defined (__sparc__)
+         sprintf(command, "/usr/sbin/setquota %s -T %d %d %s", \
+                 loginname, MAX_DQ_TIME, MAX_IQ_TIME, mountpoint);
+         printf("%s\n", command);
+         priv(ON);
+         if (!system(command)) {
+           priv(OFF);
+           /* fputs("Vremensko ogranicenje quote postavljeno.\n", stderr); */
+         }
+         else {
+           priv(OFF);
+           fputs("Nije uspjelo postavljanje vremenskog ogranicenja quote!\n", stderr);
+           waitkey();
+           return;
+         }
+         sprintf(command, "/usr/sbin/setquota %s %d %d %d %d %s", \
+                 loginname, soft, hard, 0, 0, mountpoint);
+         printf("%s\n", command);
+         priv(ON);
+         if (!system(command))
+       #endif /* __sparc__ */
+       {
+           priv(OFF);
+           fputs("Quota uspjesno promijenjena.\n", stderr);
+       }
+       else {
+           priv(OFF);
+           if (errno == 3) {
+               sprintf(greska, "Quota nije ukljucena na filesystemu %s!\n", devname);
+               fputs(greska, stderr);
+           } else {
+               perror("quotactl");
+           }
+       }
+#elif defined(__SVR4)
+       qstr.uid = pwd->pw_uid;
+       for (count = 1; ; count++)
+       {
+           char *ptr;
+
+           strcpy(string, pwd->pw_dir);
+           for (i = 0; i < count; i++)
+           {
+               ptr = strrchr(string, '/');
+               if (ptr)
+                   *ptr = 0;
+               else
+                   goto noquota;
+           }
+           strcat(string, "/quotas");
+           priv(ON);
+           if (!stat(string, &statbuf) && (fd = open(string, O_RDWR)) > 0)
+               goto success;
+           priv(OFF);
+       }
+      noquota:
+       fputs("Nema quote na ovom sistemu!\n", stderr);
+       waitkey();
+       return;
+      success:
+       priv(OFF);
+       qval.dqb_bsoftlimit = (u_long) soft << 1;
+       qval.dqb_bhardlimit = (u_long) hard << 1;
+       qval.dqb_fsoftlimit = qval.dqb_fhardlimit = (u_long) 0;
+       qval.dqb_btimelimit = (u_long) DQ_BTIMELIMIT;
+       qval.dqb_ftimelimit = (u_long) DQ_FTIMELIMIT;
+       qstr.addr = (caddr_t) &qval;
+       qstr.op = Q_SETQLIM;
+       priv(ON);
+       if (!ioctl(fd, Q_QUOTACTL, &qstr))
+           fputs("Quota uspjesno promijenjena.\n", stderr);
+       else
+           perror("quotactl");
+#elif defined(__osf__)
+       qval.dqb_bsoftlimit = (u_long) soft << 1;
+       qval.dqb_bhardlimit = (u_long) hard << 1;
+       qval.dqb_isoftlimit = qval.dqb_ihardlimit = (u_int) 0;
+       qval.dqb_btime = (time_t) MAX_DQ_TIME;
+       qval.dqb_itime = (time_t) MAX_IQ_TIME;
+       priv(ON);
+       if (!quotactl(pwd->pw_dir, QCMD(Q_SETQUOTA, USRQUOTA), pwd->pw_uid, (char *) &qval))
+           fputs("Quota uspjesno promijenjena.\n", stderr);
+       else
+           perror("quotactl");
+#elif defined(ultrix)
+       priv(ON);
+       if (stat(pwd->pw_dir, &statbuf) < 0)
+       {
+           priv(OFF);
+           fputs("Korisnik nema maticni direktorij!\n", stderr);
+           waitkey();
+           return;
+       }
+       priv(OFF);
+       qval.dqb_bsoftlimit = (u_long) soft << 1;
+       qval.dqb_bhardlimit = (u_long) hard << 1;
+       qval.dqb_isoftlimit = qval.dqb_ihardlimit = (u_short) 0;
+       qval.dqb_bwarn = (u_char) MAX_DQ_WARN;
+       qval.dqb_iwarn = (u_char) MAX_IQ_WARN;
+       qval.dqb_curblocks = (u_long) 0;
+       qval.dqb_curinodes = (u_short) 0;
+       priv(ON);
+       if (!quota(Q_SETDLIM, pwd->pw_uid, statbuf.st_dev, (caddr_t) &qval))
+           fputs("Quota uspjesno promijenjena.\n", stderr);
+       else
+           perror("quota");
+#endif
+    }
+    priv(OFF);
+    waitkey();
+    return;
+}
+
+void opgroup(void)
+{
+    char ch;
+    int oldumask;
+
+    for (;;)
+    {
+       priv(OFF);
+       banner();
+       puts("Operacije nad grupama korisnika:\n");
+       puts("1 -- Kreiranje nove grupe");
+       puts("2 -- Dodavanje korisnika u grupu");
+       puts("3 -- Brisanje korisnika iz grupe");
+       puts("4 -- Brisanje grupe");
+       puts("5 -- Kreiranje direktorija (u koji grupa moze pisati)");
+       puts("6 -- Brisanje direktorija\n");
+       puts("7 -- Povratak u osnovni izbornik\n");
+       printf("Unesite odabir > ");
+       ch = getch();
+       clear();
+       switch(ch)
+       {
+           case '1':
+               getgroup("Kreiranje nove grupe:");
+               if (testgroup() == OK)
+               {
+                   logger("GROUP CREATE: group %s", group);
+#if defined(__SVR4) || defined(__linux__)
+                   sprintf(command, "/usr/sbin/groupadd %s", group);
+#elif defined(__osf__)
+                   sprintf(command, "/usr/sbin/sysadm.addgroup %s", group);
+#elif defined(ultrix)
+                   sprintf(command, "/usr/etc/sysadm.addgroup %s", group);
+#endif
+                   priv(ON);
+                   system(command);
+                   priv(OFF);
+               }
+               waitkey();
+               break;
+           case '2':
+               getuser("Dodavanje korisnika u grupu:");
+               if (testuser(ALL) == OK)
+               {
+                   if (getpwnam(loginname))
+                   {
+                       getgroup("");
+                       if (testgroup() == OK)
+                       {
+                           FILE *readfp, *writefp;
+                           char line[2048];
+                           int found = 0;
+
+                           logger("ADD USER TO GROUP: user %s, group %s", loginname, group);
+                           priv(ON);
+                           if (lockpw() == ERROR)
+                           {
+                               priv(OFF);
+#ifdef __osf__
+                               fputs("Probajte malo kasnije, /etc/group je u upotrebi!\n", stderr);
+#endif
+                               goto getout;
+                           }
+                           if (!(readfp = fopen("/etc/group", "rt")))
+                           {
+                               priv(OFF);
+                               fputs("Ne mogu otvoriti /etc/group datoteku!\n", stderr);
+                               goto getout;
+                           }
+                           unlink("/tmp/group");
+                           if (!(writefp = fopen("/tmp/group", "wt")))
+                           {
+                               fclose(readfp);
+                               priv(OFF);
+                               fputs("Ne mogu otvoriti privremenu datoteku!\n", stderr);
+                               goto getout;
+                           }
+                           while (fgets(line, 2048, readfp))
+                           {
+                               if (strstr(line, group) == line && line[strlen(group)] == ':')
+                               {
+                                   char *ptr, left, right;
+
+                                   if ((ptr = strstr(line, loginname)))
+                                   {
+
+                                       left = *(ptr - 1);
+                                       right = *(ptr + strlen(loginname));
+                                       if ((left == ':' || left == ',') &&
+                                           (right == ',' || right == '\n'))
+                                       {
+                                           fclose(readfp);
+                                           fclose(writefp);
+                                           unlink("/tmp/group");
+                                           priv(OFF);
+                                           fputs("Korisnik je vec u unesenoj grupi!\n", stderr);
+                                           goto getout;
+                                       }
+                                   }
+                                   if ((ptr = strrchr(line, '\n')))
+                                       *ptr = 0;
+                                   else
+                                   {
+                                       fclose(readfp);
+                                       fclose(writefp);
+                                       unlink("/tmp/group");
+                                       priv(OFF);
+                                       fputs("Problem s datotekom /etc/group!\n", stderr);
+                                       goto getout;
+                                   }
+                                   if (*(ptr - 1) != ':')
+                                       strcat(line, ",");
+                                   strcat(line, loginname);
+                                   strcat(line, "\n");
+                                   found = 1;
+                               }
+                               fputs(line, writefp);
+                               if (ferror(writefp))
+                               {
+                                   fclose(readfp);
+                                   fclose(writefp);
+                                   unlink("/tmp/group");
+                                   priv(OFF);
+                                   fputs("Problem prilikom pisanja privremene datoteke!\n", stderr);
+                                   goto getout;
+                               }
+                           }
+                           fclose(readfp);
+                           fclose(writefp);
+                           if (found)
+                           {
+                               system("/bin/mv /tmp/group /etc/group");
+                               priv(OFF);
+                               fputs("Korisnik uspjesno dodan u grupu.\n", stderr);
+                           }
+                           else
+                           {
+                               unlink("/tmp/group");
+                               priv(OFF);
+                               fputs("Ne postoji unesena grupa!\n", stderr);
+                           }
+                       }
+                   }
+                   else
+                       fputs("Ne postoji uneseni korisnik!\n", stderr);
+               }
+         getout:
+               priv(ON);
+               unlockpw();
+               priv(OFF);
+               waitkey();
+               break;
+           case '3':
+               getuser("Brisanje korisnika iz grupe:");
+               if (testuser(ALL) == OK)
+               {
+                   if (getpwnam(loginname))
+                   {
+                       getgroup("");
+                       if (testgroup() == OK)
+                       {
+                           FILE *readfp, *writefp;
+                           char line[2048];
+                           int found = 0, empty = 0;
+
+                           logger("REMOVE USER FROM GROUP: user %s, group %s", loginname, group);
+                           priv(ON);
+                           if (lockpw() == ERROR)
+                           {
+                               priv(OFF);
+#ifdef __osf__
+                               fputs("Probajte malo kasnije, /etc/group je u upotrebi!\n", stderr);
+#endif
+                               goto getout1;
+                           }
+                           if (!(readfp = fopen("/etc/group", "rt")))
+                           {
+                               priv(OFF);
+                               fputs("Ne mogu otvoriti /etc/group datoteku!\n", stderr);
+                               goto getout1;
+                           }
+                           unlink("/tmp/group");
+                           if (!(writefp = fopen("/tmp/group", "wt")))
+                           {
+                               fclose(readfp);
+                               priv(OFF);
+                               fputs("Ne mogu otvoriti privremenu datoteku!\n", stderr);
+                               goto getout1;
+                           }
+                           while (fgets(line, 2048, readfp))
+                           {
+                               if (strstr(line, group) == line && line[strlen(group)] == ':')
+                               {
+                                   char *ptr, left, right;
+
+                                   if ((ptr = strstr(line, loginname)))
+                                   {
+                                       left = *(ptr - 1);
+                                       right = *(ptr + strlen(loginname));
+                                       if ((left == ':' || left == ',') &&
+                                           (right == ',' || right == '\n'))
+                                           goto ok;
+                                                                                       
+                                   }
+                                   fclose(readfp);
+                                   fclose(writefp);
+                                   unlink("/tmp/group");
+                                   priv(OFF);
+                                   fputs("Korisnik nije u unesenoj grupi!\n", stderr);
+                                   goto getout1;
+                                 ok:
+                                   if (right != '\n')
+                                       strcpy(ptr, ptr + strlen(loginname) + 1);
+                                   else if (left != ':')
+                                       strcpy(ptr - 1, "\n");
+                                   else
+                                   {
+                                       empty = 1;
+                                       strcpy(ptr, "\n");
+                                   }
+                                   found = 1;
+                               }
+                               fputs(line, writefp);
+                               if (ferror(writefp))
+                               {
+                                   fclose(readfp);
+                                   fclose(writefp);
+                                   unlink("/tmp/group");
+                                   priv(OFF);
+                                   fputs("Problem prilikom pisanja privremene datoteke!\n", stderr);
+                                   goto getout1;
+                               }
+                           }
+                           fclose(readfp);
+                           fclose(writefp);
+                           if (found)
+                           {
+                               system("/bin/mv /tmp/group /etc/group"); /* JUNK */
+                               priv(OFF);
+                               fputs("Korisnik uspjesno obrisan iz grupe.\n", stderr);
+                               if (empty)
+                                   fputs("U grupi nema vise ni jednog korisnika.\n", stderr);
+                           }
+                           else
+                           {
+                               unlink("/tmp/group");
+                               priv(OFF);
+                               fputs("Ne postoji unesena grupa!\n", stderr);
+                           }
+                       }
+                   }
+                   else
+                       fputs("Ne postoji uneseni korisnik!\n", stderr);
+               }
+         getout1:
+               priv(ON);
+               unlockpw();
+               priv(OFF);
+               waitkey();
+               break;
+           case '4':
+               getgroup("Brisanje grupe:");
+               if (testgroup() == OK)
+               {
+                   logger("GROUP REMOVE: group %s", group);
+#if defined(__SVR4) || defined(__linux__)
+                   sprintf(command, "/usr/sbin/groupdel %s", group);
+#elif defined(__osf__)
+                   sprintf(command, "/usr/sbin/sysadm.removegroup %s", group);
+#elif defined(ultrix)
+                   sprintf(command, "/usr/etc/sysadm.removegroup %s", group);
+#endif
+                   priv(ON);
+                   system(command);
+                   priv(OFF);
+               }
+               waitkey();
+               break;
+           case '5':
+               oldumask = umask(002);
+               if (getdir() == OK)
+               {
+                   getgroup("Grupa u cije vlasnistvo zelite staviti direktorij:");
+                   if (testgroup() == OK)
+                   {
+                       struct group *grpptr;
+                       int i, status;
+
+                       grpptr = getgrnam(group);
+                       if (!grpptr)
+                       {
+                           fputs("Trazena grupa ne postoji!\n", stderr);
+                           goto donedir;
+                       }
+                       logger("DIRECTORY CREATE: directory %s, group %s", directory, group);
+                       for (i = 1;;i++)
+                       {
+                           while (directory[i] && directory[i] != '/')
+                               i++;
+                           if (directory[i])
+                           {
+                               directory[i] = 0;
+                               priv(ON);
+                               status = mkdir(directory, 0755);
+                               if (status < 0 && errno != EEXIST)
+                               {
+                                   priv(OFF);
+                                   perror("mkdir");
+                                   goto donedir;
+                               }
+                               priv(OFF);
+                               directory[i] = '/';
+                           }
+                           else
+                           {
+                               priv(ON);
+                               status = mkdir(directory, 0775);
+                               if (status < 0 && errno != EEXIST)
+                               {
+                                   perror("mkdir");
+                                   goto donedir;
+                               }
+                               errno = 0;
+                               if (chown(directory, (uid_t) -1, grpptr->gr_gid) < 0)
+                                   perror("chown");
+                               else
+                                   fputs("Direktorij uspjesno kreiran.\n", stderr);
+                               goto donedir;
+                           }
+                       }
+                   }
+               }
+         donedir:
+               priv(OFF);
+               umask(oldumask);
+               waitkey();
+               break;
+           case '6':
+               if (getdir() == OK)
+               {
+                   logger("DIRECTORY REMOVE: directory %s", directory);
+                   priv(ON);
+                   if (rmdir(directory) < 0)
+                       perror("rmdir");
+                   else
+                       fputs("Direktorij uspjesno obrisan.\n", stderr);
+                   priv(OFF);
+               }
+               waitkey();
+               break;
+           case '7':
+           case 'Q':
+           case 'q':
+               return;
+           default:
+               break;
+       }
+    }
+}
+
+void shutdown(void)
+{
+    int count = 0;
+
+    printf("Unesite poruku za korisnike > ");
+    enter(message, MAXMESS);
+    do
+    {
+       if (!isalpha(message[count]) && !isspace(message[count]) && !isdigit(message[count]) && message[count] != '.' && message[count] != ',' && message[count] != '_' && message[count] != '-' && message[count] != '=')
+       {
+           priv(OFF);
+           fputs("Unijeli ste nedozvoljene znakove u poruci!\n", stderr);
+           waitkey();
+           return;
+       }
+       count++;
+    } while (message[count]);
+    printf("\nUnesite vrijeme kroz koje ce se racunalo zaustaviti (1 - 60 min) > ");
+    enter(string, MAXSTR);
+    grace = atoi(string);
+    if (grace < MINGRACE || grace > MAXGRACE)
+    {
+       priv(OFF);
+       fprintf(stderr, "Unijeli ste vrijeme koje je nula, negativno ili preveliko!\n");
+       waitkey();
+       return;
+    }
+#if defined(__SVR4)
+    grace *= 60;
+#endif
+    puts("Pokrenuta je procedura za zaustavljanje racunala!\n");
+    logger("SHUTDOWN!");
+#if defined(__SVR4)
+    sprintf(command, "/usr/sbin/shutdown -i0 -y -g%d \"%s\"", grace, message);
+#elif defined(__osf__) || defined (__linux__)
+    sprintf(command, "/sbin/shutdown -h +%d %s", grace, message);
+#elif defined(ultrix)
+    sprintf(command, "/bin/shutdown -h +%d %s", grace, message);
+#endif
+    priv(ON);
+    system(command);
+    priv(OFF);
+  loop:
+    sleep(10);
+    goto loop;
+    waitkey();
+    return;
+}
+
+void manual(void)
+{
+    FILE* manual;
+    char line[256];
+    int count = 0;
+
+    logger("MANUAL READ");
+    priv(ON);
+    if (!(manual = fopen(MANFILE, "rt")))
+    {
+       priv(OFF);
+       fputs("Uputstva nisu instalirana!\n", stderr);
+       waitkey();
+       return;
+    }
+    priv(OFF);
+    while (fgets(line, 256, manual))
+    {
+       fputs(line, stdout);
+       if (count++ == 21)
+       {
+           waitkey();
+           clear();
+           count = 0;
+       }
+    }
+    fclose(manual);
+    waitkey();
+    return;
+}
+
+void banner(void)
+{
+    clear();
+    puts(VERSION);
+    return;
+}
+
+void console_check(char *name)
+{
+    char *cptr;
+    int oncon = 0;
+    struct stat statbuf;
+    struct utmp entry;
+    FILE *fp;
+
+    priv(OFF);
+    if (isatty(0))
+       cptr = ttyname(0);
+    else
+    {
+       fprintf(stderr, "\nProblem s terminalom.\nIzlazak iz programa!\n");
+       exit(1);
+    }
+    if (!cptr || strcmp(cptr, CONSOLE))
+    {
+       if (stat(CONSOLE, &statbuf) < 0)
+       {
+           fprintf(stderr, "\nNe mogu provjeriti vlasnistvo /dev/console.\nIzlazak iz programa!\n");
+           exit(1);
+       }
+       if (statbuf.st_uid == saveduid)
+           return;
+#if defined(__SVR4)
+       else
+           consexit();
+#endif
+
+#if defined(__osf__) || defined(ultrix) || defined(__linux__)
+       if (strstr(cptr, "/dev/") == cptr)
+           strcpy(cptr, cptr + 5);
+       fp = fopen(UTMP_FILE, "r");
+       if (!fp)
+       {
+           priv(OFF);
+           fprintf(stderr, "\nNe mogu otvoriti utmp datoteku.\nIzlazak iz programa!\n");
+           exit(1);
+       }
+       while (fread(&entry, sizeof(entry), 1, fp))
+       {
+       #if defined(__linux__)
+           entry.ut_line[UT_LINESIZE-1] = 0;
+           entry.ut_user[UT_NAMESIZE-1] = 0;
+           entry.ut_host[UT_HOSTSIZE-1] = 0;
+       #else
+           entry.ut_line[8] = 0;
+           entry.ut_name[8] = 0;
+           entry.ut_host[16] = 0;
+       #endif
+       #if defined (__linux__)
+           if (entry.ut_type == DEAD_PROCESS)
+               continue;
+           if (strncmp(entry.ut_line, cptr, UT_LINESIZE-1))
+               continue;
+           if (!strncmp(entry.ut_line, "tty", 3) && \
+               entry.ut_line[3] >= '0' && \
+               entry.ut_line[3] <= '9' && \
+               !strncmp(entry.ut_user, name, UT_NAMESIZE-1)) {
+               oncon = 1;
+               break;
+               }
+           else if (!strncmp(entry.ut_host, ":0", 2) && \
+                    !strncmp(entry.ut_user, name, UT_NAMESIZE-1)) {
+               oncon = 1;
+               break;
+               }
+           else
+               break; /* pravi tty, a nije na konzoli */
+       #else
+           if (strncmp(entry.ut_line, cptr, 8))
+               continue;
+           if (!strncmp(entry.ut_line, ":0", 2) && !strncmp(entry.ut_name, name, 8))
+               {
+                   oncon = 1;
+                   break;
+               }
+           if (!strncmp(entry.ut_host, ":0.0", 8) || !strncmp(entry.ut_host, "local", 8)) {
+                   oncon = 1;
+                   break;
+               }
+       #endif /* __linux__ */
+       }
+       fclose(fp);
+       if (!oncon)
+           consexit();
+#endif
+    }
+    return;
+}
+
+
+int main(int argc, char **argv)
+{
+    char ch, *cptr;
+    int allowed;
+    FILE *aclfile;
+    FILE *conffile;
+    struct passwd *acl = NULL;
+    char adminlogin[64], adminfull[1024];
+    char *p;
+
+#if defined(DU4)
+    set_auth_parameters(argc,argv);
+#endif
+    umask(022);
+    putenv("IFS=\" \"");
+    signal(SIGINT, SIG_IGN);
+    signal(SIGTSTP, SIG_IGN);
+    signal(SIGQUIT, SIG_IGN);
+    signal(SIGPIPE, SIG_IGN);
+    saveduid = getuid();
+    setuid(0);
+    chmod(LOGFILE, 0600);
+    chmod(ACLFILE, 0600);
+    chown(LOGFILE, 0, -1);
+    chown(ACLFILE, 0, -1);
+    if (!(logfile = fopen(LOGFILE, "a")))
+    {
+       priv(OFF);
+       perror("fopen");
+       fprintf(stderr, "\nNe mogu otvoriti log datoteku.\nIzlazak iz programa!\n");
+       exit(1);
+    }
+    if (saveduid)
+    {
+       if (!(aclfile = fopen(ACLFILE, "r")))
+       {
+           priv(OFF);
+           perror("fopen");
+           fprintf(stderr, "\nNe mogu otvoriti datoteku kontrole pristupa.\nIzlazak iz programa!\n");
+           exit(1);
+       }
+       allowed = 0;
+       while (fgets(string, MAXSTR, aclfile))
+       {
+           if (*string == '#')
+               continue;
+           authdir = group_fallback_dir = NULL;
+           for (p = string; *p && !isspace(*p); p++);
+           cptr = p;
+           if (*p && *p != '\n')
+           {
+               while (isspace(*p))
+                   ++p;
+               authdir = p;
+               while (*p && !isspace(*p))
+                   ++p;
+               if (*p != '\n')
+               {
+                   *p++ = '\0';
+                   group_fallback_dir = p;
+                   while (*p && !isspace(*p))
+                       ++p;
+                   *p = '\0';
+                   group_fallback_dir = strdup(group_fallback_dir);
+               }
+               else
+                   *p = '\0';
+           }
+           *cptr = 0;
+           if ((acl = getpwnam(string)) && acl->pw_uid == saveduid)
+           {
+               if (authdir)
+                   authdir = strdup(authdir);
+               else
+                   authdir = NULL;
+               allowed = 1;
+               break;
+           }
+       }
+       fclose(aclfile);
+       if (!group_fallback_dir)
+           group_fallback_dir = authdir ? authdir : HM;
+       if (!allowed)
+       {
+           priv(OFF);
+           fprintf(stderr, "\nNemate dozvolu za koristenje programa.\nIzlazak iz programa!\n");
+           exit(1);
+       }
+       priv(ON);
+       if (!(conffile = fopen(OPTFILE, "r"))) {
+           priv(OFF);
+/*         perror("fopen");
+           fprintf(stderr, "Ne mogu otvoriti datoteku s konfiguracijskim opcijama.\n");
+           sleep(2);
+*/     }
+       else {
+           priv(OFF);
+           while (fgets(string, MAXSTR, conffile)) {
+               p = &string[strlen(string)-1];
+               if (*p == '\n')
+                   *p = '\0';
+               if (!strncmp(string, CONF_NOCONSOLE, MAXSTR-1)) 
+                   conscheck = 0;
+           }
+           fclose(conffile);
+       }
+       
+       if (!authdir && conscheck)
+          console_check(acl->pw_name);
+    }
+    else
+    {
+       authdir = NULL;
+       group_fallback_dir = HM;
+       acl = getpwuid(0);
+    }
+    if (acl && acl->pw_name)
+       strcpy(adminlogin, acl->pw_name);
+    else
+       strcpy(adminlogin, "(none)");
+    if (acl && acl->pw_gecos)
+       strcpy(adminfull, acl->pw_gecos);
+    else
+       strcpy(adminfull, "NULL");
+    logger("ADMIN START: admin %s (%s)", adminlogin, adminfull);
+    for (;;)
+    {
+       priv(OFF);
+       banner();
+       puts("1 -- Dodavanje korisnika");
+       puts("2 -- Brisanje korisnika");
+       puts("3 -- Promjena lozinke korisnika");
+       puts("4 -- Promjena quote korisnika\n");
+       puts("5 -- Operacije nad grupama korisnika\n");
+       puts("6 -- Zaustavljanje i gasenje racunala\n");
+       puts("7 -- Pomoc\n");
+       puts("8 -- Izlazak iz administracijskog programa\n");
+       printf("Unesite odabir > ");
+       ch = getch();
+       clear();
+       switch(ch)
+       {
+           case '1':
+               adduser();
+               break;
+           case '2':
+               rmuser();
+               break;
+           case '3':
+               chpass();
+               break;
+           case '4':
+               chquota();
+               break;
+           case '5':
+               opgroup();
+               break;
+           case '6':
+               shutdown();
+               break;
+           case '7':
+           case 'h':
+           case '?':
+               manual();
+               break;
+           case '0':
+           case '8':
+           case 'Q':
+           case 'q':
+               clear();
+               logger("ADMIN END: admin %s (%s)", adminlogin, adminfull);
+               fclose(logfile);
+               exit(0);
+           default:
+               break;
+       }
+    }
+}
diff --git a/sysadmin.h b/sysadmin.h
new file mode 100644 (file)
index 0000000..b79de61
--- /dev/null
@@ -0,0 +1,138 @@
+#ifdef ultrix
+#      define POSIX
+#      define __POSIX
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <utmp.h>
+#include <time.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "version.h"
+
+/* HM's must have / at the end !!! */
+
+#if defined(__linux__)
+  #define HM "/home/"
+  #if defined(__i386__)
+    #include "quota.h"  /* From quota-3.09, works only for new quota! */
+    #include "quotaio.h"
+    #include "dqblk_v2.h"
+    #include <mntent.h>
+  #elif defined(__sparc__)
+    #include <sys/quota.h>
+    #include <mntent.h>
+  #else
+  #error Unknown architecture!
+  #endif
+#elif defined(__SVR4)
+  #define HM "/home/"
+  #include <sys/fs/ufs_quota.h>
+#elif defined(__osf__)
+  #if defined(DU4)
+    #define HM "/home/"
+    #include <sys/security.h>
+    #include <prot.h>
+    #include <ufs/quota.h>
+    int quotactl(char *, int, int, char *);
+  #else
+    #define HM "/usr/users/"
+    #include <ufs/quota.h>
+    int quotactl(char *, int, int, char *);
+  #endif
+#elif defined(ultrix)
+  #define HM "/usr/users/"
+  #include <sys/param.h>
+  #include <sys/quota.h>
+  int quota(int, int, int, caddr_t);
+  extern int setreuid(uid_t, uid_t);
+  extern int seteuid(uid_t);
+  extern int putenv(char *);
+#endif
+
+#define ALL 0                  /* forbidden + srce + admin */
+#define NOTALL 1               /* only forbidden */
+#define ERROR 2                        /* error condition */
+#define OK 3                   /* everything's fine */
+
+#define OFF 0                  /* drop privileges */
+#define ON 1                   /* get priviliges */
+
+#define MAXLOGIN 16            /* max login size + 1 */
+#define MAXGROUP 16            /* max group name + 1 */
+#define MAXNAME 64             /* max username size + 1 */
+#define MAXSTR 64              /* max input string for quota numbers + 1 */
+#define MAXDIR 1024            /* max pathlen */
+#define MAXCOMMAND 256         /* max string length for system() */
+#define MAXQUOTA 262144                /* max quota in KB */
+#define MAXMESS 200            /* max message length for shutdown */
+#define MINGRACE 1             /* min grace period for shutdown */
+#define MAXGRACE 60            /* max grace period for shutdown */
+
+#define CONSOLE "/dev/console" /* console device */
+
+#define CONF_NOCONSOLE "no_console_check" /* Config: don't check for console */
+
+#if defined (__linux__) || defined(__SVR4)
+  #define LOGFILE "/var/log/sysadmin.log" /* logfile */
+  #define ACLFILE "/etc/sysadmin/users"   /* acl file */
+  #define OPTFILE "/etc/sysadmin/config"  /* config */
+  #if defined (__linux__)
+    #define MANFILE "/usr/share/sysadmin/sysadm.man" /* online manual */
+    #define PARSE_USERADD_DEFAULTS 1
+  #else /* __SVR4 */
+    #define MANFILE "/usr/local/share/sysadmin/sysadm.man" /* online manual */
+  #endif
+#else
+  #define LOGFILE "/var/adm/adminlog" /* logfile */
+  #define ACLFILE "/etc/adminusers"   /* acl file */
+  #define OPTFILE "/etc/adminconfig"  /* config */
+  #define MANFILE "/etc/sysadm.man"   /* online manual */
+#endif
+
+#if defined(__linux__)
+  #define DEFAULTSHELL "/bin/bash"
+#else
+  #define DEFAULTSHELL "/bin/csh"
+#endif
+
+/* function prototypes */
+
+void logger(char *, ...);
+void printpriv(char *);
+void priv(int);
+int lockpw(void);
+void unlockpw(void);
+void consexit(void);
+int getch(void);
+void clear(void);
+void waitkey(void);
+void enter(char *, int);
+void getuser(char *);
+void getgroup(char *);
+int getname(void);
+int getdir(void);
+int getquota(int *, int *);
+int testuser(int);
+int testgroup(void);
+int system_default_shell_check(void);
+void adduser(void);
+void rmuser(void);
+void chpass(void);
+void chquota(void);
+void opgroup(void);
+void shutdown(void);
+void manual(void);
+void banner(void);
+void console_check(char *);
diff --git a/sysadmin.html b/sysadmin.html
new file mode 100644 (file)
index 0000000..902b986
--- /dev/null
@@ -0,0 +1,170 @@
+<html>
+<head>
+<link rev=made href="mailto:zcalusic@srce.hr">
+<title>sysadmin v1.20</title>
+</head>
+
+<body>
+<h1 align=center>sysadmin v1.20</h1>
+<h1 align=center>Administracijski program</h1></em>
+<p>
+<h2>Namjena</h2>
+<p>
+Program je namijenjen za jednostavnu administraciju
+UNIX raèunala, prvenstveno osobama koje nisu u potpunosti ovladale
+potrebnim znanjima, ali imaju potrebu za nekim osnovnim operacijama.<br>
+Moguæe je izvesti slijedeæe operacije:
+
+<multicol cols=2>
+Dodavanje korisnika<br>
+Brisanje korisnika<br>
+Promjena lozinke korisnika<br>
+Promjena quote korisnika<br>
+Otvaranje nove grupe<br>
+Brisanje grupe<br>
+Dodavanje korisnika u grupu<br>
+Brisanje korisnika iz grupe<br>
+Otvaranje direktorija za rad grupe<br>
+Brisanje direktorija za rad grupe<br>
+Zaustavljanje i ga¹enje raèunala<br>
+</multicol>
+<p>
+<h2>Kratki opis</h2>
+<p>
+Jedan od osnovnih zahtjeva u izradi ovog programa je sigurnost stroja
+na kojem se izvodi. S obzirom na potrebne funkcije, program se izvodi
+sa superkorisnièkim ovlastima, ali ih se li¹ava èim mu nisu
+neophodne. Na taj naèin se smanjuje opasnost od zlouporabe. Osim toga,
+izvoðenje programa je moguæe samo sa sistemske konzole raèunala (osim
+u sluèaju kad ga pokreæe superkorisnik). Program provjerava sve operacije
+zadane od korisnika i odbija izvr¹iti one koje bi naru¹ile
+integritet raèunala odn. operacionog sustava.
+<p>
+Svaka uspje¹na operacija se bilje¾i u za to predviðenu log datoteku.
+Uz opis izvoðene operacije, u ovoj datoteci se mo¾e naæi i toèno vrijeme
+izvoðenja te svi proslijeðeni parametri. Za sluèaj da se programom
+koristi vi¹e osoba, program bilje¾i i svako svoje pokretanje
+(i izla¾enje) sa imenom osobe koja ga je pokrenula (ukoliko je start
+bio uspje¹an).
+<p>
+Kontrola pristupa se vr¹i preko kontrolne datoteke u kojoj su
+popisane osobe koje imaju pravo izvr¹avanja programa. Program
+se mo¾e izvoditi na slijedeæim platformama:
+<ul>
+<li>Solaris 2.4
+<li>OSF/1 3.0
+<li>Ultrix 4.2
+</ul>
+Naravno, podr¾ane su i vi¹e inaèice navedenih operacionih sustava.
+<p>
+Program je izveden u programskom jeziku <strong>C</strong>.
+Na OSF/1 i Ultrix OS koristi i po èetiri pomoæne skripte (raðene za
+<strong>/bin/sh</strong> ljusku),
+koje su izvedene iz sistemskih skripti iste namjene, ali im je poveæana
+sigurnost kod uporabe. Sve verzije se kompiliraju iz istog izvornog
+koda (sourcea). S programom dolaze upute za uporabu, te program za
+instaliranje.
+<p>
+<h2>Instalacija</h2>
+<p>
+Arhiva sa svim potrebnim dijelovima programa mo¾e se naæi na raèunalu
+<strong>bagan.srce.hr</strong> (IP adresa <strong>161.53.2.66</strong>) u direktorijima:
+<ul>
+<li>/export/ftp/solaris2/SRCE/
+<li>/export/ftp/osf1/SRCE/
+<li>/export/ftp/ultrix/SRCE/
+</ul>
+Naziv arhive je <strong>sysadmin-1.20.tar</strong>,
+a uz nju ide i pripadajuæi program za instalaciju naziva <strong>sysadmin-1.20.inst</strong>.
+<p>
+Kontrolne sume ovih datoteka su:
+<pre>
+MD5 (sysadmin-1.20.tar) = d45808f333b18395fbb318e9bf6dc4c2
+MD5 (sysadmin-1.20.inst) = 4c640319c988e5bbe4c1d6ab6b518063
+</pre>
+Arhive u sva tri direktorija su identiène i sadr¾e sve potrebne binarne
+datoteke, za sve potrebne platforme te izvorni kod programa. Ovakav
+razmje¹taj je odabran iskljuèivo zbog jednostavnosti pronala¾enja
+arhiva.
+<p>
+Preporuèeni naèin instalacije je pokretanje instalacijske skripte,
+koja se sama brine za otpakiravanje arhive, prepoznavanje platforme
+(OS-a) i razmje¹taj datoteka, koji se pone¹to razlikuje
+na razlièitim operacionim sustavima:
+<ul>
+<li>sysadmin izvr¹ni program instalira se kao <strong>/usr/bin/sysadmin</strong>
+(sve platforme)
+<li>online priruènik se pronalazi kao <strong>/etc/sysadm.man</strong>
+(sve platforme)
+<li>pomoæni programi se nalaze u <strong>/usr/sbin</strong> direktoriju
+(OSF/1), odn. <strong>/usr/etc</strong> direktoriju
+(Ultrix)
+</ul>
+Imena pomoænih programa su: <strong>sysadm.addgroup, sysadm.adduser, sysadm.removegroup,
+sysadm.removeuser (sysadm.*)</strong>.
+<p>
+Solaris OS ne zahtijeva pomoæne programe!
+<p>
+Primjer instalacije:
+<pre>
+# cd /tmp
+# ftp 161.53.2.66
+Connected to 161.53.2.66.
+220 bagan FTP server (Version wu-2.4-ci(5) Fri Apr 26 13:03:49 MET DST 1996) ready.
+Name (161.53.2.66:zcalusic):
+331 Password required for zcalusic.
+Password:
+230 User zcalusic logged in.
+ftp> cd /export/ftp/ultrix/SRCE
+250 CWD command successful.
+ftp> bi
+200 Type set to I.
+ftp> prompt
+Interactive mode off.
+ftp> mget sysadmin*
+200 PORT command successful.
+150 Opening BINARY mode data connection for sysadmin-1.20.inst (1497 bytes).
+226 Transfer complete.
+local: sysadmin-1.20.inst remote: sysadmin-1.20.inst
+1497 bytes received in 0.1 seconds (14 Kbytes/s)
+200 PORT command successful.
+150 Opening BINARY mode data connection for sysadmin-1.20.tar (256000 bytes).
+226 Transfer complete.
+local: sysadmin-1.20.tar remote: sysadmin-1.20.tar
+256000 bytes received in 0.7 seconds (3.6e+02 Kbytes/s)
+ftp> quit
+221 Goodbye.
+# chmod +x sysadmin-1.20.inst
+# ./sysadmin-1.20.inst
+Instalacija sysadmin programa v1.20 na Ultrix platformu...
+...
+</pre>
+Nakon uspje¹nog instaliranja, program za instalaciju bri¹e
+arhivu i samog sebe, te ispisuje poruku:
+<pre>
+Za provjeru instalacije, dodaj login srce (SRCE Admin)!
+Ne zaboravi kreirati datoteku /etc/adminusers (root, 600)!
+</pre>
+U datoteku <strong>/etc/adminusers</strong> potrebno
+je unijeti korisnièka imena osoba koje imaju pravo pokretanja programa.
+Svakog korisnika treba unijeti u zasebnu liniju ove datoteke. Ukoliko
+linija poèinje s znakom '#',
+program smatra da smo unijeli komentar i zanemaruje ostatak linije.
+<p>
+Datoteka za logiranje mo¾e se pronaæi kao <strong>/var/adm/adminlog</strong>.
+Ukoliko ne postoji, biti æe kreirana kod prvog pokretanja programa.
+<p>
+Ove dvije specijalne datoteke èitati i mijenjati mo¾e samo superkorisnik,
+a program se kod svakog pokretanja brine da dozvole i ostanu takvima.
+<p>
+<h2>O autoru</h2>
+<p>
+Mentor projekta je <strong>Dobri¹a Dobreniæ</strong>.<br>
+Autor programa je <strong>Zlatko Èalu¹iæ</strong>.
+<p>
+Upute priredio <strong>Zlatko Èalu¹iæ</strong> &lt;<a href="mailto:zcalusic@srce
+.hr">zcalusic@srce.hr</a>&gt;<br>
+Last modified: Fri Dec 20 01:25:31 MET 1996
+
+</body>
+</html>
diff --git a/test.c b/test.c
new file mode 100644 (file)
index 0000000..befe555
--- /dev/null
+++ b/test.c
@@ -0,0 +1,28 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/quota.h>
+
+#define MAXDIR (1024)
+
+int main(void)
+{
+    struct passwd *pwd;
+    struct dqblk qval;
+#if defined(__SVR4)
+    struct quotctl qstr;
+    struct stat statbuf;
+#elif defined(ultrix)
+    struct stat statbuf;
+#elif defined(__linux__)
+    struct stat statbuf;
+    struct mntent *mntp;
+    FILE *fp;
+    int dev;
+    char devname[MAXDIR], greska[MAXDIR];
+    devname[0] = '\0';
+#endif
+
+    int soft, hard;
+    return 0;
+}
\ No newline at end of file
diff --git a/users b/users
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..446a90d
--- /dev/null
+++ b/version.h
@@ -0,0 +1,4 @@
+#ifndef VERSION_H
+       #define VERSION_H
+       #define VERSION "v1.25.1, Fri, 30 May 2003 11:26:24 +0200"
+#endif