248b74bbea3162a2963e7a5ab8b3366fe0cff27a
[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
42 struct appdata
43 {
44   const char *name;
45   const char *pw;
46 };
47
48 /*
49  * conv(): the PAM conversation function. this assumes that a
50  * PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is
51  * asking for a password. esoteric authentication modules will fail with this
52  * code, but we can't really support them with the existing client protocol
53  * anyway. the failure mode should be to deny access, in any case.
54  */
55
56 static int conv(int num_msg, const struct pam_message **msg,
57                 struct pam_response **resp, void *appdata_ptr)
58 {
59   struct pam_response *temp_resp;
60   struct appdata *data = appdata_ptr;
61
62   if ((temp_resp = malloc(sizeof(struct pam_response[num_msg]))) == NULL)
63     return PAM_CONV_ERR;
64
65   while (num_msg--)
66     {
67       switch ((*msg)[num_msg].msg_style)
68         {
69         case PAM_PROMPT_ECHO_ON:
70           temp_resp[num_msg].resp = strdup(data->name);
71           break;
72         case PAM_PROMPT_ECHO_OFF:
73           temp_resp[num_msg].resp = strdup(data->pw);
74           break;
75         default:
76           temp_resp[num_msg].resp = NULL;
77         }
78       temp_resp[num_msg].resp_retcode = 0;
79     }
80
81   *resp = temp_resp;
82   return PAM_SUCCESS;
83 }
84 #endif /* HAVE_PAM_START */
85
86
87 /*
88  * check that `pass' is the correct password for `uid'
89  * returns zero if no, nonzero if yes
90  */
91
92 int validate_password(uid_t uid, const char *pass)
93 {
94         if (pass == NULL) {
95                 return(0);
96         }
97
98 #ifdef HAVE_PAM_START
99         struct pam_conv pc;
100         struct appdata data;
101         pam_handle_t *ph;
102         int i;
103 #else
104         char *crypted_pwd;
105 #ifdef HAVE_GETSPNAM
106         struct spwd *sp;
107 #endif
108 #endif
109         struct passwd *pw;
110         int retval = 0;
111
112         pw = getpwuid(uid);
113         if (pw == NULL) {
114                 return retval;
115         }
116
117 #ifdef HAVE_PAM_START
118
119 #ifdef PAM_DATA_SILENT
120         int flags = PAM_DATA_SILENT;
121 #else
122         int flags = 0;
123 #endif
124
125         pc.conv = conv;
126         pc.appdata_ptr = &data;
127         data.name = pw->pw_name;
128         data.pw = pass;
129         if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
130                 return(0);
131
132         if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS) {
133                 if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS) {
134                         retval = -1;
135                 }
136         }
137
138         pam_end(ph, i | flags);
139 #else
140         crypted_pwd = pw->pw_passwd;
141
142 #ifdef HAVE_GETSPNAM
143         if (pw == NULL) return(0);
144         if (pw->pw_name == NULL) return(0);
145         if ((sp = getspnam(pw->pw_name)) != NULL) {
146                 crypted_pwd = sp->sp_pwdp;
147         }
148 #endif
149
150         if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd)) {
151                 retval = -1;
152         }
153 #endif                          /* HAVE_PAM_START */
154
155         return retval;
156 }