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