Store some path names in global variables initialized to configure
[tprouty/samba.git] / source / pam_smbpass / pam_smb_auth.c
1 /* Unix NT password database implementation, version 0.7.5.
2  *
3  * This program is free software; you can redistribute it and/or modify it under
4  * the terms of the GNU General Public License as published by the Free
5  * Software Foundation; either version 2 of the License, or (at your option)
6  * any later version.
7  *
8  * This program is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc., 675
15  * Mass Ave, Cambridge, MA 02139, USA.
16 */
17
18 /* indicate the following groups are defined */
19 #define PAM_SM_AUTH
20
21 #include "includes.h"
22 #include "debug.h"
23
24 #ifndef LINUX
25
26 /* This is only used in the Sun implementation. */
27 #include <security/pam_appl.h>
28
29 #endif  /* LINUX */
30
31 #include <security/pam_modules.h>
32
33 #include "general.h"
34
35 #include "support.h"
36
37 #define AUTH_RETURN                                             \
38 do {                                                            \
39         if(ret_data) {                                          \
40                 *ret_data = retval;                             \
41                 pam_set_data( pamh, "smb_setcred_return"        \
42                               , (void *) ret_data, NULL );      \
43         }                                                       \
44         return retval;                                          \
45 } while (0)
46
47 static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
48                          const char *name, struct smb_passwd *smb_pwent);
49
50 /*
51  * pam_sm_authenticate() authenticates users against the samba password file.
52  *
53  *      First, obtain the password from the user. Then use a
54  *      routine in 'support.c' to authenticate the user.
55  */
56
57 #define _SMB_AUTHTOK  "-SMB-PASS"
58
59 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
60                         int argc, const char **argv)
61 {
62     unsigned int ctrl;
63     int retval, *ret_data = NULL;
64
65     const char *name;
66
67     /* Points to memory managed by the PAM library. Do not free. */
68     const char *p = NULL;
69
70     struct smb_passwd *smb_pwent = NULL;
71
72     extern BOOL in_client;
73
74     /* Samba initialization. */
75     setup_logging("pam_smbpass",False);
76     in_client = True;
77
78     ctrl = set_ctrl(flags, argc, argv);
79
80     /* Get a few bytes so we can pass our return value to
81        pam_sm_setcred(). Used in AUTH_RETURN macro */
82     ret_data = malloc(sizeof(int));
83
84     /* get the username */
85     retval = pam_get_user( pamh, &name, "Username: " );
86     if ( retval != PAM_SUCCESS ) {
87         if (on( SMB_DEBUG, ctrl )) {
88             _log_err(LOG_DEBUG, "auth: could not identify user");
89         }
90         AUTH_RETURN;
91     }
92     if (on( SMB_DEBUG, ctrl )) {
93         _log_err( LOG_DEBUG, "username [%s] obtained", name );
94     }
95
96     if (!initialize_password_db()) {
97         _log_err( LOG_ALERT, "Cannot access samba password database" );
98         retval = PAM_AUTHINFO_UNAVAIL;
99         AUTH_RETURN;
100     }
101
102     smb_pwent = getsmbpwnam( name );
103
104     if (on( SMB_MIGRATE, ctrl )) {
105         retval = _smb_add_user(pamh, ctrl, name, smb_pwent);
106         AUTH_RETURN;
107     }
108
109     if (smb_pwent == NULL) {
110         _log_err(LOG_ALERT, "Failed to find entry for user %s.", name);
111         retval = PAM_USER_UNKNOWN;
112         AUTH_RETURN;
113     }
114    
115     /* if this user does not have a password... */
116
117     if (_smb_blankpasswd( ctrl, smb_pwent )) {
118         smb_pwent = NULL;
119         retval = PAM_SUCCESS;
120         AUTH_RETURN;
121     }
122
123     /* get this user's authentication token */
124
125     retval = _smb_read_password(pamh, ctrl, NULL, "Password: ", NULL
126                                  , _SMB_AUTHTOK, &p);
127     if (retval != PAM_SUCCESS ) {
128         _log_err(LOG_CRIT, "auth: no password provided for [%s]"
129                  , name);
130         smb_pwent = NULL;
131         AUTH_RETURN;
132     }
133
134     /* verify the password of this user */
135
136     retval = _smb_verify_password( pamh, smb_pwent, p, ctrl );
137     smb_pwent = NULL;
138     p = NULL;
139     AUTH_RETURN;
140 }
141
142 /*
143  * This function is for setting samba credentials.  If anyone comes up
144  * with any credentials they think should be set, let me know.
145  */
146
147 int pam_sm_setcred(pam_handle_t *pamh, int flags,
148                    int argc, const char **argv)
149 {
150     int retval, *pretval = NULL;
151
152     retval = PAM_SUCCESS;
153
154     pam_get_data(pamh, "smb_setcred_return", (const void **) &pretval);
155     if(pretval) {
156         retval = *pretval;
157         free(pretval);
158     }
159     pam_set_data(pamh, "smb_setcred_return", NULL, NULL);
160
161     return retval;
162 }
163
164
165 /* Helper function for adding a user to the db. */
166 static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
167                          const char *name, struct smb_passwd *smb_pwent)
168 {
169     pstring err_str;
170     pstring msg_str;
171     const char *pass = NULL;
172     int retval;
173
174     err_str[0] = '\0';
175     msg_str[0] = '\0';
176
177     /* Get the authtok; if we don't have one, silently fail. */
178     retval = pam_get_item( pamh, PAM_AUTHTOK, (const void **) &pass );
179
180     if (retval != PAM_SUCCESS) {
181         _log_err( LOG_ALERT
182                   , "pam_get_item returned error to pam_sm_authenticate" );
183         return PAM_AUTHTOK_RECOVER_ERR;
184     } else if (pass == NULL) {
185         return PAM_AUTHTOK_RECOVER_ERR;
186     }
187
188     /* Add the user to the db if they aren't already there. */
189     if (smb_pwent == NULL) {
190         retval = local_password_change( name, LOCAL_ADD_USER|LOCAL_SET_PASSWORD,
191                                          pass, err_str,
192                                          sizeof(err_str),
193                                          msg_str, sizeof(msg_str) );
194         if (!retval && *err_str)
195         {
196             err_str[PSTRING_LEN-1] = '\0';
197             make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
198         }
199         else if (*msg_str)
200         {
201             msg_str[PSTRING_LEN-1] = '\0';
202             make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
203         }
204         pass = NULL;
205
206         return PAM_IGNORE;
207     }
208
209     /* Change the user's password IFF it's null. */
210     if (smb_pwent->smb_passwd == NULL && (smb_pwent->acct_ctrl & ACB_PWNOTREQ))
211     {
212         retval = local_password_change( name, LOCAL_SET_PASSWORD,
213                                          pass, err_str,
214                                          sizeof(err_str),
215                                          msg_str, sizeof(msg_str) );
216         if (!retval && *err_str)
217         {
218             err_str[PSTRING_LEN-1] = '\0';
219             make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
220         }
221         else if (*msg_str)
222         {
223             msg_str[PSTRING_LEN-1] = '\0';
224             make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
225         }
226     }
227     pass = NULL;
228
229     return PAM_IGNORE;
230 }
231
232
233 /* static module data */
234 #ifdef PAM_STATIC
235 struct pam_module _pam_smbpass_auth_modstruct = {
236      "pam_smbpass",
237      pam_sm_authenticate,
238      pam_sm_setcred,
239      NULL,
240      NULL,
241      NULL,
242      NULL
243 };
244 #endif
245