Merge from vendor branch CVS:
[dragonfly.git] / crypto / heimdal-0.6.3 / appl / popper / pop_pass.c
1 /*
2  * Copyright (c) 1989 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6
7 #include <popper.h>
8 RCSID("$Id: pop_pass.c,v 1.41 2000/04/12 15:37:46 assar Exp $");
9
10 #ifdef KRB4
11 static int
12 krb4_verify_password (POP *p)
13 {
14     int status;
15     char lrealm[REALM_SZ];
16     char tkt[MaxPathLen];
17
18     status = krb_get_lrealm(lrealm,1);
19     if (status == KFAILURE) {
20         pop_log(p, POP_PRIORITY, "%s: (%s.%s@%s) %s", p->client,
21                 p->kdata.pname, p->kdata.pinst, p->kdata.prealm,
22                 krb_get_err_text(status));
23         return 1;
24     }
25     snprintf(tkt, sizeof(tkt), "%s_popper.%u", TKT_ROOT, (unsigned)getpid());
26     krb_set_tkt_string (tkt);
27
28     status = krb_verify_user(p->user, "", lrealm,
29                              p->pop_parm[1], KRB_VERIFY_SECURE, "pop");
30     dest_tkt(); /* no point in keeping the tickets */
31     return status;
32 }
33 #endif /* KRB4 */
34
35 #ifdef KRB5
36 static int
37 krb5_verify_password (POP *p)
38 {
39     krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP};
40     krb5_get_init_creds_opt get_options;
41     krb5_verify_init_creds_opt verify_options;
42     krb5_error_code ret;
43     krb5_principal client, server;
44     krb5_creds creds;
45
46     krb5_get_init_creds_opt_init (&get_options);
47
48     krb5_get_init_creds_opt_set_preauth_list (&get_options,
49                                               pre_auth_types,
50                                               1);
51
52     krb5_verify_init_creds_opt_init (&verify_options);
53     
54     ret = krb5_parse_name (p->context, p->user, &client);
55     if (ret) {
56         pop_log(p, POP_PRIORITY, "krb5_parse_name: %s",
57                 krb5_get_err_text (p->context, ret));
58         return 1;
59     }
60
61     ret = krb5_get_init_creds_password (p->context,
62                                         &creds,
63                                         client,
64                                         p->pop_parm[1],
65                                         NULL,
66                                         NULL,
67                                         0,
68                                         NULL,
69                                         &get_options);
70     if (ret) {
71         pop_log(p, POP_PRIORITY,
72                 "krb5_get_init_creds_password: %s",
73                 krb5_get_err_text (p->context, ret));
74         return 1;
75     }
76
77     ret = krb5_sname_to_principal (p->context,
78                                    p->myhost,
79                                    "pop",
80                                    KRB5_NT_SRV_HST,
81                                    &server);
82     if (ret) {
83         pop_log(p, POP_PRIORITY,
84                 "krb5_get_init_creds_password: %s",
85                 krb5_get_err_text (p->context, ret));
86         return 1;
87     }
88
89     ret = krb5_verify_init_creds (p->context,
90                                   &creds,
91                                   server,
92                                   NULL,
93                                   NULL,
94                                   &verify_options);
95     krb5_free_principal (p->context, client);
96     krb5_free_principal (p->context, server);
97     krb5_free_creds_contents (p->context, &creds);
98     return ret;
99 }
100 #endif
101 /* 
102  *  pass:   Obtain the user password from a POP client
103  */
104
105 int
106 pop_pass (POP *p)
107 {
108     struct passwd  *pw;
109     int i;
110     struct stat st;
111
112     /* Make one string of all these parameters */
113     
114     for (i = 1; i < p->parm_count; ++i)
115         p->pop_parm[i][strlen(p->pop_parm[i])] = ' ';
116
117     /*  Look for the user in the password file */
118     if ((pw = k_getpwnam(p->user)) == NULL)
119         return (pop_msg(p,POP_FAILURE,
120                         "Password supplied for \"%s\" is incorrect.",
121                         p->user));
122
123     if (p->kerberosp) {
124 #ifdef KRB4
125         if (p->version == 4) {
126             if(kuserok (&p->kdata, p->user)) {
127                 pop_log(p, POP_PRIORITY,
128                         "%s: (%s.%s@%s) tried to retrieve mail for %s.",
129                         p->client, p->kdata.pname, p->kdata.pinst,
130                         p->kdata.prealm, p->user);
131                 return(pop_msg(p,POP_FAILURE,
132                                "Popping not authorized"));
133             }
134             pop_log(p, POP_INFO, "%s: %s.%s@%s -> %s",
135                     p->ipaddr,
136                     p->kdata.pname, p->kdata.pinst, p->kdata.prealm,
137                     p->user);
138         } else
139 #endif /* KRB4 */
140 #ifdef KRB5
141         if (p->version == 5) {
142             char *name;
143             
144             if (!krb5_kuserok (p->context, p->principal, p->user)) {
145                 pop_log (p, POP_PRIORITY,
146                          "krb5 permission denied");
147                 return pop_msg(p, POP_FAILURE,
148                                "Popping not authorized");
149             }
150             if(krb5_unparse_name (p->context, p->principal, &name) == 0) {
151                 pop_log(p, POP_INFO, "%s: %s -> %s",
152                         p->ipaddr, name, p->user);
153                 free (name);
154             }
155         } else {
156             pop_log (p, POP_PRIORITY, "kerberos authentication failed");
157             return pop_msg (p, POP_FAILURE,
158                             "kerberos authentication failed");
159         }
160 #endif
161         { }
162     } else {
163          /*  We don't accept connections from users with null passwords */
164          if (pw->pw_passwd == NULL)
165               return (pop_msg(p,
166                               POP_FAILURE,
167                               "Password supplied for \"%s\" is incorrect.",
168                               p->user));
169
170 #ifdef OTP
171          if (otp_verify_user (&p->otp_ctx, p->pop_parm[1]) == 0)
172              /* pass OK */;
173          else
174 #endif
175          /*  Compare the supplied password with the password file entry */
176          if (p->auth_level != AUTH_NONE)
177              return pop_msg(p, POP_FAILURE,
178                             "Password supplied for \"%s\" is incorrect.",
179                             p->user);
180          else if (!strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd))
181              /* pass OK */;
182          else {
183              int ret = -1;
184 #ifdef KRB4
185              ret = krb4_verify_password (p);
186 #endif
187 #ifdef KRB5
188              if(ret)
189                  ret = krb5_verify_password (p);
190 #endif
191              if(ret)
192                  return pop_msg(p, POP_FAILURE,
193                                 "Password incorrect");
194          }
195     }
196     pop_log(p, POP_INFO, "login from %s as %s",
197             p->ipaddr, p->user);
198
199     /*  Build the name of the user's maildrop */
200     snprintf(p->drop_name, sizeof(p->drop_name), "%s/%s", POP_MAILDIR, p->user);
201
202     if(stat(p->drop_name, &st) < 0 || !S_ISDIR(st.st_mode)){
203         /*  Make a temporary copy of the user's maildrop */
204         /*    and set the group and user id */
205         if (pop_dropcopy(p, pw) != POP_SUCCESS) return (POP_FAILURE);
206         
207         /*  Get information about the maildrop */
208         if (pop_dropinfo(p) != POP_SUCCESS) return(POP_FAILURE);
209     } else {
210         if(changeuser(p, pw) != POP_SUCCESS) return POP_FAILURE;
211         if(pop_maildir_info(p) != POP_SUCCESS) return POP_FAILURE;
212     }
213     /*  Initialize the last-message-accessed number */
214     p->last_msg = 0;
215
216     /*  Authorization completed successfully */
217     return (pop_msg (p, POP_SUCCESS,
218                      "%s has %d message(s) (%ld octets).",
219                      p->user, p->msg_count, p->drop_size));
220 }