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