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
error(boolean_t nowarn,pam_handle_t * pamh,char * fmt,...)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
info(boolean_t nowarn,pam_handle_t * pamh,char * fmt,...)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
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)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