formatting
[citadel] / 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; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License, version 3.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14
15 #if defined(__linux) || defined(__sun)  // needed for crypt():
16 #define _XOPEN_SOURCE
17 #define _XOPEN_SOURCE_EXTENDED 1
18 #endif
19
20 #include <pwd.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25
26 #include "auth.h"
27 #include "sysdep.h"
28
29 #ifdef HAVE_GETSPNAM
30 #include <shadow.h>
31 #endif
32
33 #ifdef HAVE_PAM_START
34 #include <security/pam_appl.h>
35
36 // struct appdata: passed to the conversation function
37 struct appdata {
38         const char *name;
39         const char *pw;
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 static int conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr) {
48         struct pam_response *temp_resp;
49         struct appdata *data = appdata_ptr;
50
51         if ((temp_resp =
52              malloc(sizeof(struct pam_response[num_msg]))) == NULL)
53                 return PAM_CONV_ERR;
54
55         while (num_msg--) {
56                 switch ((*msg)[num_msg].msg_style) {
57                 case PAM_PROMPT_ECHO_ON:
58                         temp_resp[num_msg].resp = strdup(data->name);
59                         break;
60                 case PAM_PROMPT_ECHO_OFF:
61                         temp_resp[num_msg].resp = strdup(data->pw);
62                         break;
63                 default:
64                         temp_resp[num_msg].resp = NULL;
65                 }
66                 temp_resp[num_msg].resp_retcode = 0;
67         }
68
69         *resp = temp_resp;
70         return PAM_SUCCESS;
71 }
72 #endif                          // HAVE_PAM_START
73
74
75 // check that `pass' is the correct password for `uid'
76 // returns zero if no, nonzero if yes
77 int validate_password(uid_t uid, const char *pass) {
78         if (pass == NULL) {
79                 return (0);
80         }
81 #ifdef HAVE_PAM_START
82         struct pam_conv pc;
83         struct appdata data;
84         pam_handle_t *ph;
85         int i;
86 #else
87         char *crypted_pwd;
88 #ifdef HAVE_GETSPNAM
89         struct spwd *sp;
90 #endif
91 #endif
92         struct passwd *pw;
93         int retval = 0;
94
95         pw = getpwuid(uid);
96         if (pw == NULL) {
97                 return retval;
98         }
99 #ifdef HAVE_PAM_START
100
101 #ifdef PAM_DATA_SILENT
102         int flags = PAM_DATA_SILENT;
103 #else
104         int flags = 0;
105 #endif
106
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 (0);
113
114         if ((i = pam_authenticate(ph, flags)) == PAM_SUCCESS) {
115                 if ((i = pam_acct_mgmt(ph, flags)) == PAM_SUCCESS) {
116                         retval = -1;
117                 }
118         }
119
120         pam_end(ph, i | flags);
121 #else
122         crypted_pwd = pw->pw_passwd;
123
124 #ifdef HAVE_GETSPNAM
125         if (pw == NULL)
126                 return (0);
127         if (pw->pw_name == NULL)
128                 return (0);
129         if ((sp = getspnam(pw->pw_name)) != NULL) {
130                 crypted_pwd = sp->sp_pwdp;
131         }
132 #endif
133
134         if (!strcmp(crypt(pass, crypted_pwd), crypted_pwd)) {
135                 retval = -1;
136         }
137 #endif                          // HAVE_PAM_START
138
139         return retval;
140 }