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#ifdef HAVE_CRYPT_H
9#include <crypt.h>
10#endif
11
12RCSID("$Id$");
13
14#ifdef KRB5
15static int
16krb5_verify_password (POP *p)
17{
18    krb5_preauthtype pre_auth_types[] = {KRB5_PADATA_ENC_TIMESTAMP};
19    krb5_get_init_creds_opt *get_options;
20    krb5_verify_init_creds_opt verify_options;
21    krb5_error_code ret;
22    krb5_principal client, server;
23    krb5_creds creds;
24
25    ret = krb5_get_init_creds_opt_alloc (p->context, &get_options);
26    if (ret) {
27	pop_log(p, POP_PRIORITY, "krb5_get_init_creds_opt_alloc: %s",
28		krb5_get_err_text (p->context, ret));
29	return 1;
30    }
31
32    krb5_get_init_creds_opt_set_preauth_list (get_options,
33					      pre_auth_types,
34					      1);
35
36    krb5_verify_init_creds_opt_init (&verify_options);
37
38    ret = krb5_parse_name (p->context, p->user, &client);
39    if (ret) {
40	krb5_get_init_creds_opt_free(p->context, get_options);
41	pop_log(p, POP_PRIORITY, "krb5_parse_name: %s",
42		krb5_get_err_text (p->context, ret));
43	return 1;
44    }
45
46    ret = krb5_get_init_creds_password (p->context,
47					&creds,
48					client,
49					p->pop_parm[1],
50					NULL,
51					NULL,
52					0,
53					NULL,
54					get_options);
55    krb5_get_init_creds_opt_free(p->context, get_options);
56    if (ret) {
57	pop_log(p, POP_PRIORITY,
58		"krb5_get_init_creds_password: %s",
59		krb5_get_err_text (p->context, ret));
60	return 1;
61    }
62
63    ret = krb5_sname_to_principal (p->context,
64				   p->myhost,
65				   "pop",
66				   KRB5_NT_SRV_HST,
67				   &server);
68    if (ret) {
69	pop_log(p, POP_PRIORITY,
70		"krb5_get_init_creds_password: %s",
71		krb5_get_err_text (p->context, ret));
72	return 1;
73    }
74
75    ret = krb5_verify_init_creds (p->context,
76				  &creds,
77				  server,
78				  NULL,
79				  NULL,
80				  &verify_options);
81    krb5_free_principal (p->context, client);
82    krb5_free_principal (p->context, server);
83    krb5_free_cred_contents (p->context, &creds);
84    return ret;
85}
86#endif
87/*
88 *  pass:   Obtain the user password from a POP client
89 */
90
91int
92login_user(POP *p)
93{
94    struct stat st;
95    struct passwd *pw;
96
97    /*  Look for the user in the password file */
98    if ((pw = k_getpwnam(p->user)) == NULL) {
99	pop_log(p, POP_PRIORITY, "user %s (from %s) not found",
100		p->user, p->ipaddr);
101	return pop_msg(p, POP_FAILURE, "Login incorrect.");
102    }
103
104    pop_log(p, POP_INFO, "login from %s as %s", p->ipaddr, p->user);
105
106    /*  Build the name of the user's maildrop */
107    snprintf(p->drop_name, sizeof(p->drop_name), "%s/%s", POP_MAILDIR, p->user);
108    if(stat(p->drop_name, &st) < 0 || !S_ISDIR(st.st_mode)){
109	/*  Make a temporary copy of the user's maildrop */
110	/*    and set the group and user id */
111	if (pop_dropcopy(p, pw) != POP_SUCCESS) return (POP_FAILURE);
112
113	/*  Get information about the maildrop */
114	if (pop_dropinfo(p) != POP_SUCCESS) return(POP_FAILURE);
115    } else {
116	if(changeuser(p, pw) != POP_SUCCESS) return POP_FAILURE;
117	if(pop_maildir_info(p) != POP_SUCCESS) return POP_FAILURE;
118    }
119    /*  Initialize the last-message-accessed number */
120    p->last_msg = 0;
121    return POP_SUCCESS;
122}
123
124int
125pop_pass (POP *p)
126{
127    struct passwd  *pw;
128    int i;
129    int status;
130
131    /* Make one string of all these parameters */
132
133    for (i = 1; i < p->parm_count; ++i)
134	p->pop_parm[i][strlen(p->pop_parm[i])] = ' ';
135
136    /*  Look for the user in the password file */
137    if ((pw = k_getpwnam(p->user)) == NULL)
138	return (pop_msg(p,POP_FAILURE,
139			"Password supplied for \"%s\" is incorrect.",
140			p->user));
141
142    if (p->kerberosp) {
143#ifdef KRB5
144	if (p->version == 5) {
145	    char *name;
146
147	    if (!krb5_kuserok (p->context, p->principal, p->user)) {
148		pop_log (p, POP_PRIORITY,
149			 "krb5 permission denied");
150		return pop_msg(p, POP_FAILURE,
151			       "Popping not authorized");
152	    }
153	    if(krb5_unparse_name (p->context, p->principal, &name) == 0) {
154		pop_log(p, POP_INFO, "%s: %s -> %s",
155			p->ipaddr, name, p->user);
156		free (name);
157	    }
158	} else {
159	    pop_log (p, POP_PRIORITY, "kerberos authentication failed");
160	    return pop_msg (p, POP_FAILURE,
161			    "kerberos authentication failed");
162	}
163#endif
164	{ }
165    } else {
166	 /*  We don't accept connections from users with null passwords */
167	 if (pw->pw_passwd == NULL)
168	      return (pop_msg(p,
169			      POP_FAILURE,
170			      "Password supplied for \"%s\" is incorrect.",
171			      p->user));
172
173#ifdef OTP
174	 if (otp_verify_user (&p->otp_ctx, p->pop_parm[1]) == 0)
175	     /* pass OK */;
176	 else
177#endif
178	 /*  Compare the supplied password with the password file entry */
179	 if (p->auth_level != AUTH_NONE)
180	     return pop_msg(p, POP_FAILURE,
181			    "Password supplied for \"%s\" is incorrect.",
182			    p->user);
183	 else if (!strcmp(crypt(p->pop_parm[1], pw->pw_passwd), pw->pw_passwd))
184	     /* pass OK */;
185	 else {
186	     int ret = -1;
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    status = login_user(p);
197    if(status != POP_SUCCESS)
198	return status;
199
200    /*  Authorization completed successfully */
201    return (pop_msg (p, POP_SUCCESS,
202		     "%s has %d message(s) (%ld octets).",
203		     p->user, p->msg_count, p->drop_size));
204}
205