Mailing list header changes (fuck you Google)
[citadel.git] / citadel / auth.c
1 /*
2  * system-level password checking for host auth mode
3  * by Nathan Bryant, March 1999
4  * updated by Trey van Riper, June 2005
5  *
6  * Copyright (c) 1999-2016 by the citadel.org team
7  *
8  * This program is open source software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License, version 3.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16
17 #if defined(__linux) || defined(__sun)  /* needed for crypt(): */
18 #define _XOPEN_SOURCE
19 #define _XOPEN_SOURCE_EXTENDED 1
20 #endif
21
22 #include <pwd.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/types.h>
27
28 #include "auth.h"
29 #include "sysdep.h"
30
31 #ifdef HAVE_GETSPNAM
32 #include <shadow.h>
33 #endif
34
35 #ifdef HAVE_PAM_START
36 #include <security/pam_appl.h>
37
38 /*
39  * struct appdata: passed to the conversation function
40  */
41 struct appdata {
42         const char *name;
43         const char *pw;
44 };
45
46 /*
47  * conv(): the PAM conversation function. this assumes that a
48  * PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is
49  * asking for a password. esoteric authentication modules will fail with this
50  * code, but we can't really support them with the existing client protocol
51  * anyway. the failure mode should be to deny access, in any case.
52  */
53 static int conv(int num_msg, const struct pam_message **msg,
54                 struct pam_response **resp, void *appdata_ptr)
55 {
56         struct pam_response *temp_resp;
57         struct appdata *data = appdata_ptr;
58
59         if ((temp_resp =
60              malloc(sizeof(struct pam_response[num_msg]))) == NULL)
61                 return PAM_CONV_ERR;
62
63         while (num_msg--) {
64                 switch ((*msg)[num_msg].msg_style) {
65                 case PAM_PROMPT_ECHO_ON:
66                         temp_resp[num_msg].resp = strdup(data->name);
67                         break;
68                 case PAM_PROMPT_ECHO_OFF:
69                         temp_resp[num_msg].resp = strdup(data->pw);
70                         break;
71                 default:
72                         temp_resp[num_msg].resp = NULL;
73                 }
74                 temp_resp[num_msg].resp_retcode = 0;
75         }
76
77         *resp = temp_resp;
78         return PAM_SUCCESS;
79 }
80 #endif                          /* HAVE_PAM_START */
81
82
83 /*
84  * check that `pass' is the correct password for `uid'
85  * returns zero if no, nonzero if yes
86  */
87 int validate_password(uid_t uid, const char *pass)
88 {
89         if (pass == NULL) {
90                 return (0);
91         }
92 #ifdef HAVE_PAM_START
93         struct pam_conv pc;
94         struct appdata data;
95         pam_handle_t *ph;
96         int i;
97 #else
98         char *crypted_pwd;
99 #ifdef HAVE_GETSPNAM
100         struct spwd *sp;
101 #endif
102 #endif
103         struct passwd *pw;
104         int retval = 0;
105
106         pw = getpwuid(uid);
107         if (pw == NULL) {
108                 return retval;
109         }
110 #ifdef HAVE_PAM_START
111
112 #ifdef PAM_DATA_SILENT
113         int flags = PAM_DATA_SILENT;
114 #else
115         int flags = 0;
116 #endif
117
118         pc.conv = conv;
119         pc.appdata_ptr = &data;
120         data.name = pw->pw_name;
121         data.pw = pass;
122         if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
123                 return (0);
124
125         if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS) {
126                 if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS) {
127                         retval = -1;
128                 }
129         }
130
131         pam_end(ph, i | flags);
132 #else
133         crypted_pwd = pw->pw_passwd;
134
135 #ifdef HAVE_GETSPNAM
136         if (pw == NULL)
137                 return (0);
138         if (pw->pw_name == NULL)
139                 return (0);
140         if ((sp = getspnam(pw->pw_name)) != NULL) {
141                 crypted_pwd = sp->sp_pwdp;
142         }
143 #endif
144
145         if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd)) {
146                 retval = -1;
147         }
148 #endif                          /* HAVE_PAM_START */
149
150         return retval;
151 }