a689c9006634c56711bf6717096cc193c9bc7d8a
[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  */
9
10 #if defined(__linux) || defined(__sun) /* needed for crypt(): */
11 #define _XOPEN_SOURCE
12 #define _XOPEN_SOURCE_EXTENDED 1
13 #endif
14
15 #include <pwd.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20
21 #include "auth.h"
22 #include "sysdep.h"
23
24 #ifdef HAVE_GETSPNAM
25 #include <shadow.h>
26 #endif
27
28 #ifdef HAVE_PAM_START
29 #include <security/pam_appl.h>
30
31 /*
32  * struct appdata: passed to the conversation function
33  */
34
35 struct appdata
36 {
37   const char *name;
38   const char *pw;
39 };
40
41 /*
42  * conv(): the PAM conversation function. this assumes that a
43  * PAM_PROMPT_ECHO_ON is asking for a username, and a PAM_PROMPT_ECHO_OFF is
44  * asking for a password. esoteric authentication modules will fail with this
45  * code, but we can't really support them with the existing client protocol
46  * anyway. the failure mode should be to deny access, in any case.
47  */
48
49 static int conv(int num_msg, const struct pam_message **msg,
50                 struct pam_response **resp, void *appdata_ptr)
51 {
52   struct pam_response *temp_resp;
53   struct appdata *data = appdata_ptr;
54
55   if ((temp_resp = malloc(sizeof(struct pam_response[num_msg]))) == NULL)
56     return PAM_CONV_ERR;
57
58   while (num_msg--)
59     {
60       switch ((*msg)[num_msg].msg_style)
61         {
62         case PAM_PROMPT_ECHO_ON:
63           temp_resp[num_msg].resp = strdup(data->name);
64           break;
65         case PAM_PROMPT_ECHO_OFF:
66           temp_resp[num_msg].resp = strdup(data->pw);
67           break;
68         default:
69           temp_resp[num_msg].resp = NULL;
70         }
71       temp_resp[num_msg].resp_retcode = 0;
72     }
73
74   *resp = temp_resp;
75   return PAM_SUCCESS;
76 }
77 #endif /* HAVE_PAM_START */
78
79
80 /*
81  * check that `pass' is the correct password for `uid'
82  * returns zero if no, nonzero if yes
83  */
84
85 int validate_password(uid_t uid, const char *pass)
86 {
87 #ifdef HAVE_PAM_START
88         struct pam_conv pc;
89         struct appdata data;
90         pam_handle_t *ph;
91         int i;
92 #else
93         char *crypted_pwd;
94 #ifdef HAVE_GETSPNAM
95         struct spwd *sp;
96 #endif
97 #endif
98         struct passwd *pw;
99         int retval = 0;
100         int flags = 0;
101
102         flags = 0;      /* silences compiler warning */
103
104 #ifdef PAM_DATA_SILENT
105         flags = ( flags | PAM_DATA_SILENT ) ;
106 #endif /* PAM_DATA_SILENT */
107         if ((pw = getpwuid(uid)) == NULL) {
108                 return retval;
109         }
110
111 #ifdef HAVE_PAM_START
112         pc.conv = conv;
113         pc.appdata_ptr = &data;
114         data.name = pw->pw_name;
115         data.pw = pass;
116         if (pam_start("citadel", pw->pw_name, &pc, &ph) != PAM_SUCCESS)
117                 return retval;
118
119         if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS)
120                 if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS)
121                         retval = -1;
122
123         pam_end(ph, i | flags);
124 #else
125         crypted_pwd = pw->pw_passwd;
126
127 #ifdef HAVE_GETSPNAM
128         if ((sp = getspnam(pw->pw_name)) != NULL)
129                 crypted_pwd = sp->sp_pwdp;
130 #endif
131
132         if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd))
133                 retval = -1;
134 #endif                          /* HAVE_PAM_START */
135
136         return retval;
137 }
138