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