home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1475 / dpasswd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  17.1 KB  |  699 lines

  1. /************************************************************************\
  2. **                                                                      **
  3. ** Program name: dpasswd.c (Manage "Dialup Passwords" for /bin/login)   **
  4. **                                                                      **
  5. ** Programmer:   Lenny Tropiano        EMAIL: lenny@ICUS.COM            **
  6. ** Organization: ICUS Software Systems (c)1988,1990 All rights reserved **
  7. ** Date:         December 4, 1988      [Version 1.0]                    **
  8. **               May 16, 1990          [Version 1.6]                    **
  9. **               June 16, 1990         [Version 2.0]                    **
  10. **                                                                      **
  11. ** Modified by Gary Butler, ST, Pacific Bell [1.6]                      **
  12. ** Modified by Joe Wasik, ST, Pacific Bell   [1.6]                      **
  13. ** Modified by Lenny Tropiano, ICUS Software Systems [2.0]              **
  14. **                                                                      **
  15. **************************************************************************
  16. **                                                                      **
  17. ** Program to administer the "undocumented" feature /bin/login Dialup   **
  18. ** Password's that is part of most UNIX System V releases               **
  19. **                                                                      **
  20. ** compile with -dTEST to try out on local (current dir) files          **
  21. **                                                                      **
  22. ** compile with -dDEBUG to see debug stuff                              **
  23. **                                                                      **
  24. **************************************************************************
  25. **                                                                      **
  26. ** Permission granted to redistribute without profit in the public      **
  27. ** domain only.  This header must remain in-tact as is.  This program   **
  28. ** carries no warranties, express or implied, and all consequences      **
  29. ** resulting from the use of this program are the sole responsibility   **
  30. ** of the user.  Any modifications of this program must be mailed to    **
  31. ** the author.                                                          **
  32. **                                                                      **
  33. \************************************************************************/
  34.  
  35. /*
  36. ** Revision history:
  37. **
  38. ** May 16, 1990
  39. **
  40. ** Bugs and major problems fixed:
  41. **
  42. ** 1 -    When writing out the d_passwd file, the file was opened for output
  43. **    before getting password or even checking for user errors.  If any
  44. **    kind of interruption happened (signal, user error) then program quit
  45. **    without writing array contents - effectively nulling the file.
  46. **
  47. ** 2 -    Program checked to see if progname on command line was already in
  48. **    the file; however, to get around the problem of the password being
  49. **    part of the string, the program compared only the number of
  50. **    chracters in the cmdline progname.  So, if a name was provided
  51. **    that in its entirety matched only the first part of an existing
  52. **    progname, this was considered a match.
  53. **
  54. ** 3 -    Both MAX_PROG and MAX_DIALUPS was applied to existing data, rather
  55. **    then only new data.  So, if a user wanted to enter a new entry to
  56. **    a file that was already too large, the file was truncated.
  57. **
  58. ** 4 -    A minor error was the PROGLEN variable which was described as the
  59. **    maximum length of the program name.  It was really the maximum
  60. **    length of the d_passwd record.
  61. **
  62. **
  63. ** Improvements made:
  64. **
  65. ** 1 -    Code run through indent(1) to rearrange braces, comments,
  66. **    indentation, and to line up variable definitions.
  67. **
  68. ** 2 -    Added comments.
  69. **
  70. ** 3 -    Several variables used as flags we're never initialized, while I didn't
  71. **    run into problems, it could have caused problems on some systems.
  72. **
  73. ** 4 -    Made it easier to control permissions of new d_passwd and dialup
  74. **    files by using variables.
  75. **
  76. ** 5 -    Greatly increased buffer sizes.
  77. **
  78. ** 6 -    Added DEBUG variable (#define) to aid in future work.
  79. **
  80. ** 7 -    Added TEST variable (#define) so that user can try out this program
  81. **    on local files (curr dir) before going live.
  82. **
  83. ** 8 -     Eliminated all lint errors.
  84. **
  85. ** 9 -  Tell user when a password was changed.  As written, this program
  86. **    mislead the user by saying a changed password wasa new password.
  87. **
  88. ** 10 -    Don't allow null password.
  89. **
  90. ** 11 - Default to 600 rather than 644 permissions.
  91. **
  92. **
  93. ** Improvements suggested:
  94. **
  95. ** 1 -    Change -v (verbose) to -s (silent) so that errors appear by default.
  96. **
  97. ** 2 -  Use write to temp file and rename rather than rewrite of files.
  98. **
  99. **    - Joe Wasik
  100. **
  101. ** June 16, 1990
  102. **
  103. ** Some minor improvements:
  104. **
  105. ** 1 -    Code run through indent(1) again using the "-kr" option so it's more
  106. **    like the way I like to code. This is to rearrange braces, comments,
  107. **    indentation, and to line up variable definitions using tabs, and less
  108. **    spaces.  Sorry for imposing my way of coding, but what can I say ...
  109. **    After running indent(1) I cleaned it up a little by hand, added some
  110. **    more spaces where it "looked" necessary for readability.
  111. **
  112. ** 2 -    Changed -v (verbose) to -q (quiet) so that errors appear by default,
  113. **    as suggested (instead of silent [-s], I'm using the syntax quiet [-q]).
  114. **
  115. ** 3 -    Another option -n (null password) has been added to create password 
  116. **    entries for shells that require no password.  It appears that certain  
  117. **    versions of /bin/login will prompt for a dialup password for all shells
  118. **    if the restriction is in the /etc/dialups file, but will fail if there
  119. **    is no accompaning entry in /etc/d_passwd (even a null password entry).
  120. **
  121. **    - Lenny Tropiano
  122. **
  123. */
  124.  
  125. #include <stdio.h>
  126. #include <sys/types.h>
  127. #include <pwd.h>
  128. #include <string.h>
  129.  
  130. /*
  131. ** preprocessor parameters
  132. */
  133.  
  134. /* permissions of dialups file (if created) */
  135. #ifndef DIALUPS_PERMS
  136. #define    DIALUPS_PERMS    0600
  137. #endif
  138.  
  139. /* permissions of d_passwd file (if created) */
  140. #ifndef DPASSWD_PERMS
  141. #define    DPASSWD_PERMS    0600
  142. #endif
  143.  
  144. /* maximum # of dialups on system */
  145. #ifndef MAX_DIALUPS
  146. #define    MAX_DIALUPS    10
  147. #endif
  148.  
  149. /* maximum # of program shells */
  150. #ifndef MAX_PROGS
  151. #define    MAX_PROGS    20
  152. #endif
  153.  
  154. /* tty device length "/dev/ttyXXX" */
  155. #ifndef TTYLEN
  156. #define TTYLEN        20
  157. #endif
  158.  
  159. /* program pathname length */
  160. #ifndef PROGLEN
  161. #define PROGLEN        60
  162. #endif
  163.  
  164. /* password buffer length */
  165. #ifndef PSWLEN
  166. #define PSWLEN        20
  167. #endif
  168.  
  169. /* password password entry attempts */
  170. #ifndef PSWATTEMPTS
  171. #define PSWATTEMPTS    3
  172. #endif
  173.  
  174. /* check debug flag */
  175. #ifdef DEBUG
  176. int debug = 1;
  177. #else
  178. int debug = 0;
  179. #endif
  180.  
  181. /* compute buffer for d_passwd file (name + psw + separator space) */
  182. #define DPASSWDLEN    (PROGLEN+PSWLEN+3)
  183.  
  184. /*
  185.  * global variables
  186.  */
  187.  
  188. int    delete,            /* remove dialup information        */
  189.     quiet,            /* don't be verbose, be quiet       */
  190.     null;            /* create a null password entry     */
  191. long    time();
  192. long    salt;
  193. char    saltc[2];
  194. char    terminal[TTYLEN],    /* device to declare as dialup line */
  195.     program[PROGLEN],    /* pathname to give dialup password */
  196.     passwd[PSWLEN];
  197. char    *thisprg;
  198.  
  199. void    exit();
  200. void    perror();
  201.  
  202. #ifdef TEST
  203. static    char *dttyfile = "dialups";
  204. static    char *dpswfile = "d_passwd";
  205.  
  206. #else
  207. static    char *dttyfile = "/etc/dialups";
  208. static    char *dpswfile = "/etc/d_passwd";
  209.  
  210. #endif
  211.  
  212. main(argc, argv)
  213. int    argc;
  214. char    **argv;
  215. {
  216.     int        c, 
  217.             errflg, 
  218.             chgterm,
  219.             chgprog;
  220.     extern int    optind;
  221.     extern char    *optarg;
  222.     void        manage_dialup(),
  223.             manage_program();
  224.  
  225.  
  226.     /*
  227.     ** initialize program parameters
  228.     */
  229.  
  230.     thisprg = argv[0];
  231.     delete = errflg = quiet = null = chgterm = chgprog = 0;
  232.     terminal[0] = program[0] = '\0';
  233.  
  234.     if (debug)
  235.         (void) printf("buffer length: %d\n", DPASSWDLEN);
  236.  
  237.     /*
  238.     ** read command line options
  239.     */
  240.  
  241.     while ((c = getopt(argc, argv, "?qdnt:p:")) != EOF) {
  242.         switch (c) {
  243.         case 'q':
  244.             quiet = 1;
  245.             break;
  246.         case 'd':
  247.             delete = 1;
  248.             break;
  249.         case 'n':
  250.             null = 1;
  251.             break;
  252.         case 't':
  253.             if (strchr(optarg, '/') == NULL) {
  254.             chgterm = 1;
  255.             (void) sprintf(terminal, "/dev/%s", optarg);
  256.             } else
  257.             errflg++;
  258.             break;
  259.         case 'p':
  260.             chgprog = 1;
  261.             (void) sprintf(program, "%s", optarg);
  262.             break;
  263.         case '?':
  264.             errflg++;
  265.             break;
  266.         }            /* end switch */
  267.     }            /* end while */
  268.  
  269.     if (errflg || (!chgterm && !chgprog)) {
  270.         (void) fprintf(stderr,
  271.             "Usage: %s [-qnd] -p program -t terminal\n", 
  272.             thisprg);
  273.         exit(1);
  274.     }
  275.  
  276.     if (chgterm)
  277.         manage_dialup();
  278.  
  279.     if (chgprog)
  280.         manage_program();
  281.  
  282.     exit(0);
  283. }
  284.  
  285. void manage_dialup()
  286. {
  287.     FILE    *fp,
  288.         *fopen(),
  289.         *fdopen();
  290.     int    fd,
  291.         found;
  292.     int    ttyno,
  293.         i;
  294.     char    dialtty[MAX_DIALUPS][TTYLEN],
  295.         buffer[TTYLEN],
  296.         *fgets(),
  297.         *c;
  298.  
  299.     /* read in the old dialups file */
  300.     /* if it doesn't exist,then create it */
  301.  
  302.     if ((fp = fopen(dttyfile, "r")) == NULL) {
  303.  
  304.         if (debug)
  305.             (void) printf("creating %s\n", dttyfile);
  306.  
  307.         if ((fd = creat(dttyfile, DIALUPS_PERMS)) < 0) {
  308.             perror(dttyfile);
  309.             exit(1);
  310.         }
  311.  
  312.         fp = fdopen(fd, "r");
  313.     }
  314.  
  315.     found = ttyno = 0;
  316.  
  317.     /* loop thru all records and load them into array */
  318.  
  319.     while (fgets(buffer, TTYLEN, fp) != NULL) {
  320.  
  321.         /* If file is already bigger than allotted, tell user */
  322.  
  323.         if (ttyno >= MAX_DIALUPS) {
  324.             if (!quiet)
  325.             (void) printf("%s: %s is too big\n", thisprg, dttyfile);
  326.             exit(1);
  327.         }
  328.  
  329.         /* strip trailing newline */
  330.         c = strrchr(buffer, '\n');
  331.         *c = '\0';
  332.  
  333.         /* if this record matches cmd line argument then record 
  334.          * location 
  335.          */
  336.         if (strcmp(buffer, terminal) == 0)
  337.             found = ttyno + 1;
  338.  
  339.         if (debug)
  340.             (void) printf("in %d: tty:%s\n", ttyno, buffer);
  341.  
  342.         /* move record into array space */
  343.         (void) sprintf(dialtty[ttyno++], "%s", buffer);
  344.     }
  345.     (void) fclose(fp);
  346.  
  347.     /* start deleting */
  348.     if (found && delete) {
  349.         if ((fp = fopen(dttyfile, "w")) == NULL) {
  350.             perror(dttyfile);
  351.             exit(1);
  352.         }
  353.  
  354.         /* index pos was increment by one so that position 0 would have
  355.         ** a true value, i.e. 1. 
  356.         */
  357.         found--;
  358.  
  359.         /* Write out all records */
  360.  
  361.         for (i = 0; i < ttyno; i++) {
  362.  
  363.             /* If index position matches cmd line arg, then skip 
  364.             ** this one 
  365.             */
  366.             if (i != found) {
  367.             if (debug)
  368.                 (void) printf("del/out %d: tty:%s\n", i, 
  369.                     dialtty[i]);
  370.  
  371.             (void) fprintf(fp, "%s\n", dialtty[i]);
  372.             }
  373.         }
  374.         (void) fclose(fp);
  375.  
  376.         if (!quiet)
  377.             (void) 
  378.             printf("%s: Dialup terminal restriction removed from %s.\n",
  379.                 thisprg, terminal);
  380.  
  381.         /* start adding */
  382.  
  383.     } else if (!found && !delete) {
  384.  
  385.         /* If we're going to add, ensure that there is room */
  386.  
  387.         if (ttyno == MAX_DIALUPS) {
  388.             if (!quiet)
  389.             (void) printf("%s: %s is already at max size\n",
  390.                       thisprg, dttyfile);
  391.             exit(1);
  392.         }
  393.  
  394.         /* open dialups for output 
  395.         ** Could have just done an append instead of rewrite of file.
  396.         ** I don't know what author had in mind, but I'll leave it 
  397.         ** alone 
  398.         */
  399.  
  400.         if ((fp = fopen(dttyfile, "w")) == NULL) {
  401.             perror(dttyfile);
  402.             exit(1);
  403.         }
  404.  
  405.         /* loop through all records in array (old file) and write */
  406.         for (i = 0; i < ttyno; i++) {
  407.             if (debug)
  408.             (void) printf("add/out %d: tty:%s\n", i, dialtty[i]);
  409.             (void) fprintf(fp, "%s\n", dialtty[i]);
  410.         }
  411.  
  412.         /* Append new record to end */
  413.         (void) fprintf(fp, "%s\n", terminal);
  414.  
  415.         if (debug)
  416.             (void) printf("add/out %d: tty:%s\n", i, terminal);
  417.  
  418.         (void) fclose(fp);
  419.  
  420.         if (!quiet)
  421.             (void)
  422.             printf("%s: Dialup terminal restriction added for %s.\n",
  423.                 thisprg, terminal);
  424.  
  425.         /* Some error handline follows */
  426.  
  427.     } else if (!found && delete && !quiet) {
  428.         (void) printf("%s: Terminal %s not found in %s.\n",
  429.                 thisprg, terminal, dttyfile);
  430.     } else if (found && !delete && !quiet) {
  431.         (void) printf("%s: Terminal %s already found in %s.\n",
  432.                 thisprg, terminal, dttyfile);
  433.     }
  434. }
  435.  
  436. void manage_program()
  437. {
  438.     FILE    *fp,
  439.         *fopen(),
  440.         *fdopen();
  441.     int    get_password(),
  442.         fd,
  443.         found,
  444.         pswno,
  445.         i;
  446.     char    dialpsw[MAX_PROGS][DPASSWDLEN],
  447.         buffer[DPASSWDLEN],
  448.         cmpbuff[DPASSWDLEN],
  449.         *crypt(),
  450.         *fgets(),
  451.         *c;
  452.  
  453.     /* open the d_passwd file, if it doesn't exist, create it */
  454.  
  455.     if ((fp = fopen(dpswfile, "r")) == NULL) {
  456.  
  457.         if (debug)
  458.             (void) printf("creating %s\n", dpswfile);
  459.  
  460.         if ((fd = creat(dpswfile, DPASSWD_PERMS)) < 0) {
  461.             perror(dpswfile);
  462.             exit(1);
  463.         }
  464.  
  465.         fp = fdopen(fd, "r");
  466.     }
  467.  
  468.     found = pswno = 0;
  469.  
  470.     /* loop thorugh all records, then load them into array */
  471.  
  472.     while (fgets(buffer, DPASSWDLEN, fp) != NULL) {
  473.  
  474.         /* if file is already bigger than allotted then tell user */
  475.  
  476.         if (pswno >= MAX_PROGS) {
  477.             if (!quiet)
  478.             (void) printf("%s: %s is too big\n", thisprg, dpswfile);
  479.             exit(1);
  480.         }
  481.  
  482.         /* Strip trailing newline */
  483.         c = strrchr(buffer, '\n');
  484.         *c = '\0';
  485.  
  486.         /* Copy buffer of prog+pass to buffer that only uses prog */
  487.         (void) strcpy(cmpbuff, buffer);
  488.  
  489.         /* The colon separates prog from psw, so making it null turns 
  490.         ** the prog name into a separate string 
  491.         */
  492.         c = strchr(cmpbuff, ':');
  493.         *c = '\0';
  494.  
  495.         /* If this prog name matches cmnd line entry then record 
  496.         ** its location 
  497.         */
  498.         if (strcmp(cmpbuff, program) == 0)
  499.             found = pswno + 1;
  500.  
  501.         if (debug)
  502.             (void) printf("in %d: prog:%s\n", pswno, buffer);
  503.  
  504.         /* move record to array */
  505.         (void) sprintf(dialpsw[pswno++], "%s", buffer);
  506.     }
  507.     (void) fclose(fp);
  508.  
  509.     /* start deleting */
  510.  
  511.     if (found && delete) {
  512.         if ((fp = fopen(dpswfile, "w")) == NULL) {
  513.             perror(dpswfile);
  514.             exit(1);
  515.         }
  516.  
  517.         /* index pos was increment by one so that position 0 would 
  518.         ** have a true value, i.e. 1.
  519.         */
  520.         found--;
  521.  
  522.         /* Write out all records */
  523.  
  524.         for (i = 0; i < pswno; i++) {
  525.  
  526.             /* If index position matches cmd line arg, then skip 
  527.             ** this one 
  528.             */
  529.             if (i != found) {
  530.             if (debug)
  531.                 (void) printf("del/out %d: prog:%s\n", i, dialpsw[i]);
  532.             (void) fprintf(fp, "%s\n", dialpsw[i]);
  533.             }
  534.         }
  535.         (void) fclose(fp);
  536.  
  537.         if (!quiet)
  538.             (void)
  539.             printf("%s: Dialup program restriction removed from %s.\n",
  540.                 thisprg, program);
  541.  
  542.         /* start to add a program and password 
  543.         ** if program already was in file then replace it
  544.         */
  545.  
  546.     } else if (!delete) {
  547.         if (!found && pswno == MAX_PROGS) {
  548.             if (!quiet)
  549.             (void) printf("%s: %s is already at max size\n", 
  550.                 thisprg, dpswfile);
  551.             exit(1);
  552.         }
  553.  
  554.         /* initialize password */
  555.         passwd[0] = '\0';
  556.  
  557.         if (!null) 
  558.             if (get_password())
  559.                 return;
  560.  
  561.         /* Create the file for output.
  562.         ** Note, the author had this code before the password input. 
  563.         ** If the program was stopped while at the prompt, the 
  564.         ** d_passwd file would be deleted.  So, I moved it here.
  565.         ** An even better, but perhaps more involved fix would be 
  566.         ** to create a temp file, then rename the temp file back 
  567.         ** to the original 
  568.         */
  569.  
  570.         if ((fp = fopen(dpswfile, "w")) == NULL) {
  571.             perror(dpswfile);
  572.             exit(1);
  573.         }
  574.  
  575.         /* index pos was increment by one so that position 0 would have
  576.         ** a true value, i.e. 1.
  577.         */
  578.         found--;
  579.  
  580.         /* loop through array writing out all those accept the match 
  581.         ** against the input file 
  582.         */
  583.  
  584.         for (i = 0; i < pswno; i++)
  585.             if (i != found) {
  586.             if (debug)
  587.                 (void) printf("add/out %d: prog:%s\n", 
  588.                     i, dialpsw[i]);
  589.             (void) fprintf(fp, "%s\n", dialpsw[i]);
  590.             }
  591.  
  592.         if (null)
  593.             (void) fprintf(fp, "%s::\n", program);
  594.         else
  595.             (void) fprintf(fp, "%s:%s:\n", 
  596.                 program, crypt(passwd, saltc));
  597.         if (debug)
  598.             if (null)
  599.                 (void) printf("add/out %d: prog:%s::\n", 
  600.                 i, program);
  601.             else
  602.                 (void) printf("add/out %d: prog:%s:%s:\n", 
  603.                 i, program, crypt(passwd, saltc));
  604.  
  605.         (void) fclose(fp);
  606.  
  607.         /* if requested, tell user whether program was added 
  608.         ** or just changed 
  609.         */
  610.         if (!quiet) {
  611.             if (found >= 0) {
  612.             (void) printf(
  613.                 "%s: Dialup program restriction changed for %s.\n",
  614.                 thisprg, program);
  615.             } else {
  616.             (void) printf(
  617.                 "%s: Dialup program restriction added for %s.\n",
  618.                 thisprg, program);
  619.             }
  620.         }
  621.  
  622.         /* tell user about this error (if requested) */
  623.  
  624.     } else if (!found && delete && !quiet)
  625.         (void) printf("%s: Program %s not found in %s.\n",
  626.                   thisprg, program, dpswfile);
  627.  
  628. }
  629.  
  630. int get_password()
  631. {
  632.     int    i,
  633.         d,
  634.         bad,
  635.            match;
  636.     char    *getpass(),
  637.         retype[PSWLEN];
  638.  
  639.     /* keep getting passwords (as long as the user didn't ask for
  640.     ** a null password entry) until user gets it right or until
  641.     ** attempt counter reaches maximum 
  642.     */
  643.     bad = 0;
  644.  
  645.     do {
  646.         /* get password - repeat if user just presses return */
  647.         do {
  648.  
  649.             (void) sprintf(passwd, "%s", 
  650.                 getpass("New Dialup Password:"));
  651.         } while (*passwd == '\0');
  652.  
  653.         /* get it again so that we can be sure that there 
  654.         ** are no typos 
  655.         */
  656.         (void) sprintf(retype, "%s", 
  657.                 getpass("Retype Dialup Password:"));
  658.  
  659.         /* was there a typo?  if so, count this as a failed 
  660.         ** attempt 
  661.         */
  662.         if ((match = strcmp(passwd, retype)) != 0) {
  663.             (void) printf("They don't match; try again.\n\n");
  664.             bad++;
  665.         }
  666.  
  667.     } while (match != 0 && bad < PSWATTEMPTS);
  668.  
  669.     /* return user to caller if he just cannot get it right */
  670.     if (bad == PSWATTEMPTS) {
  671.         (void) printf("Too many tries; try again later.\n\n");
  672.         return 1;
  673.     }
  674.  
  675.     /* Construct salt, then encrypt the new password */
  676.     (void) time(&salt);
  677.     salt += getpid();
  678.  
  679.     /* Make sure the new key doesn't have the first two letters
  680.     ** of the password in it, and only allow valid characters
  681.     ** . / 0-9 A-Z a-z
  682.     */
  683.     saltc[0] = salt & 007;
  684.     saltc[1] = (salt >> 6) & 077;
  685.     for (i = 0; i < 2; i++) {
  686.         d = saltc[i] + '.';
  687.         if (d > '9')
  688.             d += 7;
  689.         if (d > 'Z')
  690.             d += 6;
  691.         saltc[i] = d;
  692.     }
  693.     return 0;
  694. }
  695.  
  696. #ifndef lint
  697. static    char sccsid[] = "@(#)dpasswd.c    Version 2.0";
  698. #endif
  699.