--- /dev/null
+#
+# 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!"
--- /dev/null
+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
--- /dev/null
+changelog
\ No newline at end of file
--- /dev/null
+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
+
--- /dev/null
+etc/sysadmin/users
--- /dev/null
+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.
--- /dev/null
+etc/sysadmin
+usr/bin
+usr/share/sysadmin
+var/log
--- /dev/null
+README.CARNet
+changelog.CARNet
+manual.txt
--- /dev/null
+users etc/sysadmin
+sysadm.man usr/share/sysadmin
+sysadmin usr/bin
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ *
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+../../sysadmin/sysadm.man
\ No newline at end of file
--- /dev/null
+#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
--- /dev/null
+#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_ */
--- /dev/null
+/*
+ *
+ * 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 */
--- /dev/null
+/*
+ *
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ *
+ * 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
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+/*
+ *
+ * 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 */
--- /dev/null
+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
--- /dev/null
+/*
+ *
+ * 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;
+ }
+ }
+}
--- /dev/null
+#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 *);
--- /dev/null
+<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> <<a href="mailto:zcalusic@srce
+.hr">zcalusic@srce.hr</a>><br>
+Last modified: Fri Dec 20 01:25:31 MET 1996
+
+</body>
+</html>
--- /dev/null
+#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
--- /dev/null
+#ifndef VERSION_H
+ #define VERSION_H
+ #define VERSION "v1.25.1, Fri, 30 May 2003 11:26:24 +0200"
+#endif