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