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