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 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <sys/types.h>
29 #include <sys/varargs.h>
30 #include <string.h>
31 #include <syslog.h>
32 #include <stdlib.h>
33
34 #include <security/pam_appl.h>
35 #include <security/pam_modules.h>
36 #include <security/pam_impl.h>
37
38 #include <libintl.h>
39 #include <passwdutil.h>
40
41 #include <smbsrv/libsmb.h>
42
43 /*PRINTFLIKE3*/
44 static void
error(boolean_t nowarn,pam_handle_t * pamh,char * fmt,...)45 error(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...)
46 {
47 va_list ap;
48 char message[PAM_MAX_MSG_SIZE];
49
50 if (nowarn)
51 return;
52
53 va_start(ap, fmt);
54 (void) vsnprintf(message, sizeof (message), fmt, ap);
55 (void) __pam_display_msg(pamh, PAM_ERROR_MSG, 1, &message,
56 NULL);
57 va_end(ap);
58 }
59
60 /*PRINTFLIKE3*/
61 static void
info(boolean_t nowarn,pam_handle_t * pamh,char * fmt,...)62 info(boolean_t nowarn, pam_handle_t *pamh, char *fmt, ...)
63 {
64 va_list ap;
65 char message[PAM_MAX_MSG_SIZE];
66
67 if (nowarn)
68 return;
69
70 va_start(ap, fmt);
71 (void) vsnprintf(message, sizeof (message), fmt, ap);
72 (void) __pam_display_msg(pamh, PAM_TEXT_INFO, 1, &message,
73 NULL);
74 va_end(ap);
75 }
76
77 int
pam_sm_chauthtok(pam_handle_t * pamh,int flags,int argc,const char ** argv)78 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
79 {
80 boolean_t debug = B_FALSE;
81 boolean_t nowarn = B_FALSE;
82 pwu_repository_t files_rep;
83 char *user, *local_user;
84 char *newpw;
85 char *service;
86 int privileged;
87 int res;
88 int i;
89
90 for (i = 0; i < argc; i++) {
91 if (strcmp(argv[i], "debug") == 0)
92 debug = B_TRUE;
93 else if (strcmp(argv[i], "nowarn") == 0)
94 nowarn = B_TRUE;
95 }
96
97 if ((flags & PAM_PRELIM_CHECK) != 0)
98 return (PAM_IGNORE);
99
100 if ((flags & PAM_UPDATE_AUTHTOK) == 0)
101 return (PAM_SYSTEM_ERR);
102
103 if ((flags & PAM_SILENT) != 0)
104 nowarn = B_TRUE;
105
106 if (debug)
107 __pam_log(LOG_AUTH | LOG_DEBUG,
108 "pam_smb_passwd: storing authtok");
109
110 (void) pam_get_item(pamh, PAM_SERVICE, (void **)&service);
111 (void) pam_get_item(pamh, PAM_USER, (void **)&user);
112
113 if (user == NULL || *user == '\0') {
114 __pam_log(LOG_AUTH | LOG_ERR,
115 "pam_smb_passwd: username is empty");
116 return (PAM_USER_UNKNOWN);
117 }
118
119 (void) pam_get_item(pamh, PAM_AUTHTOK, (void **)&newpw);
120 if (newpw == NULL) {
121 /*
122 * A module on the stack has removed PAM_AUTHTOK. We fail
123 */
124 return (PAM_AUTHTOK_ERR);
125 }
126
127 /* Check to see if this is a local user */
128 files_rep.type = "files";
129 files_rep.scope = NULL;
130 files_rep.scope_len = 0;
131 res = __user_to_authenticate(user, &files_rep, &local_user,
132 &privileged);
133 if (res != PWU_SUCCESS) {
134 switch (res) {
135 case PWU_NOT_FOUND:
136 /* if not a local user, ignore */
137 if (debug) {
138 __pam_log(LOG_AUTH | LOG_DEBUG,
139 "pam_smb_passwd: %s is not local", user);
140 }
141 return (PAM_IGNORE);
142 case PWU_DENIED:
143 return (PAM_PERM_DENIED);
144 }
145 return (PAM_SYSTEM_ERR);
146 }
147
148 smb_pwd_init(B_FALSE);
149
150 res = smb_pwd_setpasswd(user, newpw);
151
152 smb_pwd_fini();
153
154 /*
155 * now map the various return states to user messages
156 * and PAM return codes.
157 */
158 switch (res) {
159 case SMB_PWE_SUCCESS:
160 info(nowarn, pamh, dgettext(TEXT_DOMAIN,
161 "%s: SMB password successfully changed for %s"),
162 service, user);
163 return (PAM_SUCCESS);
164
165 case SMB_PWE_STAT_FAILED:
166 __pam_log(LOG_AUTH | LOG_ERR,
167 "%s: stat of SMB password file failed", service);
168 return (PAM_SYSTEM_ERR);
169
170 case SMB_PWE_OPEN_FAILED:
171 case SMB_PWE_WRITE_FAILED:
172 case SMB_PWE_CLOSE_FAILED:
173 case SMB_PWE_UPDATE_FAILED:
174 error(nowarn, pamh, dgettext(TEXT_DOMAIN,
175 "%s: Unexpected failure. SMB password database unchanged."),
176 service);
177 return (PAM_SYSTEM_ERR);
178
179 case SMB_PWE_BUSY:
180 error(nowarn, pamh, dgettext(TEXT_DOMAIN,
181 "%s: SMB password database busy. Try again later."),
182 service);
183
184 return (PAM_AUTHTOK_LOCK_BUSY);
185
186 case SMB_PWE_USER_UNKNOWN:
187 error(nowarn, pamh, dgettext(TEXT_DOMAIN,
188 "%s: %s does not exist."), service, user);
189 return (PAM_USER_UNKNOWN);
190
191 case SMB_PWE_USER_DISABLE:
192 error(nowarn, pamh, dgettext(TEXT_DOMAIN,
193 "%s: %s is disable. SMB password database unchanged."),
194 service, user);
195 return (PAM_IGNORE);
196
197 case SMB_PWE_DENIED:
198 return (PAM_PERM_DENIED);
199
200 default:
201 res = PAM_SYSTEM_ERR;
202 break;
203 }
204
205 return (res);
206 }
207