1/*
2 * $Id: uams_passwd.c,v 1.31 2010-03-30 12:44:35 franklahm Exp $
3 *
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu)
6 * All Rights Reserved.  See COPYRIGHT.
7 */
8
9#ifdef HAVE_CONFIG_H
10#include <config.h>
11#endif /* HAVE_CONFIG_H */
12
13#include <atalk/standards.h>
14
15#include <sys/types.h>
16#include <stdio.h>
17#include <stdlib.h>
18/* STDC check */
19#if STDC_HEADERS
20#include <string.h>
21#else /* STDC_HEADERS */
22#ifndef HAVE_STRCHR
23#define strchr index
24#define strrchr index
25#endif /* HAVE_STRCHR */
26char *strchr (), *strrchr ();
27#ifndef HAVE_MEMCPY
28#define memcpy(d,s,n) bcopy ((s), (d), (n))
29#define memmove(d,s,n) bcopy ((s), (d), (n))
30#endif /* ! HAVE_MEMCPY */
31#endif /* STDC_HEADERS */
32#ifdef HAVE_UNISTD_H
33#include <unistd.h>
34#endif /* HAVE_UNISTD_H */
35#ifdef HAVE_CRYPT_H
36#include <crypt.h>
37#endif /* ! HAVE_CRYPT_H */
38#include <pwd.h>
39#ifdef HAVE_SYS_TIME_H
40#include <sys/time.h>
41#endif
42#ifdef HAVE_TIME_H
43#include <time.h>
44#endif
45#ifdef SHADOWPW
46#include <shadow.h>
47#endif /* SHADOWPW */
48
49#include <atalk/afp.h>
50#include <atalk/logger.h>
51#include <atalk/uam.h>
52#include <atalk/util.h>
53
54#define PASSWDLEN 8
55
56#ifndef MIN
57#define MIN(a,b) ((a) < (b) ? (a) : (b))
58#endif /* MIN */
59
60
61#ifdef TRU64
62#include <sia.h>
63#include <siad.h>
64
65static const char *clientname;
66#endif /* TRU64 */
67
68/*XXX in etc/papd/file.h */
69struct papfile;
70extern UAM_MODULE_EXPORT void append(struct papfile *, const char *, int);
71
72static int pwd_login(void *obj, char *username, int ulen, struct passwd **uam_pwd,
73                        char *ibuf, size_t ibuflen,
74                        char *rbuf _U_, size_t *rbuflen _U_)
75{
76    char  *p;
77    struct passwd *pwd;
78    int err = AFP_OK;
79#ifdef SHADOWPW
80    struct spwd *sp;
81#endif /* SHADOWPW */
82
83#ifdef TRU64
84    if( uam_afpserver_option( obj, UAM_OPTION_CLIENTNAME,
85                              (void *) &clientname, NULL ) < 0 )
86        return AFPERR_MISC;
87#endif /* TRU64 */
88
89    if (ibuflen < PASSWDLEN) {
90        return( AFPERR_PARAM );
91    }
92    ibuf[ PASSWDLEN ] = '\0';
93
94    if (( pwd = uam_getname(obj, username, ulen)) == NULL ) {
95        return AFPERR_NOTAUTH;
96    }
97
98    LOG(log_info, logtype_uams, "cleartext login: %s", username);
99
100    if (uam_checkuser(pwd) < 0) {
101        LOG(log_info, logtype_uams, "not a valid user");
102        return AFPERR_NOTAUTH;
103    }
104
105#ifdef SHADOWPW
106    if (( sp = getspnam( pwd->pw_name )) == NULL ) {
107        LOG(log_info, logtype_uams, "no shadow passwd entry for %s", username);
108        return AFPERR_NOTAUTH;
109    }
110    pwd->pw_passwd = sp->sp_pwdp;
111
112    if (sp->sp_max != -1 && sp->sp_lstchg) {
113        time_t now = time(NULL) / (60*60*24);
114        int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
115        if ( expire_days < 0 ) {
116                LOG(log_info, logtype_uams, "Password for user %s expired", username);
117		err = AFPERR_PWDEXPR;
118        }
119    }
120#endif /* SHADOWPW */
121
122    if (!pwd->pw_passwd) {
123        return AFPERR_NOTAUTH;
124    }
125
126    *uam_pwd = pwd;
127
128#ifdef TRU64
129    {
130        int ac;
131        char **av;
132        char hostname[256];
133
134        uam_afp_getcmdline( &ac, &av );
135        sprintf( hostname, "%s@%s", username, clientname );
136
137        if( uam_sia_validate_user( NULL, ac, av, hostname, username,
138                                   NULL, FALSE, NULL, ibuf ) != SIASUCCESS )
139            return AFPERR_NOTAUTH;
140
141        return err;
142    }
143#else /* TRU64 */
144    p = crypt( ibuf, pwd->pw_passwd );
145    if ( strcmp( p, pwd->pw_passwd ) == 0 )
146        return err;
147#endif /* TRU64 */
148
149    return AFPERR_NOTAUTH;
150
151}
152
153/* cleartxt login */
154static int passwd_login(void *obj, struct passwd **uam_pwd,
155                        char *ibuf, size_t ibuflen,
156                        char *rbuf, size_t *rbuflen)
157{
158    char *username;
159    size_t len, ulen;
160
161    *rbuflen = 0;
162
163    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
164                             (void *) &username, &ulen) < 0)
165        return AFPERR_MISC;
166
167    if (ibuflen < 2) {
168        return( AFPERR_PARAM );
169    }
170
171    len = (unsigned char) *ibuf++;
172    ibuflen--;
173    if (!len || len > ibuflen || len > ulen ) {
174        return( AFPERR_PARAM );
175    }
176    memcpy(username, ibuf, len );
177    ibuf += len;
178    ibuflen -=len;
179    username[ len ] = '\0';
180
181    if ((unsigned long) ibuf & 1) { /* pad character */
182        ++ibuf;
183        ibuflen--;
184    }
185    return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
186
187}
188
189/* cleartxt login ext
190 * uname format :
191    byte      3
192    2 bytes   len (network order)
193    len bytes unicode name
194*/
195static int passwd_login_ext(void *obj, char *uname, struct passwd **uam_pwd,
196                        char *ibuf, size_t ibuflen,
197                        char *rbuf, size_t *rbuflen)
198{
199    char       *username;
200    size_t     len, ulen;
201    u_int16_t  temp16;
202
203    *rbuflen = 0;
204
205    if (uam_afpserver_option(obj, UAM_OPTION_USERNAME,
206                             (void *) &username, &ulen) < 0)
207        return AFPERR_MISC;
208
209    if (*uname != 3)
210        return AFPERR_PARAM;
211    uname++;
212    memcpy(&temp16, uname, sizeof(temp16));
213    len = ntohs(temp16);
214    if (!len || len > ulen ) {
215        return( AFPERR_PARAM );
216    }
217    memcpy(username, uname +2, len );
218    username[ len ] = '\0';
219    return (pwd_login(obj, username, ulen, uam_pwd, ibuf, ibuflen, rbuf, rbuflen));
220}
221
222
223#if 0
224/* change passwd */
225static int passwd_changepw(void *obj, char *username,
226                           struct passwd *pwd, char *ibuf,
227                           size_t ibuflen, char *rbuf, size_t *rbuflen)
228{
229#ifdef SHADOWPW
230    struct spwd *sp;
231#endif /* SHADOWPW */
232    char pw[PASSWDLEN + 1], *p;
233    uid_t uid = geteuid();
234
235    if (uam_checkuser(pwd) < 0)
236        return AFPERR_ACCESS;
237
238    /* old password */
239    memcpy(pw, ibuf, PASSWDLEN);
240    memset(ibuf, 0, PASSWDLEN);
241    pw[PASSWDLEN] = '\0';
242
243#ifdef SHADOWPW
244    if (( sp = getspnam( pwd->pw_name )) == NULL ) {
245        LOG(log_info, logtype_uams, "no shadow passwd entry for %s", username);
246        return AFPERR_PARAM;
247    }
248    pwd->pw_passwd = sp->sp_pwdp;
249#endif /* SHADOWPW */
250
251    p = crypt(pw, pwd->pw_passwd );
252    if (strcmp( p, pwd->pw_passwd )) {
253        memset(pw, 0, sizeof(pw));
254        return AFPERR_NOTAUTH;
255    }
256
257    /* new password */
258    ibuf += PASSWDLEN;
259    ibuf[PASSWDLEN] = '\0';
260
261#ifdef SHADOWPW
262#else /* SHADOWPW */
263#endif /* SHADOWPW */
264    return AFP_OK;
265}
266#endif /* 0 */
267
268
269/* Printer ClearTxtUAM login */
270static int passwd_printer(char	*start, char *stop, char *username, struct papfile *out)
271{
272    struct passwd *pwd;
273#ifdef SHADOWPW
274    struct spwd *sp;
275#endif /* SHADOWPW */
276    char *data, *p, *q;
277    char	password[PASSWDLEN + 1] = "\0";
278    static const char *loginok = "0\r";
279    int ulen;
280
281    data = (char *)malloc(stop - start + 1);
282    if (!data) {
283	LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: malloc");
284	return(-1);
285    }
286    strlcpy(data, start, stop - start + 1);
287
288    /* We are looking for the following format in data:
289     * (username) (password)
290     *
291     * Let's hope username doesn't contain ") ("!
292     */
293
294    /* Parse input for username in () */
295    if ((p = strchr(data, '(' )) == NULL) {
296        LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
297        free(data);
298        return(-1);
299    }
300    p++;
301    if ((q = strstr(p, ") (" )) == NULL) {
302        LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: username not found in string");
303        free(data);
304        return(-1);
305    }
306    memcpy(username, p,  MIN( UAM_USERNAMELEN, q - p ));
307
308    /* Parse input for password in next () */
309    p = q + 3;
310    if ((q = strrchr(p , ')' )) == NULL) {
311        LOG(log_info, logtype_uams,"Bad Login ClearTxtUAM: password not found in string");
312        free(data);
313        return(-1);
314    }
315    memcpy(password, p, MIN(PASSWDLEN, q - p) );
316
317    /* Done copying username and password, clean up */
318    free(data);
319
320    ulen = strlen(username);
321
322    if (( pwd = uam_getname(NULL, username, ulen)) == NULL ) {
323        LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: ( %s ) not found ",
324            username);
325        return(-1);
326    }
327
328    if (uam_checkuser(pwd) < 0) {
329        /* syslog of error happens in uam_checkuser */
330        return(-1);
331    }
332
333#ifdef SHADOWPW
334    if (( sp = getspnam( pwd->pw_name )) == NULL ) {
335        LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: no shadow passwd entry for %s",
336            username);
337        return(-1);
338    }
339    pwd->pw_passwd = sp->sp_pwdp;
340
341    if (sp->sp_max != -1 && sp->sp_lstchg) {
342        time_t now = time(NULL) / (60*60*24);
343        int32_t expire_days = sp->sp_lstchg - now + sp->sp_max;
344        if ( expire_days < 0 ) {
345                LOG(log_info, logtype_uams, "Password for user %s expired", username);
346		return (-1);
347        }
348    }
349
350#endif /* SHADOWPW */
351
352    if (!pwd->pw_passwd) {
353        LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: no password for %s",
354            username);
355        return(-1);
356    }
357
358#ifdef AFS
359    if ( kcheckuser( pwd, password) == 0)
360        return(0);
361#endif /* AFS */
362
363    p = crypt(password, pwd->pw_passwd);
364    if (strcmp(p, pwd->pw_passwd) != 0) {
365        LOG(log_info, logtype_uams, "Bad Login ClearTxtUAM: %s: bad password", username);
366        return(-1);
367    }
368
369    /* Login successful */
370    append(out, loginok, strlen(loginok));
371    LOG(log_info, logtype_uams, "Login ClearTxtUAM: %s", username);
372    return(0);
373}
374
375static int uam_setup(const char *path)
376{
377    if (uam_register(UAM_SERVER_LOGIN_EXT, path, "Cleartxt Passwrd",
378                     passwd_login, NULL, NULL, passwd_login_ext) < 0)
379        return -1;
380    if (uam_register(UAM_SERVER_PRINTAUTH, path, "ClearTxtUAM",
381                     passwd_printer) < 0)
382        return -1;
383
384    return 0;
385}
386
387static void uam_cleanup(void)
388{
389    uam_unregister(UAM_SERVER_LOGIN, "Cleartxt Passwrd");
390    uam_unregister(UAM_SERVER_PRINTAUTH, "ClearTxtUAM");
391}
392
393UAM_MODULE_EXPORT struct uam_export uams_clrtxt = {
394            UAM_MODULE_SERVER,
395            UAM_MODULE_VERSION,
396            uam_setup, uam_cleanup
397        };
398
399UAM_MODULE_EXPORT struct uam_export uams_passwd = {
400            UAM_MODULE_SERVER,
401            UAM_MODULE_VERSION,
402            uam_setup, uam_cleanup
403        };
404