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