1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/varargs.h> 28 #include <string.h> 29 #include <syslog.h> 30 #include <stdlib.h> 31 32 #include <security/pam_appl.h> 33 #include <security/pam_modules.h> 34 #include <security/pam_impl.h> 35 36 #include <libintl.h> 37 #include <passwdutil.h> 38 39 #include <smbsrv/libsmb.h> 40 41 /*PRINTFLIKE3*/ 42 static void 43 error(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...) 44 { 45 va_list ap; 46 char message[PAM_MAX_MSG_SIZE]; 47 48 if (nowarn) 49 return; 50 51 va_start(ap, fmt); 52 (void) vsnprintf(message, sizeof (message), fmt, ap); 53 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, &message, 54 NULL); 55 va_end(ap); 56 } 57 58 /*PRINTFLIKE3*/ 59 static void 60 info(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...) 61 { 62 va_list ap; 63 char message[PAM_MAX_MSG_SIZE]; 64 65 if (nowarn) 66 return; 67 68 va_start(ap, fmt); 69 (void) vsnprintf(message, sizeof (message), fmt, ap); 70 (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, &message, 71 NULL); 72 va_end(ap); 73 } 74 75 int 76 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv) 77 { 78 boolean_t debug = B_FALSE; 79 boolean_t nowarn = B_FALSE; 80 pwu_repository_t files_rep; 81 char *user, *local_user; 82 char *newpw; 83 char *service; 84 int privileged; 85 int res; 86 int i; 87 88 for (i = 0; i < argc; i++) { 89 if (strcmp(argv[i], "debug") == 0) 90 debug = B_TRUE; 91 else if (strcmp(argv[i], "nowarn") == 0) 92 nowarn = B_TRUE; 93 } 94 95 if ((flags & PAM_PRELIM_CHECK) != 0) 96 return (PAM_IGNORE); 97 98 if ((flags & PAM_UPDATE_AUTHTOK) == 0) 99 return (PAM_SYSTEM_ERR); 100 101 if ((flags & PAM_SILENT) != 0) 102 nowarn = B_TRUE; 103 104 if (debug) 105 __pam_log(LOG_AUTH | LOG_DEBUG, 106 "pam_smb_passwd: storing authtok"); 107 108 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service); 109 (void) pam_get_item(pamh, PAM_USER, (void **)&user); 110 111 if (user == NULL || *user == '\0') { 112 __pam_log(LOG_AUTH | LOG_ERR, 113 "pam_smb_passwd: username is empty"); 114 return (PAM_USER_UNKNOWN); 115 } 116 117 (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&newpw); 118 if (newpw == NULL) { 119 /* 120 * A module on the stack has removed PAM_AUTHTOK. We fail 121 */ 122 return (PAM_AUTHTOK_ERR); 123 } 124 125 /* Check to see if this is a local user */ 126 files_rep.type = "files"; 127 files_rep.scope = NULL; 128 files_rep.scope_len = 0; 129 res = __user_to_authenticate(user, &files_rep, &local_user, 130 &privileged); 131 if (res != PWU_SUCCESS) { 132 switch (res) { 133 case PWU_NOT_FOUND: 134 /* if not a local user, ignore */ 135 if (debug) { 136 __pam_log(LOG_AUTH | LOG_DEBUG, 137 "pam_smb_passwd: %s is not local", user); 138 } 139 return (PAM_IGNORE); 140 case PWU_DENIED: 141 return (PAM_PERM_DENIED); 142 } 143 return (PAM_SYSTEM_ERR); 144 } 145 146 smb_pwd_init(B_FALSE); 147 148 res = smb_pwd_setpasswd(user, newpw); 149 150 smb_pwd_fini(); 151 152 /* 153 * now map the various return states to user messages 154 * and PAM return codes. 155 */ 156 switch (res) { 157 case SMB_PWE_SUCCESS: 158 info(nowarn, pamh, dgettext(TEXT_DOMAIN, 159 "%s: SMB password successfully changed for %s"), 160 service, user); 161 return (PAM_SUCCESS); 162 163 case SMB_PWE_STAT_FAILED: 164 __pam_log(LOG_AUTH | LOG_ERR, 165 "%s: stat of SMB password file failed", service); 166 return (PAM_SYSTEM_ERR); 167 168 case SMB_PWE_OPEN_FAILED: 169 case SMB_PWE_WRITE_FAILED: 170 case SMB_PWE_CLOSE_FAILED: 171 case SMB_PWE_UPDATE_FAILED: 172 error(nowarn, pamh, dgettext(TEXT_DOMAIN, 173 "%s: Unexpected failure. SMB password database unchanged."), 174 service); 175 return (PAM_SYSTEM_ERR); 176 177 case SMB_PWE_BUSY: 178 error(nowarn, pamh, dgettext(TEXT_DOMAIN, 179 "%s: SMB password database busy. Try again later."), 180 service); 181 182 return (PAM_AUTHTOK_LOCK_BUSY); 183 184 case SMB_PWE_USER_UNKNOWN: 185 error(nowarn, pamh, dgettext(TEXT_DOMAIN, 186 "%s: %s does not exist."), service, user); 187 return (PAM_USER_UNKNOWN); 188 189 case SMB_PWE_USER_DISABLE: 190 error(nowarn, pamh, dgettext(TEXT_DOMAIN, 191 "%s: %s is disable. SMB password database unchanged."), 192 service, user); 193 return (PAM_IGNORE); 194 195 case SMB_PWE_DENIED: 196 return (PAM_PERM_DENIED); 197 198 default: 199 res = PAM_SYSTEM_ERR; 200 break; 201 } 202 203 return (res); 204 } 205