home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3477 < prev    next >
Internet Message Format  |  1991-06-11  |  73KB

  1. From: jfh@rpp386.cactus.org (John F Haugh II)
  2. Newsgroups: alt.sources
  3. Subject: Shadow Login Suite, patch 4
  4. Message-ID: <19372@rpp386.cactus.org>
  5. Date: 11 Jun 91 11:27:15 GMT
  6.  
  7. [ Either this didn't make it off this site or I'm in really bad shape. ]
  8.  
  9. This is patch #4 for the current beta test release of the shadow login
  10. suite.  It adds three new commands, useradd, userdel and usermod.  The
  11. documentation that I promised in patch #3 hasn't been written.  I've been
  12. busy planning a wedding (mine) and I've not had the time.  You may refer
  13. either to the source code or your nearest SVR4 documentation for the
  14. behavior of these commands.
  15.  
  16. It is known that there are bugs in these three new commands.  Since they
  17. are the newest code in the entire suite, that's to be expected.  Have
  18. patience and I'll get it fixed.  Some of the bugs have been fixed already,
  19. and other fixes are due out in patch #6 (patch #5 is currently being
  20. verified by Chip).
  21.  
  22. Also added was a "patchlevel.h" file.  So many of you asked for it, so
  23. I've provided it ...
  24. --
  25. *** /dev/null    Fri Jun  7 11:02:59 1991
  26. --- patchlevel.h    Fri Jun  7 11:13:28 1991
  27. ***************
  28. *** 0 ****
  29. --- 1,13 ----
  30. + /*
  31. +  * Copyright 1991, John F. Haugh II
  32. +  * All rights reserved.
  33. +  *
  34. +  * Permission is granted to copy and create derivative works for any
  35. +  * non-commercial purpose, provided this copyright notice is preserved
  36. +  * in all copies of source code, or included in human readable form
  37. +  * and conspicuously displayed on all copies of object code or
  38. +  * distribution media.
  39. +  */
  40. + #define    RELEASE        3
  41. + #define    PATCHLEVEL    4
  42. *** rel3/config.h    Thu Jun  6 09:35:02 1991
  43. --- config.h    Fri Jun  7 11:11:26 1991
  44. ***************
  45. *** 12,18 ****
  46.   /*
  47.    * Configuration file for login.
  48.    *
  49. !  *    @(#)config.h    3.7    08:57:09    5/30/91
  50.    */
  51.   
  52.   /*
  53. --- 12,18 ----
  54.   /*
  55.    * Configuration file for login.
  56.    *
  57. !  *    @(#)config.h    3.8    11:11:17    6/7/91
  58.    */
  59.   
  60.   /*
  61. ***************
  62. *** 31,40 ****
  63. --- 31,44 ----
  64.    * for getpwuid() and getpwnam().  This provides compatibility for
  65.    * privileged applications which are shadow-ignorant.  YOU ARE
  66.    * ENCOURAGED TO NOT USE THIS OPTION UNLESS ABSOLUTELY NECESSARY.
  67. +  *
  68. +  * Define SHADOWGRP to user shadowed group files.  This feature adds
  69. +  * the concept of a group administrator.
  70.    */
  71.   
  72.   #define    SHADOWPWD
  73.   #undef    AUTOSHADOW
  74. + #define    SHADOWGRP
  75.   
  76.   /*
  77.    * Define DOUBLESIZE to use 16 character passwords
  78. ***************
  79. *** 270,275 ****
  80. --- 274,282 ----
  81.   #define    GETPWENT    /* Define if you want my GETPWENT(3) routines */
  82.   #define    GETGRENT    /* Define if you want my GETGRENT(3) routines */
  83.   #define    NEED_AL64    /* Define if library does not include a64l() */
  84. + #define    NEED_MKDIR    /* Define if system does not have mkdir() */
  85. + #define    NEED_RMDIR    /* Define if system does not have rmdir() */
  86. + #define    NEED_RENAME    /* Define if system does not have rename() */
  87.   #undef    NO_STRSTR    /* Define if library does not include strstr() */
  88.   
  89.   /*
  90. *** rel3/Makefile    Thu Jun  6 09:35:02 1991
  91. --- Makefile    Fri Jun  7 11:12:38 1991
  92. ***************
  93. *** 8,16 ****
  94.   # and conspicuously displayed on all copies of object code or
  95.   # distribution media.
  96.   #
  97. ! #    @(#)Makefile    3.10    09:05:50  - Shadow password system
  98.   #
  99. ! #    @(#)Makefile    3.10    09:05:50    5/30/91
  100.   #
  101.   SHELL = /bin/sh
  102.   
  103. --- 8,16 ----
  104.   # and conspicuously displayed on all copies of object code or
  105.   # distribution media.
  106.   #
  107. ! #    @(#)Makefile    3.11    11:11:42  - Shadow password system
  108.   #
  109. ! #    @(#)Makefile    3.11    11:11:42    6/7/91
  110.   #
  111.   SHELL = /bin/sh
  112.   
  113. ***************
  114. *** 127,135 ****
  115.       utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
  116.       chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
  117.       newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
  118. !     spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c
  119.   
  120. ! FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c id.c
  121.   
  122.   FILES2 = passwd.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \
  123.       sulog.c getpass.c
  124. --- 127,137 ----
  125.       utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
  126.       chfn.c chsh.c chage.c rad64.c encrypt.c chpasswd.c shadowio.c pwio.c \
  127.       newusers.c groupio.c fields.c pwdbm.c grpack.c grdbm.c sppack.c \
  128. !     spdbm.c dpmain.c gshadow.c gsdbm.c gspack.c sgroupio.c useradd.c \
  129. !     userdel.c patchlevel.h usermod.c
  130.   
  131. ! FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c id.c \
  132. !     patchlevel.h
  133.   
  134.   FILES2 = passwd.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \
  135.       sulog.c getpass.c
  136. ***************
  137. *** 147,152 ****
  138. --- 149,156 ----
  139.   
  140.   FILES7 = groupio.c shadowio.c sgroupio.c
  141.   
  142. + FILES8 = useradd.c userdel.c usermod.c
  143.   MAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1
  144.   MAN_3 = shadow.3
  145.   MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
  146. ***************
  147. *** 155,161 ****
  148.   DOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8)
  149.   
  150.   BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
  151. !     mkpasswd chfn chsh chage chpasswd newusers dpasswd id
  152.   
  153.   all:    $(BINS) $(DOCS)
  154.   
  155. --- 159,166 ----
  156.   DOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8)
  157.   
  158.   BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
  159. !     mkpasswd chfn chsh chage chpasswd newusers dpasswd id useradd \
  160. !     userdel usermod
  161.   
  162.   all:    $(BINS) $(DOCS)
  163.   
  164. ***************
  165. *** 214,220 ****
  166.   
  167.   lint:    su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
  168.       faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
  169. !     chsh.lint chage.lint dpasswd.lint $(ALLSRCS:.c=.L)
  170.   
  171.   tags:    $(ALLSRCS)
  172.       $(TAGS) $(ALLSRCS)
  173. --- 219,226 ----
  174.   
  175.   lint:    su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
  176.       faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
  177. !     chsh.lint chage.lint dpasswd.lint id.lint useradd.lint userdel.lint \
  178. !     usermod.lint $(ALLSRCS:.c=.L)
  179.   
  180.   tags:    $(ALLSRCS)
  181.       $(TAGS) $(ALLSRCS)
  182. ***************
  183. *** 327,332 ****
  184. --- 333,356 ----
  185.   id.lint: id.c
  186.       $(LINT) $(LINTFLAGS) id.c > id.lint
  187.   
  188. + useradd: useradd.o libshadow.a
  189. +     $(CC) -o useradd $(LDFLAGS) useradd.o libshadow.a $(LIBS)
  190. + useradd.lint: useradd.c
  191. +     $(LINT) $(LINTFLAGS) useradd.c > useradd.lint
  192. + userdel: userdel.o libshadow.a
  193. +     $(CC) -o userdel $(LDFLAGS) userdel.o libshadow.a $(LIBS)
  194. + userdel.lint: userdel.c
  195. +     $(LINT) $(LINTFLAGS) userdel.c > userdel.lint
  196. + usermod: usermod.o libshadow.a
  197. +     $(CC) -o usermod $(LDFLAGS) usermod.o libshadow.a $(LIBS)
  198. + usermod.lint: usermod.c
  199. +     $(LINT) $(LINTFLAGS) usermod.c > usermod.lint
  200.   sulog.o: config.h
  201.   
  202.   susetup.c: setup.c
  203. ***************
  204. *** 395,400 ****
  205. --- 419,426 ----
  206.   id.o: pwd.h
  207.   newusers.o: config.h shadow.h pwd.h
  208.   dpmain.o: dialup.h
  209. + useradd.o: config.h shadow.h pwd.h
  210. + userdel.o: config.h shadow.h pwd.h
  211.   
  212.   clean:
  213.       -rm -f *.o a.out core npasswd nshadow *.pag *.dir
  214. ***************
  215. *** 410,416 ****
  216.       done
  217.   
  218.   shar:    login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5 login.sh.6 \
  219. !     login.sh.7 login.sh.8
  220.   
  221.   login.sh.1: $(FILES1) Makefile
  222.       shar -a $(FILES1) > login.sh.1
  223. --- 436,442 ----
  224.       done
  225.   
  226.   shar:    login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5 login.sh.6 \
  227. !     login.sh.7 login.sh.8 login.sh.9
  228.   
  229.   login.sh.1: $(FILES1) Makefile
  230.       shar -a $(FILES1) > login.sh.1
  231. ***************
  232. *** 433,437 ****
  233.   login.sh.7: $(FILES7) Makefile
  234.       shar -a $(FILES7) > login.sh.7
  235.   
  236. ! login.sh.8: $(DOCS) Makefile
  237. !     shar -a $(DOCS) > login.sh.8
  238. --- 459,466 ----
  239.   login.sh.7: $(FILES7) Makefile
  240.       shar -a $(FILES7) > login.sh.7
  241.   
  242. ! login.sh.8: $(FILES8) Makefile
  243. !     shar -a $(FILES8) > login.sh.8
  244. ! login.sh.9: $(DOCS) Makefile
  245. !     shar -a $(DOCS) > login.sh.9
  246. *** /dev/null    Fri Jun  7 11:02:59 1991
  247. --- useradd.c    Fri Jun  7 11:10:07 1991
  248. ***************
  249. *** 0 ****
  250. --- 1,1245 ----
  251. + /*
  252. +  * Copyright 1991, John F. Haugh II
  253. +  * All rights reserved.
  254. +  *
  255. +  * Permission is granted to copy and create derivative works for any
  256. +  * non-commercial purpose, provided this copyright notice is preserved
  257. +  * in all copies of source code, or included in human readable form
  258. +  * and conspicuously displayed on all copies of object code or
  259. +  * distribution media.
  260. +  */
  261. + #ifndef lint
  262. + static    char    sccsid[] = "@(#)useradd.c    3.1    11:08:18    6/7/91";
  263. + #endif
  264. + #include <sys/types.h>
  265. + #include <sys/stat.h>
  266. + #include <stdio.h>
  267. + #include <errno.h>
  268. + #include <pwd.h>
  269. + #include <grp.h>
  270. + #include <ctype.h>
  271. + #include <fcntl.h>
  272. + #include <time.h>
  273. + #ifdef    BSD
  274. + #include <strings.h>
  275. + #else
  276. + #include <string.h>
  277. + #endif
  278. + #include "config.h"
  279. + #include "shadow.h"
  280. + #ifdef    USE_SYSLOG
  281. + #include <syslog.h>
  282. + #ifndef    LOG_WARN
  283. + #define    LOG_WARN LOG_WARNING
  284. + #endif
  285. + #endif
  286. + gid_t    def_group;
  287. + char    def_home[BUFSIZ];
  288. + char    def_shell[BUFSIZ];
  289. + long    def_inactive;
  290. + long    def_expire;
  291. + char    def_file[] = "/etc/default/useradd";
  292. + #ifndef    NGROUPS_MAX
  293. + #define    NGROUPS_MAX    64
  294. + #endif
  295. + char    user_name[BUFSIZ];
  296. + uid_t    user_id;
  297. + gid_t    user_gid;
  298. + char    user_comment[BUFSIZ];
  299. + char    user_home[BUFSIZ];
  300. + char    user_shell[BUFSIZ];
  301. + long    user_expire;
  302. + int    user_ngroups;
  303. + gid_t    user_groups[NGROUPS_MAX];
  304. + char    *Prog;
  305. + int    uflg;    /* specify user ID for new account                            */
  306. + int    oflg;    /* permit non-unique user ID to be specified with -u          */
  307. + int    gflg;    /* primary group ID  for new account                          */
  308. + int    Gflg;    /* secondary group set for new account                        */
  309. + int    dflg;    /* home directory for new account                             */
  310. + int    bflg;    /* new default root of home directory                         */
  311. + int    sflg;    /* shell program for new account                              */
  312. + int    cflg;    /* comment (GECOS) field for new account                      */
  313. + int    mflg;    /* create user's home directory if it doesn't exist           */
  314. + int    kflg;    /* specify a directory to fill new user directory             */
  315. + int    fflg;    /* days until account with expired password is locked         */
  316. + int    eflg;    /* days after password changed before it becomes expired      */
  317. + int    Dflg;    /* set/show new user default values                           */
  318. + #if defined(DBM) || defined(NDBM)
  319. + extern    int    pw_dbm_mode;
  320. + #endif
  321. + #ifdef    NDBM
  322. + extern    int    sp_dbm_mode;
  323. + extern    int    gr_dbm_mode;
  324. + extern    int    sg_dbm_mode;
  325. + #endif
  326. + extern    FILE    *fopen();
  327. + extern    int    fclose();
  328. + extern    char    *malloc();
  329. + extern    char    *mktemp();
  330. + extern    struct    group    *getgrnam();
  331. + extern    struct    group    *getgrgid();
  332. + extern    struct    group    *gr_next();
  333. + extern    struct    group    *gr_locate();
  334. + extern    int    gr_lock();
  335. + extern    int    gr_unlock();
  336. + extern    int    gr_rewind();
  337. + extern    int    gr_open();
  338. + #ifdef    SHADOWGRP
  339. + extern    struct    sgrp    *sgr_next();
  340. + extern    int    sgr_lock();
  341. + extern    int    sgr_unlock();
  342. + extern    int    sgr_rewind();
  343. + extern    int    sgr_open();
  344. + #endif
  345. + extern    struct    passwd    *getpwnam();
  346. + extern    struct    passwd    *pw_next();
  347. + extern    int    pw_lock();
  348. + extern    int    pw_unlock();
  349. + extern    int    pw_rewind();
  350. + extern    int    pw_open();
  351. + extern    int    spw_lock();
  352. + extern    int    spw_unlock();
  353. + extern    int    spw_open();
  354. + #define    DAY    (24L*3600L)
  355. + #define    WEEK    (7*DAY)
  356. + #ifdef    ITI_AGING
  357. + #define    SCALE    (1)
  358. + #else
  359. + #define    SCALE    (DAY)
  360. + #endif
  361. + /*
  362. +  * days and juldays are used to compute the number of days in the
  363. +  * current month, and the cummulative number of days in the preceding
  364. +  * months.  they are declared so that january is 1, not 0.
  365. +  */
  366. + static    short    days[13] = { 0,
  367. +     31,    28,    31,    30,    31,    30,    /* JAN - JUN */
  368. +     31,    31,    30,    31,    30,    31 };    /* JUL - DEC */
  369. + static    short    juldays[13] = { 0,
  370. +     0,    31,    59,    90,    120,    151,    /* JAN - JUN */
  371. +     181,    212,    243,    273,    304,    334 };    /* JUL - DEC */
  372. + #ifdef    NEED_MKDIR
  373. + /*
  374. +  * mkdir - create a directory
  375. +  *
  376. +  *    mkdir is provided for systems which do not include the mkdir()
  377. +  *    system call.
  378. +  */
  379. + int
  380. + mkdir (dir, mode)
  381. + char    *dir;
  382. + int    mode;
  383. + {
  384. +     int    status;
  385. +     if (fork ()) {
  386. +         while (wait (&status) != -1)
  387. +             ;
  388. +         return status >> 8;
  389. +     }
  390. + #ifdef    USE_SYSLOG
  391. +     closelog ();
  392. + #endif
  393. +     close (2);
  394. +     open ("/dev/null", O_WRONLY);
  395. +     umask (0777 & ~ mode);
  396. +     execl ("/bin/mkdir", "mkdir", dir, 0);
  397. +     _exit (128);
  398. + }
  399. + #endif
  400. + #ifdef    NEED_RENAME
  401. + /*
  402. +  * rename - rename a file to another name
  403. +  *
  404. +  *    rename is provided for systems which do not include the rename()
  405. +  *    system call.
  406. +  */
  407. + int
  408. + rename (begin, end)
  409. + char    *begin;
  410. + char    *end;
  411. + {
  412. +     struct    stat    s1, s2;
  413. +     extern    int    errno;
  414. +     int    orig_err = errno;
  415. +     if (stat (begin, &s1))
  416. +         return -1;
  417. +     if (stat (end, &s2)) {
  418. +         errno = orig_err;
  419. +     } else {
  420. +         /*
  421. +          * See if this is a cross-device link.  We do this to
  422. +          * insure that the link below has a chance of working.
  423. +          */
  424. +         if (s1.st_dev != s2.st_dev) {
  425. +             errno = EXDEV;
  426. +             return -1;
  427. +         }
  428. +         /*
  429. +          * See if we can unlink the existing destination
  430. +          * file.  If the unlink works the directory is writable,
  431. +          * so there is no need here to figure that out.
  432. +          */
  433. +         if (unlink (end))
  434. +             return -1;
  435. +     }
  436. +     /*
  437. +      * Now just link the original name to the final name.  If there
  438. +      * was no file previously, this link will fail if the target
  439. +      * directory isn't writable.  The unlink will fail if the source
  440. +      * directory isn't writable, but life stinks ...
  441. +      */
  442. +     if (link (begin, end) || unlink (begin))
  443. +         return -1;
  444. +     return 0;
  445. + }
  446. + #endif
  447. + /*
  448. +  * strtoday - compute the number of days since 1970.
  449. +  *
  450. +  * the total number of days prior to the current date is
  451. +  * computed.  january 1, 1970 is used as the origin with
  452. +  * it having a day number of 0.
  453. +  */
  454. + long
  455. + strtoday (str)
  456. + char    *str;
  457. + {
  458. +     char    slop[2];
  459. +     int    month;
  460. +     int    day;
  461. +     int    year;
  462. +     long    total;
  463. +     /*
  464. +      * start by separating the month, day and year.  this is
  465. +      * a chauvanistic program - it only takes date input in
  466. +      * the standard USA format.
  467. +      */
  468. +     if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
  469. +         return -1;
  470. +     /*
  471. +      * the month, day of the month, and year are checked for
  472. +      * correctness and the year adjusted so it falls between
  473. +      * 1970 and 2069.
  474. +      */
  475. +     if (month < 1 || month > 12)
  476. +         return -1;
  477. +     if (day < 1)
  478. +         return -1;
  479. +     if ((month != 2 || (year % 4) != 0) && day > days[month])
  480. +         return -1;
  481. +     else if ((month == 2 && (year % 4) == 0) && day > 29)
  482. +         return -1;
  483. +     if (year < 0)
  484. +         return -1;
  485. +     else if (year < 69)
  486. +         year += 2000;
  487. +     else if (year < 99)
  488. +         year += 1900;
  489. +     if (year < 1970 || year > 2069)
  490. +         return -1;
  491. +     /*
  492. +      * the total number of days is the total number of days in all
  493. +      * the whole years, plus the number of leap days, plus the
  494. +      * number of days in the whole months preceding, plus the number
  495. +      * of days so far in the month.
  496. +      */
  497. +     total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
  498. +     total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
  499. +     total += (long) day - 1;
  500. +     return total;
  501. + }
  502. + /*
  503. +  * add_list - add a member to a list of group members
  504. +  *
  505. +  *    the array of member names is searched for the new member
  506. +  *    name, and if not present it is added to a freshly allocated
  507. +  *    list of users.
  508. +  */
  509. + char **
  510. + add_list (list, member)
  511. + char    **list;
  512. + char    *member;
  513. + {
  514. +     int    i;
  515. +     char    **tmp;
  516. +     /*
  517. +      * Scan the list for the new name.  Return the original list
  518. +      * pointer if it is present.
  519. +      */
  520. +     for (i = 0;list[i] != (char *) 0;i++)
  521. +         if (strcmp (list[i], member) == 0)
  522. +             return list;
  523. +     /*
  524. +      * Allocate a new list pointer large enough to hold all the
  525. +      * old entries, and the new entries as well.
  526. +      */
  527. +     if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
  528. +         return 0;
  529. +     /*
  530. +      * Copy the original list to the new list, then append the
  531. +      * new member and NULL terminate the result.  This new list
  532. +      * is returned to the invoker.
  533. +      */
  534. +     for (i = 0;list[i] != (char *) 0;i++)
  535. +         tmp[i] = list[i];
  536. +     tmp[i++] = strdup (member);
  537. +     tmp[i] = (char *) 0;
  538. +     return tmp;
  539. + }
  540. + /*
  541. +  * get_defaults - read the defaults file
  542. +  *
  543. +  *    get_defaults() reads the defaults file for this command.  It sets
  544. +  *    the various values from the file, or uses built-in default values
  545. +  *    if the file does not exist.
  546. +  */
  547. + void
  548. + get_defaults ()
  549. + {
  550. +     FILE    *fp;
  551. +     char    buf[BUFSIZ];
  552. +     char    *cp;
  553. +     struct    group    *grp;
  554. +     /*
  555. +      * Open the defaults file for reading.
  556. +      */
  557. +     if (! (fp = fopen (def_file, "r"))) {
  558. +         /*
  559. +          * No defaults file - set up the defaults that are given
  560. +          * in the documentation.
  561. +          */
  562. +         def_group = 1;
  563. +         strcpy (def_home, "/home");
  564. +         def_inactive = 0;
  565. +         def_expire = 0;
  566. +         return;
  567. +     }
  568. +     /*
  569. +      * Read the file a line at a time.  Only the lines that have
  570. +      * relevant values are used, everything else can be ignored.
  571. +      */
  572. +     while (fgets (buf, BUFSIZ, fp)) {
  573. +         if (cp = strrchr (buf, '\n'))
  574. +             *cp = '\0';
  575. +         /*
  576. +          * Primary GROUP identifier
  577. +          */
  578. +         if (strncmp ("GROUP=", buf, 6) == 0) {
  579. +             cp = buf + 6;
  580. +             if (isdigit (*cp))
  581. +                 def_group = atoi (cp);
  582. +             else if (grp = getgrnam (cp))
  583. +                 def_group = grp->gr_gid;
  584. +             else
  585. +                 fprintf (stderr, "%s: unknown group %s\n", cp);
  586. +         }
  587. +         
  588. +         /*
  589. +          * Default HOME filesystem
  590. +          */
  591. +          
  592. +         else if (strncmp ("HOME=", buf, 5) == 0) {
  593. +             strncpy (def_home, buf + 5, BUFSIZ);
  594. +         }
  595. +         /*
  596. +          * Default Login Shell command
  597. +          */
  598. +         else if (strncmp ("SHELL=", buf, 6) == 0) {
  599. +             strncpy (def_shell, buf + 6, BUFSIZ);
  600. +         }
  601. +         /*
  602. +          * Default Password Inactive value
  603. +          */
  604. +         else if (strncmp ("INACTIVE=", buf, 9) == 0) {
  605. +             def_inactive = atoi (buf + 9);
  606. +         }
  607. +         
  608. +         /*
  609. +          * Default Password Expiration value
  610. +          */
  611. +         else if (strncmp ("EXPIRE=", buf, 7) == 0) {
  612. +             def_expire = atoi (buf + 7);
  613. +         }
  614. +     }
  615. + }
  616. + /*
  617. +  * show_defaults - show the contents of the defaults file
  618. +  *
  619. +  *    show_defaults() displays the values that are used from the default
  620. +  *    file and the built-in values.
  621. +  */
  622. + void
  623. + show_defaults ()
  624. + {
  625. +     printf ("GROUP=%d\n", def_group);
  626. +     printf ("HOME=%s\n", def_home);
  627. +     printf ("INACTIVE=%d\n", def_inactive);
  628. +     printf ("EXPIRE=%d\n", def_expire);
  629. + }
  630. + /*
  631. +  * set_defaults - write new defaults file
  632. +  *
  633. +  *    set_defaults() re-writes the defaults file using the values that
  634. +  *    are currently set.  Duplicated lines are pruned, missing lines are
  635. +  *    added, and unrecognized lines are copied as is.
  636. +  */
  637. + int
  638. + set_defaults ()
  639. + {
  640. +     FILE    *ifp;
  641. +     FILE    *ofp;
  642. +     char    buf[BUFSIZ];
  643. +     static    char    new_file[] = "/etc/default/nuaddXXXXXX";
  644. +     char    *cp;
  645. +     int    out_group = 0;
  646. +     int    out_home = 0;
  647. +     int    out_inactive = 0;
  648. +     int    out_expire = 0;
  649. +     /*
  650. +      * Create a temporary file to copy the new output to.
  651. +      */
  652. +     mktemp (new_file);
  653. +     if (! (ofp = fopen (new_file, "w"))) {
  654. +         fprintf (stderr, "%s: cannot create new defaults file\n", Prog);
  655. +         return -1;
  656. +     }
  657. +     /*
  658. +      * Open the existing defaults file and copy the lines to the
  659. +      * temporary files, using any new values.  Each line is checked
  660. +      * to insure that it is not output more than once.
  661. +      */
  662. +     if (ifp = fopen (def_file, "r")) {
  663. +         while (fgets (buf, BUFSIZ, ifp)) {
  664. +             if (cp = strrchr (buf, '\n'))
  665. +                 *cp = '\0';
  666. +             if (strncmp ("GROUP=", buf, 6) == 0) {
  667. +                 if (! out_group)
  668. +                     fprintf (ofp, "GROUP=%d\n", def_group);
  669. +                 out_group++;
  670. +             } else if (strncmp ("HOME=", buf, 5) == 0) {
  671. +                 if (! out_home)
  672. +                     fprintf (ofp, "HOME=%s\n", def_home);
  673. +                 out_home++;
  674. +             } else if (strncmp ("INACTIVE=", buf, 9) == 0) {
  675. +                 if (! out_inactive)
  676. +                     fprintf (ofp, "INACTIVE=%d\n",
  677. +                         def_inactive);
  678. +                 out_inactive++;
  679. +             } else if (strncmp ("EXPIRE=", buf, 7) == 0) {
  680. +                 if (! out_expire)
  681. +                     fprintf (ofp, "EXPIRE=%d\n",
  682. +                         def_expire);
  683. +                 out_expire++;
  684. +             } else
  685. +                 fprintf (ofp, "%s\n", buf);
  686. +         }
  687. +         fclose ((FILE *) ifp);
  688. +     }
  689. +     /*
  690. +      * Check each line to insure that every line was output.  This
  691. +      * causes new values to be added to a file which did not previously
  692. +      * have an entry for that value.
  693. +      */
  694. +     if (! out_group)
  695. +         fprintf (ofp, "GROUP=%d\n", def_group);
  696. +     if (! out_home)
  697. +         fprintf (ofp, "HOME=%s\n", def_home);
  698. +     if (! out_inactive)
  699. +         fprintf (ofp, "INACTIVE=%d\n", def_inactive);
  700. +     if (! out_expire)
  701. +         fprintf (ofp, "EXPIRE=%d\n", def_expire);
  702. +     /*
  703. +      * Flush and close the file.  Check for errors to make certain
  704. +      * the new file is intact.
  705. +      */
  706. +     (void) fflush (ofp);
  707. +     if (ferror (ofp) || fclose ((FILE *) ofp)) {
  708. +         unlink (new_file);
  709. +         return -1;
  710. +     }
  711. +     /*
  712. +      * Rename the current default file to its backup name.
  713. +      */
  714. +     sprintf (buf, "%s-", def_file);
  715. +     if (rename (def_file, buf) && errno != ENOENT) {
  716. +         sprintf (buf, "%s: rename: %s", Prog, def_file);
  717. +         perror (buf);
  718. +         unlink (new_file);
  719. +         return -1;
  720. +     }
  721. +     /*
  722. +      * Rename the new default file to its correct name.
  723. +      */
  724. +     if (rename (new_file, def_file)) {
  725. +         sprintf (buf, "%s: rename: %s", Prog, new_file);
  726. +         perror (buf);
  727. +         return -1;
  728. +     }
  729. + #ifdef    USE_SYSLOG
  730. +     syslog (LOG_INFO, "defaults: group=%d, home=%s, inactive=%d, expire=%d",
  731. +         def_group, def_home, def_inactive, def_expire);
  732. + #endif
  733. +     return 0;
  734. + }
  735. + /*
  736. +  * get_groups - convert a list of group names to an array of group IDs
  737. +  *
  738. +  *    get_groups() takes a comma-separated list of group names and
  739. +  *    converts it to an array of group ID values.  Any unknown group
  740. +  *    names are reported as errors.
  741. +  */
  742. + int
  743. + get_groups (list)
  744. + char    *list;
  745. + {
  746. +     char    *cp;
  747. +     struct    group    *grp;
  748. +     int    errors = 0;
  749. +     /*
  750. +      * Initialize the list to be empty
  751. +      */
  752. +     user_ngroups = 0;
  753. +     if (! *list)
  754. +         return 0;
  755. +     /*
  756. +      * So long as there is some data to be converted, strip off
  757. +      * each name and look it up.  A mix of numerical and string
  758. +      * values for group identifiers is permitted.
  759. +      */
  760. +     do {
  761. +         /*
  762. +          * Strip off a single name from the list
  763. +          */
  764. +         if (cp = strchr (list, ','))
  765. +             *cp++ = '\0';
  766. +         /*
  767. +          * Names starting with digits are treated as numerical
  768. +          * GID values, otherwise the string is looked up as is.
  769. +          */
  770. +         if (isdigit (*list))
  771. +             grp = getgrgid (atoi (list));
  772. +         else
  773. +             grp = getgrnam (list);
  774. +         /*
  775. +          * There must be a match, either by GID value or by
  776. +          * string name.
  777. +          */
  778. +         if (! grp) {
  779. +             fprintf (stderr, "%s: unknown group %s\n", Prog, list);
  780. +             errors++;
  781. +         }
  782. +         /*
  783. +          * Add the GID value from the group file to the user's
  784. +          * list of groups.
  785. +          */
  786. +         user_groups[user_ngroups++] = grp->gr_gid;
  787. +         list = cp;
  788. +     } while (list);
  789. +     /*
  790. +      * Any errors in finding group names are fatal
  791. +      */
  792. +     if (errors)
  793. +         return -1;
  794. +     return 0;
  795. + }
  796. + /*
  797. +  * usage - display usage message and exit
  798. +  */
  799. + usage ()
  800. + {
  801. +     fprintf (stderr,
  802. +         "usage:\tuseradd [-u uid [-o]] [-g group] [-G group,...] \n");
  803. +     fprintf (stderr,
  804. +         "\t\t[-d home] [-s shell] [-c comment] [-m [-k template]]\n");
  805. +     fprintf (stderr,
  806. +         "\t\t[-f inactive] [-e expire] name\n");
  807. +     fprintf (stderr,
  808. +         "\tuseradd -D [-g group] [-b base] [-f inactive] [-e expire]\n");
  809. +     exit (1);
  810. + }
  811. + /*
  812. +  * new_pwent - initialize the values in a password file entry
  813. +  *
  814. +  *    new_pwent() takes all of the values that have been entered and
  815. +  *    fills in a (struct passwd) with them.
  816. +  */
  817. + void
  818. + new_pwent (pwent)
  819. + struct    passwd    *pwent;
  820. + {
  821. +     memset (pwent, 0, sizeof *pwent);
  822. +     pwent->pw_name = user_name;
  823. +     pwent->pw_passwd = "*";
  824. +     pwent->pw_age = "";
  825. +     pwent->pw_uid = user_id;
  826. +     pwent->pw_gid = user_gid;
  827. +     pwent->pw_gecos = user_comment;
  828. +     pwent->pw_comment = "";
  829. +     pwent->pw_dir = user_home;
  830. +     pwent->pw_shell = user_shell;
  831. + }
  832. + /*
  833. +  * new_spent - initialize the values in a shadow password file entry
  834. +  *
  835. +  *    new_spent() takes all of the values that have been entered and
  836. +  *    fills in a (struct spwd) with them.
  837. +  */
  838. + void
  839. + new_spent (spent)
  840. + struct    spwd    *spent;
  841. + {
  842. +     memset (spent, 0, sizeof *spent);
  843. +     spent->sp_namp = user_name;
  844. +     spent->sp_pwdp = "!";
  845. +     spent->sp_lstchg = 0;
  846. +     spent->sp_min = 0;
  847. +     spent->sp_max = def_expire;
  848. +     spent->sp_warn = 0;
  849. +     spent->sp_inact = def_inactive;
  850. +     spent->sp_expire = user_expire;
  851. + }
  852. + /*
  853. +  * grp_update - add user to secondary group set
  854. +  *
  855. +  *    grp_update() takes the secondary group set given in user_groups
  856. +  *    and adds the user to each group given by that set.
  857. +  */
  858. + void
  859. + grp_update ()
  860. + {
  861. +     int    i;
  862. +     struct    group    *grp;
  863. +     struct    sgrp    *sgrp;
  864. +     /*
  865. +      * Lock and open the group file.  This will load all of the group
  866. +      * entries.
  867. +      */
  868. +     if (! gr_lock ()) {
  869. +         fprintf (stderr, "%s: error locking group file\n", Prog);
  870. +         exit (1);
  871. +     }
  872. +     if (! gr_open (O_RDWR)) {
  873. +         fprintf (stderr, "%s: error opening group file\n", Prog);
  874. +         exit (1);
  875. +     }
  876. + #ifdef    SHADOWGRP
  877. +     if (! sgr_lock ()) {
  878. +         fprintf (stderr, "%s: error locking shadow group file\n", Prog);
  879. +         exit (1);
  880. +     }
  881. +     if (! sgr_open (O_RDWR)) {
  882. +         fprintf (stderr, "%s: error opening shadow group file\n", Prog);
  883. +         exit (1);
  884. +     }
  885. + #endif
  886. +     /*
  887. +      * Scan through the entire group file looking for the groups that
  888. +      * the user is a member of.
  889. +      */
  890. +     for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  891. +         /*
  892. +          * See if the user specified this group as one of their
  893. +          * concurrent groups.
  894. +          */
  895. +         for (i = 0;i < user_ngroups;i++)
  896. +             if (grp->gr_gid == user_groups[i])
  897. +                 break;
  898. +         if (i == user_ngroups)
  899. +             continue;
  900. +         /* 
  901. +          * Add the username to the list of group members and
  902. +          * update the group entry to reflect the change.
  903. +          */
  904. +         grp->gr_mem = add_list (grp->gr_mem, user_name);
  905. +         if (! gr_update (grp)) {
  906. +             fprintf (stderr, "%s: error adding new group entry\n",
  907. +                 Prog);
  908. +             exit (1);
  909. +         }
  910. + #ifdef    NDBM
  911. +         /*
  912. +          * Update the DBM group file with the new entry as well.
  913. +          */
  914. +         if (! gr_dbm_update (grp)) {
  915. +             fprintf (stderr, "%s: cannot add new dbm group entry\n",
  916. +                 Prog);
  917. +             exit (1);
  918. +         }
  919. + #endif
  920. + #ifdef    USE_SYSLOG
  921. +         syslog (LOG_INFO, "add `%s' to group `%s'\n",
  922. +             user_name, grp->gr_name);
  923. + #endif
  924. +     }
  925. + #ifdef    SHADOWGRP
  926. +     /*
  927. +      * Scan through the entire shadow group file looking for the groups
  928. +      * that the user is a member of.  The administrative list isn't
  929. +      * modified.
  930. +      */
  931. +     for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  932. +         /*
  933. +          * See if the user specified this group as one of their
  934. +          * concurrent groups.
  935. +          */
  936. +         for (i = 0;i < user_ngroups;i++) {
  937. +             if (! (grp = gr_locate (sgrp->sg_name)))
  938. +                 continue;
  939. +             if (grp->gr_gid == user_groups[i])
  940. +                 break;
  941. +         }
  942. +         if (i == user_ngroups)
  943. +             continue;
  944. +         /* 
  945. +          * Add the username to the list of group members and
  946. +          * update the group entry to reflect the change.
  947. +          */
  948. +         sgrp->sg_mem = add_list (sgrp->sg_mem, user_name);
  949. +         if (! sgr_update (sgrp)) {
  950. +             fprintf (stderr, "%s: error adding new group entry\n",
  951. +                 Prog);
  952. +             exit (1);
  953. +         }
  954. + #ifdef    NDBM
  955. +         /*
  956. +          * Update the DBM group file with the new entry as well.
  957. +          */
  958. +         if (! sgr_dbm_update (sgrp)) {
  959. +             fprintf (stderr, "%s: cannot add new dbm group entry\n",
  960. +                 Prog);
  961. +             exit (1);
  962. +         }
  963. + #endif
  964. + #ifdef    USE_SYSLOG
  965. +         syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
  966. +             user_name, sgrp->sg_name);
  967. + #endif
  968. +     }
  969. + #endif
  970. + }
  971. + /*
  972. +  * find_new_uid - find the next available UID
  973. +  *
  974. +  *    find_new_uid() locates the next highest unused UID in the password
  975. +  *    file, or checks the given user ID against the existing ones for
  976. +  *    uniqueness.
  977. +  */
  978. + int
  979. + find_new_uid ()
  980. + {
  981. +     struct    passwd    *pwd;
  982. +     /*
  983. +      * Start with some UID value if the user didn't provide us with
  984. +      * one already.
  985. +      */
  986. +     if (! uflg)
  987. +         user_id = 100;
  988. +     /*
  989. +      * Search the entire password file, either looking for this
  990. +      * UID (if the user specified one with -u) or looking for the
  991. +      * largest unused value.
  992. +      */
  993. +     for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
  994. +         if (strcmp (user_name, pwd->pw_name) == 0) {
  995. +             fprintf (stderr, "%s: name %s is not unique\n",
  996. +                 Prog, user_name);
  997. +             exit (1);
  998. +         }
  999. +         if (uflg && user_id == pwd->pw_uid) {
  1000. +             fprintf (stderr, "%s: uid %d is not unique\n",
  1001. +                 Prog, user_id);
  1002. +             exit (1);
  1003. +         }
  1004. +         if (! uflg && pwd->pw_uid >= user_id)
  1005. +             user_id = pwd->pw_uid + 1;
  1006. +     }
  1007. + }
  1008. + /*
  1009. +  * process_flags - perform command line argument setting
  1010. +  *
  1011. +  *    process_flags() interprets the command line arguments and sets
  1012. +  *    the values that the user will be created with accordingly.  The
  1013. +  *    values are checked for sanity.
  1014. +  */
  1015. + void
  1016. + process_flags (argc, argv)
  1017. + int    argc;
  1018. + char    **argv;
  1019. + {
  1020. +     extern    int    optind;
  1021. +     extern    char    *optarg;
  1022. +     struct    group    *grp;
  1023. +     int    anyflag = 0;
  1024. +     int    arg;
  1025. +     while ((arg = getopt (argc, argv, "Du:og:G:d:s:c:mk:f:e:b:")) != EOF) {
  1026. +         switch (arg) {
  1027. +             case 'b':
  1028. +                 bflg++;
  1029. +                 if (! Dflg)
  1030. +                     usage ();
  1031. +                 strncpy (def_home, optarg, BUFSIZ);
  1032. +                 break;
  1033. +             case 'c':
  1034. +                 cflg++;
  1035. +                 strncpy (user_comment, optarg, BUFSIZ);
  1036. +                 break;
  1037. +             case 'd':
  1038. +                 dflg++;
  1039. +                 strncpy (user_home, optarg, BUFSIZ);
  1040. +                 break;
  1041. +             case 'D':
  1042. +                 if (anyflag)
  1043. +                     usage ();
  1044. +                 Dflg++;
  1045. +                 break;
  1046. +             case 'e':
  1047. +                 eflg++;
  1048. +                 if (Dflg)
  1049. +                     def_expire = atoi (optarg);
  1050. +                 else {
  1051. +                     user_expire = strtoday (optarg);
  1052. + #ifdef    ITI_AGING
  1053. +                     user_expire *= DAY;
  1054. + #endif
  1055. +                 }
  1056. +                 break;
  1057. +             case 'f':
  1058. +                 fflg++;
  1059. +                 def_inactive = atoi (optarg);
  1060. +                 break;
  1061. +             case 'g':
  1062. +                 gflg++;
  1063. +                 if (isdigit (optarg[0]))
  1064. +                     grp = getgrgid (atoi (optarg));
  1065. +                 else
  1066. +                     grp = getgrnam (optarg);
  1067. +                 if (! grp) {
  1068. +                     fprintf (stderr,
  1069. +                         "%s: unknown group %s\n",
  1070. +                         optarg);
  1071. +                     exit (1);
  1072. +                 }
  1073. +                 def_group = grp->gr_gid;
  1074. +                 break;
  1075. +             case 'G':
  1076. +                 Gflg++;
  1077. +                 if (get_groups (optarg))
  1078. +                     exit (1);
  1079. +                 break;
  1080. +             case 'k':
  1081. +                 if (! mflg)
  1082. +                     usage ();
  1083. +                 kflg++;
  1084. +                 break;
  1085. +             case 'm':
  1086. +                 mflg++;
  1087. +                 break;
  1088. +             case 'o':
  1089. +                 if (! uflg)
  1090. +                     usage ();
  1091. +                 oflg++;
  1092. +                 break;
  1093. +             case 's':
  1094. +                 sflg++;
  1095. +                 strncpy (user_shell, optarg, BUFSIZ);
  1096. +                 break;
  1097. +             case 'u':
  1098. +                 uflg++;
  1099. +                 user_id = atoi (optarg);
  1100. +                 break;
  1101. +             default:
  1102. +                 usage ();
  1103. +         }
  1104. +         anyflag++;
  1105. +     }
  1106. +     if (! Dflg && optind == argc - 1)
  1107. +         strcpy (user_name, argv[argc - 1]);
  1108. +     if (! dflg)
  1109. +         sprintf (user_home, "%s/%s", def_home, user_name);
  1110. +     if (! gflg)
  1111. +         user_gid = def_group;
  1112. +     if (Dflg) {
  1113. +         if (optind != argc)
  1114. +             usage ();
  1115. +         if (uflg || oflg || Gflg || dflg ||
  1116. +                 sflg || cflg || mflg || kflg)
  1117. +             usage ();
  1118. +     } else {
  1119. +         if (optind != argc - 1)
  1120. +             usage ();
  1121. +     }
  1122. + }
  1123. + /*
  1124. +  * close_files - close all of the files that were opened
  1125. +  *
  1126. +  *    close_files() closes all of the files that were opened for this
  1127. +  *    new user.  This causes any modified entries to be written out.
  1128. +  */
  1129. + close_files ()
  1130. + {
  1131. +     if (! pw_close ()) {
  1132. +         fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  1133. +         exit (1);
  1134. +     }
  1135. +     if (! spw_close ()) {
  1136. +         fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  1137. +             Prog);
  1138. +         exit (1);
  1139. +     }
  1140. +     if (user_ngroups > 0) {
  1141. +         if (! gr_close ()) {
  1142. +             fprintf (stderr, "%s: cannot rewrite group file\n",
  1143. +                 Prog);
  1144. +             exit (1);
  1145. +         }
  1146. +         (void) gr_unlock ();
  1147. + #ifdef    SHADOWGRP
  1148. +         if (! sgr_close ()) {
  1149. +             fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  1150. +                 Prog);
  1151. +             exit (1);
  1152. +         }
  1153. + #endif
  1154. +     }
  1155. +     (void) pw_unlock ();
  1156. + }
  1157. + /*
  1158. +  * open_files - lock and open the password files
  1159. +  *
  1160. +  *    open_files() opens the two password files.
  1161. +  */
  1162. + open_files ()
  1163. + {
  1164. +     if (! pw_lock ()) {
  1165. +         fprintf (stderr, "%s: unable to lock password file\n", Prog);
  1166. +         exit (1);
  1167. +     }
  1168. +     if (! pw_open (O_RDWR)) {
  1169. +         fprintf (stderr, "%s: unable to open password file\n", Prog);
  1170. +         exit (1);
  1171. +     }
  1172. +     if (! spw_lock ()) {
  1173. +         fprintf ("%s: cannot lock shadow password file\n", Prog);
  1174. +         exit (1);
  1175. +     }
  1176. +     if (! spw_open (O_RDWR)) {
  1177. +         fprintf ("%s: cannot open shadow password file\n", Prog);
  1178. +         exit (1);
  1179. +     }
  1180. + }
  1181. + /*
  1182. +  * usr_update - create the user entries
  1183. +  *
  1184. +  *    usr_update() creates the password file entries for this user
  1185. +  *    and will update the group entries if required.
  1186. +  */
  1187. + usr_update ()
  1188. + {
  1189. +     struct    passwd    pwent;
  1190. +     struct    spwd    spent;
  1191. +     if (! oflg)
  1192. +         find_new_uid ();
  1193. +     new_pwent (&pwent);
  1194. +     if (! pw_update (&pwent)) {
  1195. +         fprintf (stderr, "%s: error adding new password entry\n", Prog);
  1196. +         exit (1);
  1197. +     }
  1198. +     new_spent (&spent);
  1199. +     if (! spw_update (&spent)) {
  1200. +         fprintf (stderr, "%s: error adding new shadow password entry\n",
  1201. +             Prog);
  1202. +         exit (1);
  1203. +     }
  1204. + #if defined(DBM) || defined(NDBM)
  1205. +     if (access ("/etc/passwd.pag", 0) == 0 && ! pw_dbm_update (&pwent)) {
  1206. +         fprintf (stderr, "%s: error updating password dbm entry\n",
  1207. +             Prog);
  1208. +         exit (1);
  1209. +     }
  1210. + #endif
  1211. + #ifdef    NDBM
  1212. +     if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (&spent)) {
  1213. +         fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
  1214. +             Prog);
  1215. +         exit (1);
  1216. +     }
  1217. + #endif
  1218. + #ifdef    USE_SYSLOG
  1219. +     syslog (LOG_INFO,
  1220. +         "new user: name=%s, uid=%d, gid=%d, home=%s, shell=%s\n",
  1221. +         user_name, user_id, user_gid, user_home, user_shell);
  1222. + #endif
  1223. +     if (user_ngroups > 0)
  1224. +         grp_update ();
  1225. + }
  1226. + /*
  1227. +  * create_home - create the user's home directory
  1228. +  *
  1229. +  *    create_home() creates the user's home directory if it does not
  1230. +  *    already exist.  It will be created mode 755 owned by the user
  1231. +  *    with the user's default group.
  1232. +  */
  1233. + create_home ()
  1234. + {
  1235. +     if (access (user_home, 0)) {
  1236. +         if (mkdir (user_home, 0755)) {
  1237. +             fprintf (stderr, "%s: cannot create directory %s\n",
  1238. +                 Prog, user_home);
  1239. +             exit (1);
  1240. +         }
  1241. +         chown (user_home, user_id, user_gid);
  1242. +         chmod (user_home, 0755);
  1243. +     }
  1244. + }
  1245. + /*
  1246. +  * main - useradd command
  1247. +  */
  1248. + main (argc, argv)
  1249. + int    argc;
  1250. + char    **argv;
  1251. + {
  1252. +     /*
  1253. +      * Get my name so that I can use it to report errors.
  1254. +      */
  1255. +     if (Prog = strrchr (argv[0], '/'))
  1256. +         Prog++;
  1257. +     else
  1258. +         Prog = argv[0];
  1259. + #ifdef    USE_SYSLOG
  1260. +     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1261. + #endif
  1262. +     /*
  1263. +      * The open routines for the DBM files don't use read-write
  1264. +      * as the mode, so we have to clue them in.
  1265. +      */
  1266. + #if defined(DBM) || defined(NDBM)
  1267. +     pw_dbm_mode = O_RDWR;
  1268. + #endif
  1269. + #ifdef    NDBM
  1270. +     sp_dbm_mode = O_RDWR;
  1271. +     gr_dbm_mode = O_RDWR;
  1272. + #ifdef    SHADOWGRP
  1273. +     sg_dbm_mode = O_RDWR;
  1274. + #endif
  1275. + #endif
  1276. +     get_defaults ();
  1277. +     process_flags (argc, argv);
  1278. +     /*
  1279. +      * See if we are messing with the defaults file, or creating
  1280. +      * a new user.
  1281. +      */
  1282. +     if (Dflg) {
  1283. +         if (gflg || bflg || fflg || eflg)
  1284. +             exit (set_defaults () ? 1:0);
  1285. +         show_defaults ();
  1286. +         exit (0);
  1287. +     }
  1288. +     /*
  1289. +      * Start with a quick check to see if the user exists.
  1290. +      */
  1291. +     if (getpwnam (user_name)) {
  1292. +         fprintf (stderr, "%s: user %s exists\n", Prog, user_name);
  1293. +         exit (1);
  1294. +     }
  1295. +     /*
  1296. +      * Do the hard stuff - open the files, create the user entries,
  1297. +      * create the home directory, then close and update the files.
  1298. +      */
  1299. +     open_files ();
  1300. +     usr_update ();
  1301. +     if (mflg)
  1302. +         create_home ();
  1303. +     close_files ();
  1304. +     exit (0);
  1305. +     /*NOTREACHED*/
  1306. + }
  1307. *** /dev/null    Fri Jun  7 11:02:59 1991
  1308. --- userdel.c    Fri Jun  7 11:10:08 1991
  1309. ***************
  1310. *** 0 ****
  1311. --- 1,499 ----
  1312. + /*
  1313. +  * Copyright 1991, John F. Haugh II
  1314. +  * All rights reserved.
  1315. +  *
  1316. +  * Permission is granted to copy and create derivative works for any
  1317. +  * non-commercial purpose, provided this copyright notice is preserved
  1318. +  * in all copies of source code, or included in human readable form
  1319. +  * and conspicuously displayed on all copies of object code or
  1320. +  * distribution media.
  1321. +  */
  1322. + #ifndef lint
  1323. + static    char    sccsid[] = "@(#)userdel.c    3.1    11:08:47    6/7/91";
  1324. + #endif
  1325. + #include <sys/types.h>
  1326. + #include <sys/stat.h>
  1327. + #include <stdio.h>
  1328. + #include <errno.h>
  1329. + #include <pwd.h>
  1330. + #include <grp.h>
  1331. + #include <ctype.h>
  1332. + #include <fcntl.h>
  1333. + #include <time.h>
  1334. + #ifdef    BSD
  1335. + #include <strings.h>
  1336. + #else
  1337. + #include <string.h>
  1338. + #endif
  1339. + #include "config.h"
  1340. + #include "shadow.h"
  1341. + #ifdef    USE_SYSLOG
  1342. + #include <syslog.h>
  1343. + #ifndef    LOG_WARN
  1344. + #define    LOG_WARN LOG_WARNING
  1345. + #endif
  1346. + #endif
  1347. + gid_t    default_group;
  1348. + char    default_home[BUFSIZ];
  1349. + char    default_shell[BUFSIZ];
  1350. + long    default_inactive;
  1351. + long    default_expire;
  1352. + char    default_file[] = "/etc/default/useradd";
  1353. + #ifndef    NGROUPS_MAX
  1354. + #define    NGROUPS_MAX    64
  1355. + #endif
  1356. + char    user_name[BUFSIZ];
  1357. + uid_t    user_id;
  1358. + gid_t    user_group;
  1359. + char    user_comment[BUFSIZ];
  1360. + char    user_home[BUFSIZ];
  1361. + char    user_shell[BUFSIZ];
  1362. + int    user_ngroups;
  1363. + int    user_expire;
  1364. + gid_t    user_groups[NGROUPS_MAX];
  1365. + char    *Prog;
  1366. + int    rflg;
  1367. + #if defined(DBM) || defined(NDBM)
  1368. + extern    int    pw_dbm_mode;
  1369. + #endif
  1370. + #ifdef    NDBM
  1371. + extern    int    sp_dbm_mode;
  1372. + extern    int    gr_dbm_mode;
  1373. + #ifdef    SHADOWGRP
  1374. + extern    int    sg_dbm_mode;
  1375. + #endif
  1376. + #endif
  1377. + extern    struct    group    *getgrnam();
  1378. + extern    struct    group    *getgrgid();
  1379. + extern    struct    group    *gr_next();
  1380. + extern    struct    passwd    *getpwnam();
  1381. + extern    struct    passwd    *pw_next();
  1382. + #ifdef    SHADOWGRP
  1383. + extern    int    sgr_lock();
  1384. + extern    int    sgr_unlock();
  1385. + extern    int    sgr_open();
  1386. + extern    int    sgr_close();
  1387. + extern    struct    sgrp    *sgr_next();
  1388. + #endif
  1389. + extern    char    *malloc();
  1390. + #ifdef    NEED_RMDIR
  1391. + /*
  1392. +  * rmdir - remove a directory
  1393. +  *
  1394. +  *    rmdir is provided for systems which do not include the rmdir()
  1395. +  *    system call.
  1396. +  */
  1397. + int
  1398. + rmdir (dir)
  1399. + char    *dir;
  1400. + {
  1401. +     int    status;
  1402. +     if (fork ()) {
  1403. +         while (wait (&status) != -1)
  1404. +             ;
  1405. +         return status >> 8;
  1406. +     }
  1407. +     close (2);
  1408. +     open ("/dev/null", O_WRONLY);
  1409. +     execl ("/bin/rmdir", "rmdir", dir, 0);
  1410. +     _exit (128);
  1411. + }
  1412. + #endif
  1413. + /*
  1414. +  * del_list - delete a member from a list of group members
  1415. +  *
  1416. +  *    the array of member names is searched for the old member
  1417. +  *    name, and if present it is deleted from a freshly allocated
  1418. +  *    list of users.
  1419. +  */
  1420. + char **
  1421. + del_list (list, member)
  1422. + char    **list;
  1423. + char    *member;
  1424. + {
  1425. +     int    i, j;
  1426. +     char    **tmp;
  1427. +     /*
  1428. +      * Scan the list for the new name.  Return the original list
  1429. +      * pointer if it is present.
  1430. +      */
  1431. +     for (i = j = 0;list[i] != (char *) 0;i++)
  1432. +         if (strcmp (list[i], member))
  1433. +             j++;
  1434. +     if (j == i)
  1435. +         return list;
  1436. +     /*
  1437. +      * Allocate a new list pointer large enough to hold all the
  1438. +      * old entries, and the new entries as well.
  1439. +      */
  1440. +     if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
  1441. +         return 0;
  1442. +     /*
  1443. +      * Copy the original list to the new list, then append the
  1444. +      * new member and NULL terminate the result.  This new list
  1445. +      * is returned to the invoker.
  1446. +      */
  1447. +     for (i = j = 0;list[i] != (char *) 0;i++)
  1448. +         if (strcmp (list[i], member))
  1449. +             tmp[j++] = list[i];
  1450. +     tmp[j] = (char *) 0;
  1451. +     return tmp;
  1452. + }
  1453. + /*
  1454. +  * usage - display usage message and exit
  1455. +  */
  1456. + usage ()
  1457. + {
  1458. +     fprintf (stderr, "usage: userdel [-r] name\n");
  1459. +     exit (1);
  1460. + }
  1461. + /*
  1462. +  * update_groups - delete user from secondary group set
  1463. +  *
  1464. +  *    update_groups() takes the user name that was given and searches
  1465. +  *    the group files for membership in any group.
  1466. +  */
  1467. + void
  1468. + update_groups ()
  1469. + {
  1470. +     int    i;
  1471. +     struct    group    *grp;
  1472. + #ifdef    SHADOWGRP
  1473. +     struct    sgrp    *sgrp;
  1474. + #endif
  1475. +     /*
  1476. +      * Scan through the entire group file looking for the groups that
  1477. +      * the user is a member of.
  1478. +      */
  1479. +     for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  1480. +         /*
  1481. +          * See if the user specified this group as one of their
  1482. +          * concurrent groups.
  1483. +          */
  1484. +         for (i = 0;grp->gr_mem[i];i++)
  1485. +             if (strcmp (grp->gr_mem[i], user_name) == 0)
  1486. +                 break;
  1487. +         if (grp->gr_mem[i] == (char *) 0)
  1488. +             continue;
  1489. +         /* 
  1490. +          * Delete the username from the list of group members and
  1491. +          * update the group entry to reflect the change.
  1492. +          */
  1493. +         grp->gr_mem = del_list (grp->gr_mem, user_name);
  1494. +         if (! gr_update (grp)) {
  1495. +             fprintf (stderr, "%s: error updating group entry\n",
  1496. +                 Prog);
  1497. +             exit (1);
  1498. +         }
  1499. + #ifdef    NDBM
  1500. +         /*
  1501. +          * Update the DBM group file with the new entry as well.
  1502. +          */
  1503. +         if (! gr_dbm_update (grp)) {
  1504. +             fprintf (stderr, "%s: cannot update dbm group entry\n",
  1505. +                 Prog);
  1506. +             exit (1);
  1507. +         }
  1508. + #endif
  1509. +     }
  1510. + #ifdef    SHADOWGRP
  1511. +     /*
  1512. +      * Scan through the entire shadow group file looking for the groups
  1513. +      * that the user is a member of.  Both the administrative list and
  1514. +      * the ordinary membership list is checked.
  1515. +      */
  1516. +     for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  1517. +         int    group_changed = 0;
  1518. +         /*
  1519. +          * See if the user specified this group as one of their
  1520. +          * concurrent groups.
  1521. +          */
  1522. +         for (i = 0;sgrp->sg_mem[i];i++)
  1523. +             if (strcmp (sgrp->sg_mem[i], user_name) == 0)
  1524. +                 break;
  1525. +         if (sgrp->sg_mem[i]) {
  1526. +             sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
  1527. +             group_changed = 1;
  1528. +         }
  1529. +         for (i = 0;sgrp->sg_adm[i];i++)
  1530. +             if (strcmp (sgrp->sg_adm[i], user_name) == 0)
  1531. +                 break;
  1532. +         if (sgrp->sg_adm[i]) {
  1533. +             sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
  1534. +             group_changed = 1;
  1535. +         }
  1536. +         if (! group_changed)
  1537. +             continue;
  1538. +         if (! sgr_update (sgrp)) {
  1539. +             fprintf (stderr, "%s: error updating group entry\n",
  1540. +                 Prog);
  1541. +             exit (1);
  1542. +         }
  1543. + #ifdef    NDBM
  1544. +         /*
  1545. +          * Update the DBM group file with the new entry as well.
  1546. +          */
  1547. +         if (! sgr_dbm_update (sgrp)) {
  1548. +             fprintf (stderr, "%s: cannot update dbm group entry\n",
  1549. +                 Prog);
  1550. +             exit (1);
  1551. +         }
  1552. + #endif
  1553. +     }
  1554. + #endif
  1555. + }
  1556. + /*
  1557. +  * close_files - close all of the files that were opened
  1558. +  *
  1559. +  *    close_files() closes all of the files that were opened for this
  1560. +  *    new user.  This causes any modified entries to be written out.
  1561. +  */
  1562. + close_files ()
  1563. + {
  1564. +     if (! pw_close ()) {
  1565. +         fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  1566. +         exit (1);
  1567. +     }
  1568. +     if (! spw_close ()) {
  1569. +         fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  1570. +             Prog);
  1571. +         exit (1);
  1572. +     }
  1573. +     if (! gr_close ()) {
  1574. +         fprintf (stderr, "%s: cannot rewrite group file\n",
  1575. +             Prog);
  1576. +         exit (1);
  1577. +     }
  1578. +     (void) gr_unlock ();
  1579. + #ifdef    SHADOWGRP
  1580. +     if (! sgr_close ()) {
  1581. +         fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  1582. +             Prog);
  1583. +         exit (1);
  1584. +     }
  1585. +     (void) sgr_unlock ();
  1586. + #endif
  1587. +     (void) pw_unlock ();
  1588. + }
  1589. + /*
  1590. +  * open_files - lock and open the password files
  1591. +  *
  1592. +  *    open_files() opens the two password files.
  1593. +  */
  1594. + open_files ()
  1595. + {
  1596. +     if (! pw_lock ()) {
  1597. +         fprintf (stderr, "%s: unable to lock password file\n", Prog);
  1598. +         exit (1);
  1599. +     }
  1600. +     if (! pw_open (O_RDWR)) {
  1601. +         fprintf (stderr, "%s: unable to open password file\n", Prog);
  1602. +         exit (1);
  1603. +     }
  1604. +     if (! spw_lock ()) {
  1605. +         fprintf ("%s: cannot lock shadow password file\n", Prog);
  1606. +         exit (1);
  1607. +     }
  1608. +     if (! spw_open (O_RDWR)) {
  1609. +         fprintf ("%s: cannot open shadow password file\n", Prog);
  1610. +         exit (1);
  1611. +     }
  1612. +     if (! gr_lock ()) {
  1613. +         fprintf (stderr, "%s: unable to lock group file\n", Prog);
  1614. +         exit (1);
  1615. +     }
  1616. +     if (! gr_open (O_RDWR)) {
  1617. +         fprintf (stderr, "%s: cannot open group file\n", Prog);
  1618. +         exit (1);
  1619. +     }
  1620. + #ifdef    SHADOWGRP
  1621. +     if (! sgr_lock ()) {
  1622. +         fprintf (stderr, "%s: unable to lock shadow group file\n", Prog);
  1623. +         exit (1);
  1624. +     }
  1625. +     if (! sgr_open (O_RDWR)) {
  1626. +         fprintf (stderr, "%s: cannot open shadow group file\n", Prog);
  1627. +         exit (1);
  1628. +     }
  1629. + #endif
  1630. + }
  1631. + /*
  1632. +  * update_user - delete the user entries
  1633. +  *
  1634. +  *    update_user() deletes the password file entries for this user
  1635. +  *    and will update the group entries as required.
  1636. +  */
  1637. + update_user ()
  1638. + {
  1639. +     struct    passwd    *pwd;
  1640. +     if (! pw_remove (user_name))
  1641. +         fprintf (stderr, "%s: error deleting password entry\n", Prog);
  1642. +     if (! spw_remove (user_name))
  1643. +         fprintf (stderr, "%s: error deleting shadow password entry\n",
  1644. +             Prog);
  1645. + #if defined(DBM) || defined(NDBM)
  1646. +     if (access ("/etc/passwd.pag", 0) == 0) {
  1647. +         if ((pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd))
  1648. +             fprintf (stderr,
  1649. +                 "%s: error deleting password dbm entry\n",
  1650. +                 Prog);
  1651. +     }
  1652. +     /*
  1653. +      * If the user's UID is a duplicate the duplicated entry needs
  1654. +      * to be updated so that a UID match can be found in the DBM
  1655. +      * files.
  1656. +      */
  1657. +     for (pw_rewind (), pwd = pw_next ();pwd;pwd = pw_next ()) {
  1658. +         if (pwd->pw_uid == user_id) {
  1659. +             pw_dbm_update (pwd);
  1660. +             break;
  1661. +         }
  1662. +     }
  1663. + #endif
  1664. + #ifdef    NDBM
  1665. +     if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_remove (user_name))
  1666. +         fprintf (stderr, "%s: error deleting shadow passwd dbm entry\n",
  1667. +             Prog);
  1668. + #endif
  1669. + }
  1670. + /*
  1671. +  * main - useradd command
  1672. +  */
  1673. + main (argc, argv)
  1674. + int    argc;
  1675. + char    **argv;
  1676. + {
  1677. +     struct    passwd    *pwd;
  1678. +     int    arg;
  1679. +     extern    int    optind;
  1680. +     extern    char    *optarg;
  1681. +     /*
  1682. +      * Get my name so that I can use it to report errors.
  1683. +      */
  1684. +     if (Prog = strrchr (argv[0], '/'))
  1685. +         Prog++;
  1686. +     else
  1687. +         Prog = argv[0];
  1688. + #ifdef    USE_SYSLOG
  1689. +     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  1690. + #endif
  1691. +     /*
  1692. +      * The open routines for the DBM files don't use read-write
  1693. +      * as the mode, so we have to clue them in.
  1694. +      */
  1695. + #if defined(DBM) || defined(NDBM)
  1696. +     pw_dbm_mode = O_RDWR;
  1697. + #endif
  1698. + #ifdef    NDBM
  1699. +     sp_dbm_mode = O_RDWR;
  1700. +     gr_dbm_mode = O_RDWR;
  1701. + #ifdef    SHADOWGRP
  1702. +     sg_dbm_mode = O_RDWR;
  1703. + #endif
  1704. + #endif
  1705. +     while ((arg = getopt (argc, argv, "r")) != EOF)
  1706. +         if (arg != 'r')
  1707. +             usage ();
  1708. +         else
  1709. +             rflg++;
  1710. +     
  1711. +     if (optind == argc)
  1712. +         usage ();
  1713. +     /*
  1714. +      * Start with a quick check to see if the user exists.
  1715. +      */
  1716. +     strncpy (user_name, argv[argc - 1], BUFSIZ);
  1717. +     if (! (pwd = getpwnam (user_name))) {
  1718. +         fprintf (stderr, "%s: user %s does not exist\n",
  1719. +             Prog, user_name);
  1720. +         exit (1);
  1721. +     }
  1722. +     user_id = pwd->pw_uid;
  1723. +     strcpy (user_home, pwd->pw_dir);
  1724. +     /*
  1725. +      * Do the hard stuff - open the files, create the user entries,
  1726. +      * create the home directory, then close and update the files.
  1727. +      */
  1728. +     open_files ();
  1729. +     update_user ();
  1730. +     update_groups ();
  1731. +     if (rflg)
  1732. +         rmdir (user_home);
  1733. +     close_files ();
  1734. +     exit (0);
  1735. +     /*NOTREACHED*/
  1736. + }
  1737. *** /dev/null    Fri Jun  7 11:02:59 1991
  1738. --- usermod.c    Fri Jun  7 11:10:08 1991
  1739. ***************
  1740. *** 0 ****
  1741. --- 1,1149 ----
  1742. + /*
  1743. +  * Copyright 1991, John F. Haugh II
  1744. +  * All rights reserved.
  1745. +  *
  1746. +  * Permission is granted to copy and create derivative works for any
  1747. +  * non-commercial purpose, provided this copyright notice is preserved
  1748. +  * in all copies of source code, or included in human readable form
  1749. +  * and conspicuously displayed on all copies of object code or
  1750. +  * distribution media.
  1751. +  */
  1752. + #ifndef lint
  1753. + static    char    sccsid[] = "@(#)usermod.c    3.1    11:08:35    6/7/91";
  1754. + #endif
  1755. + #include <sys/types.h>
  1756. + #include <sys/stat.h>
  1757. + #include <stdio.h>
  1758. + #include <errno.h>
  1759. + #include <pwd.h>
  1760. + #include <grp.h>
  1761. + #include <ctype.h>
  1762. + #include <fcntl.h>
  1763. + #include <time.h>
  1764. + #ifdef    BSD
  1765. + #include <strings.h>
  1766. + #else
  1767. + #include <string.h>
  1768. + #endif
  1769. + #include "config.h"
  1770. + #include "shadow.h"
  1771. + #ifdef    USE_SYSLOG
  1772. + #include <syslog.h>
  1773. + #ifndef    LOG_WARN
  1774. + #define    LOG_WARN LOG_WARNING
  1775. + #endif
  1776. + #endif
  1777. + #ifndef    NGROUPS_MAX
  1778. + #define    NGROUPS_MAX    64
  1779. + #endif
  1780. + char    user_name[BUFSIZ];
  1781. + char    user_newname[BUFSIZ];
  1782. + uid_t    user_id;
  1783. + uid_t    user_newid;
  1784. + gid_t    user_gid;
  1785. + char    user_comment[BUFSIZ];
  1786. + char    user_home[BUFSIZ];
  1787. + char    user_newhome[BUFSIZ];
  1788. + char    user_shell[BUFSIZ];
  1789. + long    user_expire;
  1790. + long    user_inactive;
  1791. + int    user_ngroups;
  1792. + gid_t    user_groups[NGROUPS_MAX];
  1793. + struct    passwd    user_pwd;
  1794. + struct    spwd    user_spwd;
  1795. + char    *Prog;
  1796. + int    uflg;    /* specify user ID for new account                            */
  1797. + int    oflg;    /* permit non-unique user ID to be specified with -u          */
  1798. + int    gflg;    /* primary group ID  for new account                          */
  1799. + int    Gflg;    /* secondary group set for new account                        */
  1800. + int    dflg;    /* home directory for new account                             */
  1801. + int    sflg;    /* shell program for new account                              */
  1802. + int    cflg;    /* comment (GECOS) field for new account                      */
  1803. + int    mflg;    /* create user's home directory if it doesn't exist           */
  1804. + int    fflg;    /* days until account with expired password is locked         */
  1805. + int    eflg;    /* days after password changed before it becomes expired      */
  1806. + int    lflg;    /* new user name for user                                     */
  1807. + #if defined(DBM) || defined(NDBM)
  1808. + extern    int    pw_dbm_mode;
  1809. + #endif
  1810. + #ifdef    NDBM
  1811. + extern    int    sp_dbm_mode;
  1812. + extern    int    gr_dbm_mode;
  1813. + extern    int    sg_dbm_mode;
  1814. + #endif
  1815. + extern    FILE    *fopen();
  1816. + extern    int    fclose();
  1817. + extern    char    *malloc();
  1818. + extern    char    *mktemp();
  1819. + extern    struct    group    *getgrnam();
  1820. + extern    struct    group    *getgrgid();
  1821. + extern    struct    group    *gr_next();
  1822. + extern    struct    group    *gr_locate();
  1823. + extern    int    gr_lock();
  1824. + extern    int    gr_unlock();
  1825. + extern    int    gr_rewind();
  1826. + extern    int    gr_open();
  1827. + #ifdef    SHADOWGRP
  1828. + extern    struct    sgrp    *sgr_next();
  1829. + extern    int    sgr_lock();
  1830. + extern    int    sgr_unlock();
  1831. + extern    int    sgr_rewind();
  1832. + extern    int    sgr_open();
  1833. + #endif
  1834. + extern    struct    passwd    *getpwnam();
  1835. + extern    struct    passwd    *pw_next();
  1836. + extern    struct    passwd    *pw_locate();
  1837. + extern    int    pw_lock();
  1838. + extern    int    pw_unlock();
  1839. + extern    int    pw_rewind();
  1840. + extern    int    pw_open();
  1841. + extern    int    spw_lock();
  1842. + extern    int    spw_unlock();
  1843. + extern    int    spw_open();
  1844. + extern    int    spw_locate();
  1845. + #define    DAY    (24L*3600L)
  1846. + #define    WEEK    (7*DAY)
  1847. + #ifdef    ITI_AGING
  1848. + #define    SCALE    (1)
  1849. + #else
  1850. + #define    SCALE    (DAY)
  1851. + #endif
  1852. + /*
  1853. +  * days and juldays are used to compute the number of days in the
  1854. +  * current month, and the cummulative number of days in the preceding
  1855. +  * months.  they are declared so that january is 1, not 0.
  1856. +  */
  1857. + static    short    days[13] = { 0,
  1858. +     31,    28,    31,    30,    31,    30,    /* JAN - JUN */
  1859. +     31,    31,    30,    31,    30,    31 };    /* JUL - DEC */
  1860. + static    short    juldays[13] = { 0,
  1861. +     0,    31,    59,    90,    120,    151,    /* JAN - JUN */
  1862. +     181,    212,    243,    273,    304,    334 };    /* JUL - DEC */
  1863. + #ifdef    NEED_MKDIR
  1864. + /*
  1865. +  * mkdir - create a directory
  1866. +  *
  1867. +  *    mkdir is provided for systems which do not include the mkdir()
  1868. +  *    system call.
  1869. +  */
  1870. + int
  1871. + mkdir (dir, mode)
  1872. + char    *dir;
  1873. + int    mode;
  1874. + {
  1875. +     int    status;
  1876. +     if (fork ()) {
  1877. +         while (wait (&status) != -1)
  1878. +             ;
  1879. +         return status >> 8;
  1880. +     }
  1881. + #ifdef    USE_SYSLOG
  1882. +     closelog ();
  1883. + #endif
  1884. +     close (2);
  1885. +     open ("/dev/null", O_WRONLY);
  1886. +     umask (0777 & ~ mode);
  1887. +     execl ("/bin/mkdir", "mkdir", dir, 0);
  1888. +     _exit (128);
  1889. + }
  1890. + #endif
  1891. + #ifdef    NEED_RENAME
  1892. + /*
  1893. +  * rename - rename a file to another name
  1894. +  *
  1895. +  *    rename is provided for systems which do not include the rename()
  1896. +  *    system call.
  1897. +  */
  1898. + int
  1899. + rename (begin, end)
  1900. + char    *begin;
  1901. + char    *end;
  1902. + {
  1903. +     struct    stat    s1, s2;
  1904. +     extern    int    errno;
  1905. +     int    orig_err = errno;
  1906. +     if (stat (begin, &s1))
  1907. +         return -1;
  1908. +     if (stat (end, &s2)) {
  1909. +         errno = orig_err;
  1910. +     } else {
  1911. +         /*
  1912. +          * See if this is a cross-device link.  We do this to
  1913. +          * insure that the link below has a chance of working.
  1914. +          */
  1915. +         if (s1.st_dev != s2.st_dev) {
  1916. +             errno = EXDEV;
  1917. +             return -1;
  1918. +         }
  1919. +         /*
  1920. +          * See if we can unlink the existing destination
  1921. +          * file.  If the unlink works the directory is writable,
  1922. +          * so there is no need here to figure that out.
  1923. +          */
  1924. +         if (unlink (end))
  1925. +             return -1;
  1926. +     }
  1927. +     /*
  1928. +      * Now just link the original name to the final name.  If there
  1929. +      * was no file previously, this link will fail if the target
  1930. +      * directory isn't writable.  The unlink will fail if the source
  1931. +      * directory isn't writable, but life stinks ...
  1932. +      */
  1933. +     if (link (begin, end) || unlink (begin))
  1934. +         return -1;
  1935. +     return 0;
  1936. + }
  1937. + #endif
  1938. + /*
  1939. +  * strtoday - compute the number of days since 1970.
  1940. +  *
  1941. +  * the total number of days prior to the current date is
  1942. +  * computed.  january 1, 1970 is used as the origin with
  1943. +  * it having a day number of 0.
  1944. +  */
  1945. + long
  1946. + strtoday (str)
  1947. + char    *str;
  1948. + {
  1949. +     char    slop[2];
  1950. +     int    month;
  1951. +     int    day;
  1952. +     int    year;
  1953. +     long    total;
  1954. +     /*
  1955. +      * start by separating the month, day and year.  this is
  1956. +      * a chauvanistic program - it only takes date input in
  1957. +      * the standard USA format.
  1958. +      */
  1959. +     if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
  1960. +         return -1;
  1961. +     /*
  1962. +      * the month, day of the month, and year are checked for
  1963. +      * correctness and the year adjusted so it falls between
  1964. +      * 1970 and 2069.
  1965. +      */
  1966. +     if (month < 1 || month > 12)
  1967. +         return -1;
  1968. +     if (day < 1)
  1969. +         return -1;
  1970. +     if ((month != 2 || (year % 4) != 0) && day > days[month])
  1971. +         return -1;
  1972. +     else if ((month == 2 && (year % 4) == 0) && day > 29)
  1973. +         return -1;
  1974. +     if (year < 0)
  1975. +         return -1;
  1976. +     else if (year < 69)
  1977. +         year += 2000;
  1978. +     else if (year < 99)
  1979. +         year += 1900;
  1980. +     if (year < 1970 || year > 2069)
  1981. +         return -1;
  1982. +     /*
  1983. +      * the total number of days is the total number of days in all
  1984. +      * the whole years, plus the number of leap days, plus the
  1985. +      * number of days in the whole months preceding, plus the number
  1986. +      * of days so far in the month.
  1987. +      */
  1988. +     total = (long) ((year - 1970) * 365L) + (((year + 1) - 1970) / 4);
  1989. +     total += (long) juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
  1990. +     total += (long) day - 1;
  1991. +     return total;
  1992. + }
  1993. + /*
  1994. +  * add_list - add a member to a list of group members
  1995. +  *
  1996. +  *    the array of member names is searched for the new member
  1997. +  *    name, and if not present it is added to a freshly allocated
  1998. +  *    list of users.
  1999. +  */
  2000. + char **
  2001. + add_list (list, member)
  2002. + char    **list;
  2003. + char    *member;
  2004. + {
  2005. +     int    i;
  2006. +     char    **tmp;
  2007. +     /*
  2008. +      * Scan the list for the new name.  Return the original list
  2009. +      * pointer if it is present.
  2010. +      */
  2011. +     for (i = 0;list[i] != (char *) 0;i++)
  2012. +         if (strcmp (list[i], member) == 0)
  2013. +             return list;
  2014. +     /*
  2015. +      * Allocate a new list pointer large enough to hold all the
  2016. +      * old entries, and the new entries as well.
  2017. +      */
  2018. +     if (! (tmp = (char **) malloc ((i + 2) * sizeof member)))
  2019. +         return 0;
  2020. +     /*
  2021. +      * Copy the original list to the new list, then append the
  2022. +      * new member and NULL terminate the result.  This new list
  2023. +      * is returned to the invoker.
  2024. +      */
  2025. +     for (i = 0;list[i] != (char *) 0;i++)
  2026. +         tmp[i] = list[i];
  2027. +     tmp[i++] = strdup (member);
  2028. +     tmp[i] = (char *) 0;
  2029. +     return tmp;
  2030. + }
  2031. + /*
  2032. +  * del_list - delete a member from a list of group members
  2033. +  *
  2034. +  *    the array of member names is searched for the old member
  2035. +  *    name, and if present it is deleted from a freshly allocated
  2036. +  *    list of users.
  2037. +  */
  2038. + char **
  2039. + del_list (list, member)
  2040. + char    **list;
  2041. + char    *member;
  2042. + {
  2043. +     int    i, j;
  2044. +     char    **tmp;
  2045. +     /*
  2046. +      * Scan the list for the new name.  Return the original list
  2047. +      * pointer if it is present.
  2048. +      */
  2049. +     for (i = j = 0;list[i] != (char *) 0;i++)
  2050. +         if (strcmp (list[i], member))
  2051. +             j++;
  2052. +     if (j == i)
  2053. +         return list;
  2054. +     /*
  2055. +      * Allocate a new list pointer large enough to hold all the
  2056. +      * old entries, and the new entries as well.
  2057. +      */
  2058. +     if (! (tmp = (char **) malloc ((j + 2) * sizeof member)))
  2059. +         return 0;
  2060. +     /*
  2061. +      * Copy the original list to the new list, then append the
  2062. +      * new member and NULL terminate the result.  This new list
  2063. +      * is returned to the invoker.
  2064. +      */
  2065. +     for (i = j = 0;list[i] != (char *) 0;i++)
  2066. +         if (strcmp (list[i], member))
  2067. +             tmp[j++] = list[i];
  2068. +     tmp[j] = (char *) 0;
  2069. +     return tmp;
  2070. + }
  2071. + /*
  2072. +  * get_groups - convert a list of group names to an array of group IDs
  2073. +  *
  2074. +  *    get_groups() takes a comma-separated list of group names and
  2075. +  *    converts it to an array of group ID values.  Any unknown group
  2076. +  *    names are reported as errors.
  2077. +  */
  2078. + int
  2079. + get_groups (list)
  2080. + char    *list;
  2081. + {
  2082. +     char    *cp;
  2083. +     struct    group    *grp;
  2084. +     int    errors = 0;
  2085. +     /*
  2086. +      * Initialize the list to be empty
  2087. +      */
  2088. +     user_ngroups = 0;
  2089. +     if (! *list)
  2090. +         return 0;
  2091. +     /*
  2092. +      * So long as there is some data to be converted, strip off
  2093. +      * each name and look it up.  A mix of numerical and string
  2094. +      * values for group identifiers is permitted.
  2095. +      */
  2096. +     do {
  2097. +         /*
  2098. +          * Strip off a single name from the list
  2099. +          */
  2100. +         if (cp = strchr (list, ','))
  2101. +             *cp++ = '\0';
  2102. +         /*
  2103. +          * Names starting with digits are treated as numerical
  2104. +          * GID values, otherwise the string is looked up as is.
  2105. +          */
  2106. +         if (isdigit (*list))
  2107. +             grp = getgrgid (atoi (list));
  2108. +         else
  2109. +             grp = getgrnam (list);
  2110. +         /*
  2111. +          * There must be a match, either by GID value or by
  2112. +          * string name.
  2113. +          */
  2114. +         if (! grp) {
  2115. +             fprintf (stderr, "%s: unknown group %s\n", Prog, list);
  2116. +             errors++;
  2117. +         }
  2118. +         /*
  2119. +          * Add the GID value from the group file to the user's
  2120. +          * list of groups.
  2121. +          */
  2122. +         user_groups[user_ngroups++] = grp->gr_gid;
  2123. +         list = cp;
  2124. +     } while (list);
  2125. +     /*
  2126. +      * Any errors in finding group names are fatal
  2127. +      */
  2128. +     if (errors)
  2129. +         return -1;
  2130. +     return 0;
  2131. + }
  2132. + /*
  2133. +  * usage - display usage message and exit
  2134. +  */
  2135. + usage ()
  2136. + {
  2137. +     fprintf (stderr,
  2138. +         "usage: %s [-u uid [-o]] [-g group] [-G group,...] \n", Prog);
  2139. +     fprintf (stderr,
  2140. +         "\t\t[-d home [-m]] [-s shell] [-c comment] [-l new_name]\n");
  2141. +     fprintf (stderr,
  2142. +         "\t\t[-f inactive] [-e expire] name\n");
  2143. +     exit (2);
  2144. + }
  2145. + /*
  2146. +  * new_pwent - initialize the values in a password file entry
  2147. +  *
  2148. +  *    new_pwent() takes all of the values that have been entered and
  2149. +  *    fills in a (struct passwd) with them.
  2150. +  */
  2151. + void
  2152. + new_pwent (pwent)
  2153. + struct    passwd    *pwent;
  2154. + {
  2155. +     if (lflg)
  2156. +         pwent->pw_name = strdup (user_newname);
  2157. +     if (uflg)
  2158. +         pwent->pw_uid = user_newid;
  2159. +     if (gflg)
  2160. +         pwent->pw_gid = user_gid;
  2161. +     if (cflg)
  2162. +         pwent->pw_gecos = strdup (user_comment);
  2163. +     if (dflg)
  2164. +         pwent->pw_dir = strdup (user_newhome);
  2165. +     if (sflg)
  2166. +         pwent->pw_shell = strdup (user_shell);
  2167. + }
  2168. + /*
  2169. +  * new_spent - initialize the values in a shadow password file entry
  2170. +  *
  2171. +  *    new_spent() takes all of the values that have been entered and
  2172. +  *    fills in a (struct spwd) with them.
  2173. +  */
  2174. + void
  2175. + new_spent (spent)
  2176. + struct    spwd    *spent;
  2177. + {
  2178. +     if (lflg)
  2179. +         spent->sp_namp = strdup (user_newname);
  2180. +     spent->sp_inact = user_inactive;
  2181. +     spent->sp_expire = user_expire;
  2182. + }
  2183. + /*
  2184. +  * grp_update - add user to secondary group set
  2185. +  *
  2186. +  *    grp_update() takes the secondary group set given in user_groups
  2187. +  *    and adds the user to each group given by that set.
  2188. +  */
  2189. + void
  2190. + grp_update ()
  2191. + {
  2192. +     int    i;
  2193. +     int    is_member;
  2194. +     int    was_member;
  2195. +     int    was_admin;
  2196. +     struct    group    *grp;
  2197. +     struct    sgrp    *sgrp;
  2198. +     /*
  2199. +      * Lock and open the group file.  This will load all of the group
  2200. +      * entries.
  2201. +      */
  2202. +     if (! gr_lock ()) {
  2203. +         fprintf (stderr, "%s: error locking group file\n", Prog);
  2204. +         exit (1);
  2205. +     }
  2206. +     if (! gr_open (O_RDWR)) {
  2207. +         fprintf (stderr, "%s: error opening group file\n", Prog);
  2208. +         exit (1);
  2209. +     }
  2210. + #ifdef    SHADOWGRP
  2211. +     if (! sgr_lock ()) {
  2212. +         fprintf (stderr, "%s: error locking shadow group file\n", Prog);
  2213. +         exit (1);
  2214. +     }
  2215. +     if (! sgr_open (O_RDWR)) {
  2216. +         fprintf (stderr, "%s: error opening shadow group file\n", Prog);
  2217. +         exit (1);
  2218. +     }
  2219. + #endif
  2220. +     /*
  2221. +      * Scan through the entire group file looking for the groups that
  2222. +      * the user is a member of.
  2223. +      */
  2224. +     for (gr_rewind (), grp = gr_next ();grp;grp = gr_next ()) {
  2225. +         /*
  2226. +          * See if the user specified this group as one of their
  2227. +          * concurrent groups.
  2228. +          */
  2229. +         for (i = 0;i < user_ngroups;i++)
  2230. +             if (grp->gr_gid == user_groups[i])
  2231. +                 break;
  2232. +         is_member = i == user_ngroups ? -1:i;
  2233. +         for (i = 0;grp->gr_mem[i];i++)
  2234. +             if (strcmp (user_name, grp->gr_mem[i]) == 0)
  2235. +                 break;
  2236. +         was_member = grp->gr_mem[i] ? i:-1;
  2237. +         if (is_member == -1 && was_member == -1)
  2238. +             continue;
  2239. +         if (was_member >= 0 && (! Gflg || is_member >= 0)) {
  2240. +             if (lflg) {
  2241. +                 grp->gr_mem = del_list (grp->gr_mem,
  2242. +                     user_name);
  2243. +                 grp->gr_mem = add_list (grp->gr_mem,
  2244. +                     user_newname);
  2245. + #ifdef    USE_SYSLOG
  2246. +                 syslog (LOG_INFO,
  2247. +                     "change `%s' to `%s' in group `%s'\n",
  2248. +                     user_name, user_newname, grp->gr_name);
  2249. + #endif
  2250. +             }
  2251. +         } else if (was_member >= 0 && Gflg && is_member < 0) {
  2252. +             grp->gr_mem = del_list (grp->gr_mem, user_name);
  2253. + #ifdef    USE_SYSLOG
  2254. +             syslog (LOG_INFO, "delete `%s' from group `%s'\n",
  2255. +                 user_name, grp->gr_name);
  2256. + #endif
  2257. +         } else if (was_member < 0 && Gflg && is_member >= 0) {
  2258. +             grp->gr_mem = add_list (grp->gr_mem,
  2259. +                 lflg ? user_newname:user_name);
  2260. + #ifdef    USE_SYSLOG
  2261. +             syslog (LOG_INFO, "add `%s' to group `%s'\n",
  2262. +                 lflg ? user_newname:user_name, grp->gr_name);
  2263. + #endif
  2264. +         } else
  2265. +             continue;
  2266. +         if (! gr_update (grp)) {
  2267. +             fprintf (stderr, "%s: error adding new group entry\n",
  2268. +                 Prog);
  2269. +             exit (1);
  2270. +         }
  2271. + #ifdef    NDBM
  2272. +         /*
  2273. +          * Update the DBM group file with the new entry as well.
  2274. +          */
  2275. +         if (! gr_dbm_update (grp)) {
  2276. +             fprintf (stderr, "%s: cannot add new dbm group entry\n",
  2277. +                 Prog);
  2278. +             exit (1);
  2279. +         }
  2280. + #endif
  2281. +     }
  2282. + #ifdef    SHADOWGRP
  2283. +     /*
  2284. +      * Scan through the entire shadow group file looking for the groups
  2285. +      * that the user is a member of.
  2286. +      */
  2287. +     for (sgr_rewind (), sgrp = sgr_next ();sgrp;sgrp = sgr_next ()) {
  2288. +         /*
  2289. +          * See if the user was a member of this group
  2290. +          */
  2291. +         for (i = 0;sgrp->sg_mem[i];i++)
  2292. +             if (strcmp (sgrp->sg_mem[i], user_name) == 0)
  2293. +                 break;
  2294. +         was_member = sgrp->sg_mem[i] ? i:-1;
  2295. +         /*
  2296. +          * See if the user was an administrator of this group
  2297. +          */
  2298. +         for (i = 0;sgrp->sg_adm[i];i++)
  2299. +             if (strcmp (sgrp->sg_adm[i], user_name) == 0)
  2300. +                 break;
  2301. +         was_admin = sgrp->sg_adm[i] ? i:-1;
  2302. +         /*
  2303. +          * See if the user specified this group as one of their
  2304. +          * concurrent groups.
  2305. +          */
  2306. +         for (i = 0;i < user_ngroups;i++) {
  2307. +             if (! (grp = gr_locate (sgrp->sg_name)))
  2308. +                 continue;
  2309. +             if (grp->gr_gid == user_groups[i])
  2310. +                 break;
  2311. +         }
  2312. +         is_member = i == user_ngroups ? -1:i;
  2313. +         if (is_member == -1 && was_admin == -1 && was_member == -1)
  2314. +             continue;
  2315. +         if (was_admin >= 0 && lflg) {
  2316. +             sgrp->sg_adm = del_list (sgrp->sg_adm, user_name);
  2317. +             sgrp->sg_adm = add_list (sgrp->sg_adm, user_newname);
  2318. + #ifdef    USE_SYSLOG
  2319. +             syslog (LOG_INFO, "change admin `%s' to `%s' in shadow group `%s'\n",
  2320. +                 user_name, user_newname, sgrp->sg_name);
  2321. + #endif
  2322. +         }
  2323. +         if (was_member >= 0 && (! Gflg || is_member >= 0)) {
  2324. +             if (lflg) {
  2325. +                 sgrp->sg_mem = del_list (sgrp->sg_mem,
  2326. +                     user_name);
  2327. +                 sgrp->sg_mem = add_list (sgrp->sg_mem,
  2328. +                     user_newname);
  2329. + #ifdef    USE_SYSLOG
  2330. +                 syslog (LOG_INFO, "change `%s' to `%s' in shadow group `%s'\n",
  2331. +                     user_name, user_newname, sgrp->sg_name);
  2332. + #endif
  2333. +             }
  2334. +         } else if (was_member >= 0 && Gflg && is_member < 0) {
  2335. +             sgrp->sg_mem = del_list (sgrp->sg_mem, user_name);
  2336. + #ifdef    USE_SYSLOG
  2337. +             syslog (LOG_INFO, "delete `%s' from shadow group `%s'\n",
  2338. +                 user_name, sgrp->sg_name);
  2339. + #endif
  2340. +         } else if (was_member < 0 && Gflg && is_member >= 0) {
  2341. +             sgrp->sg_mem = add_list (sgrp->sg_mem,
  2342. +                 lflg ? user_newname:user_name);
  2343. + #ifdef    USE_SYSLOG
  2344. +             syslog (LOG_INFO, "add `%s' to shadow group `%s'\n",
  2345. +                 lflg ? user_newname:user_name, grp->gr_name);
  2346. + #endif
  2347. +         } else
  2348. +             continue;
  2349. +         /* 
  2350. +          * Update the group entry to reflect the changes.
  2351. +          */
  2352. +         if (! sgr_update (sgrp)) {
  2353. +             fprintf (stderr, "%s: error adding new group entry\n",
  2354. +                 Prog);
  2355. +             exit (1);
  2356. +         }
  2357. + #ifdef    NDBM
  2358. +         /*
  2359. +          * Update the DBM group file with the new entry as well.
  2360. +          */
  2361. +         if (! sgr_dbm_update (sgrp)) {
  2362. +             fprintf (stderr, "%s: cannot add new dbm group entry\n",
  2363. +                 Prog);
  2364. +             exit (1);
  2365. +         }
  2366. + #endif
  2367. +     }
  2368. + #endif
  2369. + }
  2370. + /*
  2371. +  * check_new_id - verify the new UID for uniqueness
  2372. +  *
  2373. +  *    check_new_id() insures that the new UID does not exist already.
  2374. +  *    It does this by checking that the UID has changed and that there
  2375. +  *    is no current entry for this user ID.
  2376. +  */
  2377. + int
  2378. + check_new_id ()
  2379. + {
  2380. +     /*
  2381. +      * First, the easy stuff.  If the ID can be duplicated, or if
  2382. +      * the ID didn't really change, just return.  If the ID didn't
  2383. +      * change, turn off those flags.  No sense doing needless work.
  2384. +      */
  2385. +     if (oflg)
  2386. +         return 0;
  2387. +     if (user_id == user_newid) {
  2388. +         uflg = lflg = 0;
  2389. +         return 0;
  2390. +     }
  2391. +     if (getpwuid (user_newid))
  2392. +         return -1;
  2393. +     return 0;
  2394. + }
  2395. + /*
  2396. +  * process_flags - perform command line argument setting
  2397. +  *
  2398. +  *    process_flags() interprets the command line arguments and sets
  2399. +  *    the values that the user will be created with accordingly.  The
  2400. +  *    values are checked for sanity.
  2401. +  */
  2402. + void
  2403. + process_flags (argc, argv)
  2404. + int    argc;
  2405. + char    **argv;
  2406. + {
  2407. +     extern    int    optind;
  2408. +     extern    char    *optarg;
  2409. +     struct    group    *grp;
  2410. +     struct    passwd    *pwd;
  2411. +     struct    spwd    *spwd;
  2412. +     long    l;
  2413. +     int    anyflag = 0;
  2414. +     int    arg;
  2415. +     if (argc == 1 || argv[argc - 1][0] == '-')
  2416. +         usage ();
  2417. +     if (! (pwd = getpwnam (argv[argc - 1]))) {
  2418. +         fprintf (stderr, "%s: user %s does not exist\n",
  2419. +             Prog, argv[argc - 1]);
  2420. +         exit (6);
  2421. +     }
  2422. +     strcpy (user_name, pwd->pw_name);
  2423. +     user_id = pwd->pw_uid;
  2424. +     user_gid = pwd->pw_gid;
  2425. +     strcpy (user_comment, pwd->pw_gecos);
  2426. +     strcpy (user_home, pwd->pw_dir);
  2427. +     strcpy (user_shell, pwd->pw_shell);
  2428. +     if (spwd = getspnam (user_name)) {
  2429. +         user_expire = spwd->sp_expire;
  2430. +         user_inactive = spwd->sp_inact;
  2431. +     }
  2432. +     while ((arg = getopt (argc, argv, "u:og:G:d:s:c:mf:e:l:")) != EOF) {
  2433. +         switch (arg) {
  2434. +             case 'c':
  2435. +                 if (strcmp (optarg, user_comment)) {
  2436. +                     cflg++;
  2437. +                     strncpy (user_comment, optarg, BUFSIZ);
  2438. +                 }
  2439. +                 break;
  2440. +             case 'd':
  2441. +                 dflg++;
  2442. +                 strncpy (user_newhome, optarg, BUFSIZ);
  2443. +                 break;
  2444. +             case 'e':
  2445. +                 l = strtoday (optarg);
  2446. + #ifdef    ITI_AGING
  2447. +                 l *= DAY;
  2448. + #endif
  2449. +                 if (l != user_expire) {
  2450. +                     eflg++;
  2451. +                     user_expire = l;
  2452. +                 }
  2453. +                 break;
  2454. +             case 'f':
  2455. +                 if (user_inactive != atoi (optarg)) {
  2456. +                     fflg++;
  2457. +                     user_inactive = atoi (optarg);
  2458. +                 }
  2459. +                 break;
  2460. +             case 'g':
  2461. +                 if (isdigit (optarg[0]))
  2462. +                     grp = getgrgid (atoi (optarg));
  2463. +                 else
  2464. +                     grp = getgrnam (optarg);
  2465. +                 if (! grp) {
  2466. +                     fprintf (stderr,
  2467. +                         "%s: unknown group %s\n",
  2468. +                         optarg);
  2469. +                     exit (1);
  2470. +                 }
  2471. +                 if (grp->gr_gid != user_gid) {
  2472. +                     gflg++;
  2473. +                     user_gid = grp->gr_gid;
  2474. +                 }
  2475. +                 break;
  2476. +             case 'G':
  2477. +                 Gflg++;
  2478. +                 if (get_groups (optarg))
  2479. +                     exit (1);
  2480. +                 break;
  2481. +             case 'l':
  2482. +                 if (strcmp (user_name, optarg)) {
  2483. +                     lflg++;
  2484. +                     strcpy (user_newname, optarg);
  2485. +                 }
  2486. +                 break;
  2487. +             case 'm':
  2488. +                 if (! dflg)
  2489. +                     usage ();
  2490. +                 mflg++;
  2491. +                 break;
  2492. +             case 'o':
  2493. +                 if (! uflg)
  2494. +                     usage ();
  2495. +                 oflg++;
  2496. +                 break;
  2497. +             case 's':
  2498. +                 if (strcmp (user_shell, optarg)) {
  2499. +                     strncpy (user_shell, optarg, BUFSIZ);
  2500. +                     sflg++;
  2501. +                 }
  2502. +                 break;
  2503. +             case 'u':
  2504. +                 uflg++;
  2505. +                 user_newid = atoi (optarg);
  2506. +                 break;
  2507. +             default:
  2508. +                 usage ();
  2509. +         }
  2510. +         anyflag++;
  2511. +     }
  2512. +     if (optind != argc - 1)
  2513. +         usage ();
  2514. +     if (dflg && strcmp (user_home, user_newhome) == 0)
  2515. +         dflg = mflg = 0;
  2516. +     if (uflg && user_id == user_newid)
  2517. +         uflg = oflg = 0;
  2518. +     if (lflg && getpwnam (user_newname)) {
  2519. +         fprintf (stderr, "%s: user %s exists\n", user_newname);
  2520. +         exit (9);
  2521. +     }
  2522. + }
  2523. + /*
  2524. +  * close_files - close all of the files that were opened
  2525. +  *
  2526. +  *    close_files() closes all of the files that were opened for this
  2527. +  *    new user.  This causes any modified entries to be written out.
  2528. +  */
  2529. + close_files ()
  2530. + {
  2531. +     if (! pw_close ()) {
  2532. +         fprintf (stderr, "%s: cannot rewrite password file\n", Prog);
  2533. +         exit (1);
  2534. +     }
  2535. +     if (! spw_close ()) {
  2536. +         fprintf (stderr, "%s: cannot rewrite shadow password file\n",    
  2537. +             Prog);
  2538. +         exit (1);
  2539. +     }
  2540. +     if (user_ngroups > 0) {
  2541. +         if (! gr_close ()) {
  2542. +             fprintf (stderr, "%s: cannot rewrite group file\n",
  2543. +                 Prog);
  2544. +             exit (1);
  2545. +         }
  2546. +         (void) gr_unlock ();
  2547. + #ifdef    SHADOWGRP
  2548. +         if (! sgr_close ()) {
  2549. +             fprintf (stderr, "%s: cannot rewrite shadow group file\n",
  2550. +                 Prog);
  2551. +             exit (1);
  2552. +         }
  2553. + #endif
  2554. +     }
  2555. +     (void) pw_unlock ();
  2556. + }
  2557. + /*
  2558. +  * open_files - lock and open the password files
  2559. +  *
  2560. +  *    open_files() opens the two password files.
  2561. +  */
  2562. + open_files ()
  2563. + {
  2564. +     if (! pw_lock ()) {
  2565. +         fprintf (stderr, "%s: unable to lock password file\n", Prog);
  2566. +         exit (1);
  2567. +     }
  2568. +     if (! pw_open (O_RDWR)) {
  2569. +         fprintf (stderr, "%s: unable to open password file\n", Prog);
  2570. +         exit (1);
  2571. +     }
  2572. +     if (! spw_lock ()) {
  2573. +         fprintf ("%s: cannot lock shadow password file\n", Prog);
  2574. +         exit (1);
  2575. +     }
  2576. +     if (! spw_open (O_RDWR)) {
  2577. +         fprintf ("%s: cannot open shadow password file\n", Prog);
  2578. +         exit (1);
  2579. +     }
  2580. + }
  2581. + /*
  2582. +  * usr_update - create the user entries
  2583. +  *
  2584. +  *    usr_update() creates the password file entries for this user
  2585. +  *    and will update the group entries if required.
  2586. +  */
  2587. + usr_update ()
  2588. + {
  2589. +     struct    passwd    pwent;
  2590. +     struct    spwd    spent;
  2591. +     struct    passwd    *pwd;
  2592. +     struct    spwd    *spwd;
  2593. +     pwd = pw_locate (user_name);
  2594. +     pwent = *pwd;
  2595. +     spwd = spw_locate (user_name);
  2596. +     spent = *spwd;
  2597. +     new_pwent (&pwent);
  2598. +     new_spent (&spent);
  2599. +     if (lflg || uflg || gflg || cflg || dflg || sflg) {
  2600. +         if (! pw_update (&pwent)) {
  2601. +             fprintf (stderr, "%s: error changing password entry\n");
  2602. +             exit (1);
  2603. +         }
  2604. +         if (lflg && ! pw_remove (user_name)) {
  2605. +             fprintf (stderr, "%s: error removing password entry\n");
  2606. +             exit (1);
  2607. +         }
  2608. + #if defined(DBM) || defined(NDBM)
  2609. +         if (access ("/etc/passwd.pag", 0) == 0) {
  2610. +             if (! pw_dbm_update (&pwent)) {
  2611. +                 fprintf (stderr, "%s: error adding password dbm entry\n",
  2612. +                     Prog);
  2613. +                 exit (1);
  2614. +             }
  2615. +             if (lflg && (pwd = getpwnam (user_name)) && ! pw_dbm_remove (pwd)) {
  2616. +                 fprintf (stderr, "%s: error removing passwd dbm entry\n",
  2617. +                     Prog);
  2618. +                 exit (1);
  2619. +             }
  2620. +         }
  2621. + #endif
  2622. +     }
  2623. +     if (lflg || eflg || fflg) {
  2624. +         if (! spw_update (&spent)) {
  2625. +             fprintf (stderr, "%s: error adding new shadow password entry\n",
  2626. +                 Prog);
  2627. +             exit (1);
  2628. +         }
  2629. +         if (lflg && ! spw_remove (user_name)) {
  2630. +             fprintf (stderr, "%s: error removing shadow password entry\n",
  2631. +                 Prog);
  2632. +             exit (1);
  2633. +         }
  2634. +     }
  2635. + #ifdef    NDBM
  2636. +     if (access ("/etc/shadow.pag", 0) == 0) {
  2637. +         if (! sp_dbm_update (&spent)) {
  2638. +             fprintf (stderr, "%s: error updating shadow passwd dbm entry\n",
  2639. +                 Prog);
  2640. +             exit (1);
  2641. +         }
  2642. +         if (lflg && ! sp_dbm_remove (user_name)) {
  2643. +             fprintf (stderr, "%s: error removing shadow passwd db entry\n",
  2644. +                 Prog);
  2645. +             exit (1);
  2646. +         }
  2647. +     }
  2648. + #endif
  2649. +     if (Gflg || lflg)
  2650. +         grp_update ();
  2651. + }
  2652. + /*
  2653. +  * move_home - move the user's home directory
  2654. +  *
  2655. +  *    move_home() creates the user's home directory if it does not
  2656. +  *    already exist.  It will be created mode 755 owned by the user
  2657. +  *    with the user's default group.
  2658. +  */
  2659. + move_home ()
  2660. + {
  2661. +     if (mflg && access (user_home, 0) == 0) {
  2662. +         if (access (user_newhome, 0) == 0) {
  2663. +             fprintf (stderr, "%s: directory %s exists\n",
  2664. +                 Prog, user_newhome);
  2665. +             exit (12);
  2666. +         } else if (rename (user_home, user_newhome)) {
  2667. +             fprintf (stderr,
  2668. +                 "%s: cannot rename directory %s to %s\n",
  2669. +                 Prog, user_home, user_newhome);
  2670. +             exit (12);
  2671. +         }
  2672. +     }
  2673. +     if (uflg || gflg)
  2674. +         chown (dflg ? user_newhome:user_home, user_id, user_gid);
  2675. + }
  2676. + /*
  2677. +  * main - useradd command
  2678. +  */
  2679. + main (argc, argv)
  2680. + int    argc;
  2681. + char    **argv;
  2682. + {
  2683. +     /*
  2684. +      * Get my name so that I can use it to report errors.
  2685. +      */
  2686. +     if (Prog = strrchr (argv[0], '/'))
  2687. +         Prog++;
  2688. +     else
  2689. +         Prog = argv[0];
  2690. + #ifdef    USE_SYSLOG
  2691. +     openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
  2692. + #endif
  2693. +     /*
  2694. +      * The open routines for the DBM files don't use read-write
  2695. +      * as the mode, so we have to clue them in.
  2696. +      */
  2697. + #if defined(DBM) || defined(NDBM)
  2698. +     pw_dbm_mode = O_RDWR;
  2699. + #endif
  2700. + #ifdef    NDBM
  2701. +     sp_dbm_mode = O_RDWR;
  2702. +     gr_dbm_mode = O_RDWR;
  2703. + #ifdef    SHADOWGRP
  2704. +     sg_dbm_mode = O_RDWR;
  2705. + #endif
  2706. + #endif
  2707. +     process_flags (argc, argv);
  2708. +     /*
  2709. +      * Do the hard stuff - open the files, change the user entries,
  2710. +      * change the home directory, then close and update the files.
  2711. +      */
  2712. +     open_files ();
  2713. +     usr_update ();
  2714. +     close_files ();
  2715. +     if (mflg)
  2716. +         move_home ();
  2717. +     exit (0);
  2718. +     /*NOTREACHED*/
  2719. + }
  2720. -- 
  2721. John F. Haugh II        | Distribution to  | UUCP: ...!cs.utexas.edu!rpp386!jfh
  2722. Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) |  Domain: jfh@rpp386.cactus.org
  2723. "If liberals interpreted the 2nd Amendment the same way they interpret the
  2724.  rest of the Constitution, gun ownership would be mandatory."
  2725.