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