chiark / gitweb /
Merge branch 'master' of login.chiark.greenend.org.uk:public-git/inn-innduct
[inn-innduct.git] / contrib / auth_pass.c
1 /*
2  *      auth_pass.c  ( $Revision: 6141 $ )
3  *
4  * Abstract: 
5  *
6  *      This module is the complete source for a sample "authinfo generic" 
7  *      program.  This program takes a user's login name and password
8  *      (supplied either as arguments or as responses to prompts) and
9  *      validates them against the contents of the password database.  
10  *
11  *      If the user properly authenticates themselves, a nnrp.auth style
12  *      record indicating the user's authenticated login and permitting
13  *      reading and posting to all groups is output on stderr (for reading by
14  *      nnrpd) and the program exits with a 0 status.  If the user fails to
15  *      authenticate, then a record with the attempted login name and no
16  *      access is output on stderr and a non-zero exit status is returned.
17  *
18  * Exit statuses:
19  *      0       Successfully authenticated.
20  *      1       getpeername() failed, returned a bad address family, or 
21  *              gethostbyaddr() failed.
22  *      2       Entry not found in password file.
23  *      3       No permission to read passwords, or password field is '*'.
24  *      4       Bad password match.
25  *
26  * Environment:
27  *      Run by nnrpd with stdin/stdout connected to the reader and stderr
28  *      connected back to nnrpd.  This program will need to be run as suid
29  *      root on systems where passwords are stored in a file readable only by
30  *      root. 
31  *
32  * Written 1996 July 6 by Douglas Wade Needham (dneedham@oucsace.cs.ohiou.edu).
33  *      
34  */
35
36 #include "config.h"
37 #include "clibrary.h"
38 #include "portable/socket.h"
39 #include <netdb.h>
40 #include <pwd.h>
41
42 \f
43 main(int argc, char** argv)
44 /*+
45  * Abstract:
46  *      Main routine of the program, implementing all prompting, validation, 
47  *      and status returns.
48  *
49  * Arguments:
50  *      argc            Argument count.
51  *      argv            Null terminated argument vector.
52  *
53  * Returns:
54  *      Exits according to program status values.
55  *
56  * Variables:
57  *      hp              Pointer to host entry.
58  *      length          General integer variable
59  *      password        Password given by user.
60  *      peername        Hostname of the peer.
61  *      pwd             Pointer to entry from passwd file.
62  *      sin             Socket address structure.
63  *      username        User's login name.
64  */
65 {
66     struct hostent *    hp;
67     int                 length;
68     char                password[256];
69     char                peername[1024];
70     struct passwd *     pwd;
71     struct sockaddr_in  sin;
72     char                username[32];
73
74     /*
75      * Get the user name and password if needed.  
76      */
77     if (argc<2) {
78         fprintf(stdout, "Username: "); fflush(stdout);
79         fgets(username, sizeof(username), stdin);
80     } else {
81         strlcpy(username, argv[1], sizeof(username));
82     }
83     if (argc<3) {
84         fprintf(stdout, "Password: "); fflush(stdout);
85         fgets(password, sizeof(password), stdin);
86     } else {
87         strlcpy(password, argv[2], sizeof(password));
88     }
89     
90     /*
91      *  Strip CR's and NL's from the end.
92      */
93     length = strlen(username)-1;
94     while (username[length] == '\r' || username[length] == '\n') {
95         username[length--] = '\0';
96     }
97     length = strlen(password)-1;
98     while (password[length] == '\r' || password[length] == '\n') {
99         password[length--] = '\0';
100     }
101
102     /*
103      *  Get the hostname of the peer.
104      */
105     length = sizeof(sin);
106     if (getpeername(0, (struct sockaddr *)&sin, &length) < 0) {
107         if (!isatty(0)) {
108             fprintf(stderr, "cant getpeername()::%s:+:!*\n", username);
109             exit(1);
110         }
111         strlcpy(peername, "stdin", sizeof(peername));
112     } else if (sin.sin_family != AF_INET) {
113         fprintf(stderr, "Bad address family %ld::%s:+:!*\n",
114                 (long)sin.sin_family, username);
115         exit(1);
116     } else if ((hp = gethostbyaddr((char *)&sin.sin_addr, sizeof(sin.sin_addr), AF_INET)) == NULL) {
117         strlcpy(peername, inet_ntoa(sin.sin_addr), sizeof(peername));
118     } else {
119         strlcpy(peername, hp->h_name, sizeof(peername));
120     }
121    
122     /*
123      *  Get the user name in the passwd file.
124      */
125     if ((pwd = getpwnam(username)) == NULL) {
126
127         /*
128          *  No entry in the passwd file.
129          */
130         fprintf(stderr, "%s::%s:+:!*\n", peername, username);
131         exit(2);
132     }
133
134     /*
135      *  Make sure we managed to read in the password.
136      */
137     if (strcmp(pwd->pw_passwd, "*")==0) {
138
139         /*
140          *  No permission to read passwords.
141          */
142         fprintf(stderr, "%s::%s:+:!*\n", peername, username);
143         exit(3);
144     }
145
146     /*
147      *  Verify the password.
148      */
149     if (strcmp(pwd->pw_passwd, crypt(password, pwd->pw_passwd))!=0) {
150
151         /*
152          * Password was invalid.
153          */
154         fprintf(stderr, "%s::%s:+:!*\n", peername, username);
155         exit(4);
156     }
157
158     /*
159      *  We managed to authenticate the user.
160      */
161     fprintf(stderr, "%s:RP:%s:+:*\n", peername, username);
162     exit(0);
163 }