74fa9ebc321b6814ac3bab1bed45e6095b41d6a2
[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-2009 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 #ifdef HAVE_PAM_START
95         struct pam_conv pc;
96         struct appdata data;
97         pam_handle_t *ph;
98         int i;
99 #else
100         char *crypted_pwd;
101 #ifdef HAVE_GETSPNAM
102         struct spwd *sp;
103 #endif
104 #endif
105         struct passwd *pw;
106         int retval = 0;
107
108         if ((pw = getpwuid(uid)) == NULL) {
109                 return retval;
110         }
111
112 #ifdef HAVE_PAM_START
113
114 #ifdef PAM_DATA_SILENT
115         int flags = PAM_DATA_SILENT;
116 #else
117         int flags = 0;
118 #endif /* PAM_DATA_SILENT */
119
120         pc.conv = conv;
121         pc.appdata_ptr = &data;
122         data.name = pw->pw_name;
123         data.pw = pass;
124         if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
125                 return retval;
126
127         if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS)
128                 if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS)
129                         retval = -1;
130
131         pam_end(ph, i | flags);
132 #else
133         crypted_pwd = pw->pw_passwd;
134
135 #ifdef HAVE_GETSPNAM
136         if ((sp = getspnam(pw->pw_name)) != NULL)
137                 crypted_pwd = sp->sp_pwdp;
138 #endif
139
140         if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd))
141                 retval = -1;
142 #endif                          /* HAVE_PAM_START */
143
144         return retval;
145 }