1 /**
2 * xrdp: A Remote Desktop Protocol server.
3 *
4 * Copyright (C) Jay Sorg 2004-2013
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 /**
20 *
21 * @file verify_user.c
22 * @brief Authenticate user using standard unix passwd/shadow system
23 * @author Jay Sorg, Simone Fedele
24 *
25 */
26
27 #if defined(HAVE_CONFIG_H)
28 #include <config_ac.h>
29 #endif
30
31 #include "sesman.h"
32 #include "string_calls.h"
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/types.h>
37 #include <crypt.h>
38 #include <shadow.h>
39 #include <pwd.h>
40
41 #ifndef SECS_PER_DAY
42 #define SECS_PER_DAY (24L*3600L)
43 #endif
44
45 extern struct config_sesman *g_cfg; /* in sesman.c */
46
47 static int
48 auth_crypt_pwd(const char *pwd, const char *pln, char *crp);
49
50 static int
51 auth_account_disabled(struct spwd *stp);
52
53 /******************************************************************************/
54 /* returns boolean */
55 long
auth_userpass(const char * user,const char * pass,int * errorcode)56 auth_userpass(const char *user, const char *pass, int *errorcode)
57 {
58 const char *encr;
59 const char *epass;
60 struct passwd *spw;
61 struct spwd *stp;
62
63 spw = getpwnam(user);
64
65 if (spw == 0)
66 {
67 return 0;
68 }
69
70 if (g_strncmp(spw->pw_passwd, "x", 3) == 0)
71 {
72 /* the system is using shadow */
73 stp = getspnam(user);
74
75 if (stp == 0)
76 {
77 return 0;
78 }
79
80 if (1 == auth_account_disabled(stp))
81 {
82 LOG(LOG_LEVEL_INFO, "account %s is disabled", user);
83 return 0;
84 }
85
86 encr = stp->sp_pwdp;
87 }
88 else
89 {
90 /* old system with only passwd */
91 encr = spw->pw_passwd;
92 }
93 epass = crypt(pass, encr);
94 if (epass == 0)
95 {
96 return 0;
97 }
98 return (strcmp(encr, epass) == 0);
99 }
100
101 /******************************************************************************/
102 /* returns error */
103 int
auth_start_session(long in_val,int in_display)104 auth_start_session(long in_val, int in_display)
105 {
106 return 0;
107 }
108
109 /******************************************************************************/
110 /* returns error */
111 int
auth_stop_session(long in_val)112 auth_stop_session(long in_val)
113 {
114 return 0;
115 }
116
117 /******************************************************************************/
118 int
auth_end(long in_val)119 auth_end(long in_val)
120 {
121 return 0;
122 }
123
124 /******************************************************************************/
125 int
auth_set_env(long in_val)126 auth_set_env(long in_val)
127 {
128 return 0;
129 }
130
131 /******************************************************************************/
132 int
auth_check_pwd_chg(const char * user)133 auth_check_pwd_chg(const char *user)
134 {
135 struct passwd *spw;
136 struct spwd *stp;
137 int now;
138 long today;
139
140 spw = getpwnam(user);
141
142 if (spw == 0)
143 {
144 return AUTH_PWD_CHG_ERROR;
145 }
146
147 if (g_strncmp(spw->pw_passwd, "x", 3) != 0)
148 {
149 /* old system with only passwd */
150 return AUTH_PWD_CHG_OK;
151 }
152
153 /* the system is using shadow */
154 stp = getspnam(user);
155
156 if (stp == 0)
157 {
158 return AUTH_PWD_CHG_ERROR;
159 }
160
161 /* check if we need a pwd change */
162 now = g_time1();
163 today = now / SECS_PER_DAY;
164
165 if (stp->sp_expire == -1)
166 {
167 return AUTH_PWD_CHG_OK;
168 }
169
170 if (today >= (stp->sp_lstchg + stp->sp_max - stp->sp_warn))
171 {
172 return AUTH_PWD_CHG_CHANGE;
173 }
174
175 if (today >= (stp->sp_lstchg + stp->sp_max))
176 {
177 return AUTH_PWD_CHG_CHANGE_MANDATORY;
178 }
179
180 if (today < ((stp->sp_lstchg) + (stp->sp_min)))
181 {
182 /* cannot change pwd for now */
183 return AUTH_PWD_CHG_NOT_NOW;
184 }
185
186 return AUTH_PWD_CHG_OK;
187 }
188
189 int
auth_change_pwd(const char * user,const char * newpwd)190 auth_change_pwd(const char *user, const char *newpwd)
191 {
192 struct passwd *spw;
193 struct spwd *stp;
194 char hash[35] = "";
195 long today;
196
197 FILE *fd;
198
199 if (0 != lckpwdf())
200 {
201 return 1;
202 }
203
204 /* open passwd */
205 spw = getpwnam(user);
206
207 if (spw == 0)
208 {
209 return 1;
210 }
211
212 if (g_strncmp(spw->pw_passwd, "x", 3) != 0)
213 {
214 /* old system with only passwd */
215 if (auth_crypt_pwd(spw->pw_passwd, newpwd, hash) != 0)
216 {
217 ulckpwdf();
218 return 1;
219 }
220
221 spw->pw_passwd = g_strdup(hash);
222 fd = fopen("/etc/passwd", "rw");
223 putpwent(spw, fd);
224 }
225 else
226 {
227 /* the system is using shadow */
228 stp = getspnam(user);
229
230 if (stp == 0)
231 {
232 return 1;
233 }
234
235 /* old system with only passwd */
236 if (auth_crypt_pwd(stp->sp_pwdp, newpwd, hash) != 0)
237 {
238 ulckpwdf();
239 return 1;
240 }
241
242 stp->sp_pwdp = g_strdup(hash);
243 today = g_time1() / SECS_PER_DAY;
244 stp->sp_lstchg = today;
245 stp->sp_expire = today + stp->sp_max + stp->sp_inact;
246 fd = fopen("/etc/shadow", "rw");
247 putspent(stp, fd);
248 }
249
250 ulckpwdf();
251 return 0;
252 }
253
254 /**
255 *
256 * @brief Password encryption
257 * @param pwd Old password
258 * @param pln Plaintext new password
259 * @param crp Crypted new password
260 *
261 */
262
263 static int
auth_crypt_pwd(const char * pwd,const char * pln,char * crp)264 auth_crypt_pwd(const char *pwd, const char *pln, char *crp)
265 {
266 char salt[13] = "$1$";
267 int saltcnt = 0;
268 char *encr;
269
270 if (g_strncmp(pwd, "$1$", 3) == 0)
271 {
272 /* gnu style crypt(); */
273 saltcnt = 3;
274
275 while ((pwd[saltcnt] != '$') && (saltcnt < 11))
276 {
277 salt[saltcnt] = pwd[saltcnt];
278 saltcnt++;
279 }
280
281 salt[saltcnt] = '$';
282 salt[saltcnt + 1] = '\0';
283 }
284 else
285 {
286 /* classic two char salt */
287 salt[0] = pwd[0];
288 salt[1] = pwd[1];
289 salt[2] = '\0';
290 }
291
292 encr = crypt(pln, salt);
293 g_strncpy(crp, encr, 34);
294
295 return 0;
296 }
297
298 /**
299 *
300 * @return 1 if the account is disabled, 0 otherwise
301 *
302 */
303 static int
auth_account_disabled(struct spwd * stp)304 auth_account_disabled(struct spwd *stp)
305 {
306 int today;
307
308 if (0 == stp)
309 {
310 /* if an invalid struct was passed we assume a disabled account */
311 return 1;
312 }
313
314 today = g_time1() / SECS_PER_DAY;
315
316 LOG_DEVEL(LOG_LEVEL_DEBUG, "last %ld", stp->sp_lstchg);
317 LOG_DEVEL(LOG_LEVEL_DEBUG, "min %ld", stp->sp_min);
318 LOG_DEVEL(LOG_LEVEL_DEBUG, "max %ld", stp->sp_max);
319 LOG_DEVEL(LOG_LEVEL_DEBUG, "inact %ld", stp->sp_inact);
320 LOG_DEVEL(LOG_LEVEL_DEBUG, "warn %ld", stp->sp_warn);
321 LOG_DEVEL(LOG_LEVEL_DEBUG, "expire %ld", stp->sp_expire);
322 LOG_DEVEL(LOG_LEVEL_DEBUG, "today %d", today);
323
324 if ((stp->sp_expire != -1) && (today >= stp->sp_expire))
325 {
326 return 1;
327 }
328
329 if ((stp->sp_max >= 0) &&
330 (stp->sp_inact >= 0) &&
331 (stp->sp_lstchg > 0) &&
332 (today >= (stp->sp_lstchg + stp->sp_max + stp->sp_inact)))
333 {
334 return 1;
335 }
336
337 return 0;
338 }
339