Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / pam / pam_modules / unix / unix_update_authtok_nis.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: unix_update_authtok_nis.c /main/5 1996/05/09 04:36:14 drk $ */
24 /*
25  * Copyright (c) 1992-1996, by Sun Microsystems, Inc.
26  * All rights reserved.
27  */
28
29 #ident  "@(#)unix_update_authtok_nis.c 1.43     96/02/02 SMI"
30
31 #include "unix_headers.h"
32
33 #ifdef PAM_NIS
34
35 static void     reencrypt_secret(pam_handle_t *, char *, char *, char *,
36                                 int);
37 static int      update_nisattr(pam_handle_t *, char *, char **,
38                                 struct passwd *, int, int);
39
40 int
41 update_authtok_nis(
42         pam_handle_t    *pamh,
43         char            *field,
44         char            *data[],        /* encrypted new passwd */
45                                         /* or new attribute info */
46         char            *old,           /* old passwd: clear */
47         char            *new,           /* new passwd: clear */
48         struct passwd   *nis_pwd,       /* password structure */
49         int             privileged,
50         int             nowarn)         /* no compat mode: npd and yp server */
51                                         /* take the same protocol */
52 {
53         int                             ok;
54         enum clnt_stat                  ans;
55         char                            *domain;
56         char                            *master;
57         CLIENT                          *client;
58         struct timeval                  timeout;
59         char                            *prognamep;
60         char                            *usrname;
61         int                             retcode = PAM_SYSTEM_ERR;
62         char                    messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
63         struct yppasswd         yppasswd;
64
65         /* initialize this */
66         yppasswd.oldpass = NULL;
67
68         if ((retcode = pam_get_item(pamh, PAM_SERVICE, (void **)&prognamep))
69                                                 != PAM_SUCCESS ||
70             (retcode = pam_get_item(pamh, PAM_USER, (void **)&usrname))
71                                                 != PAM_SUCCESS)
72                 goto out;
73
74         if (strcmp(field, "passwd") == 0) {
75                 /*
76                  * ck_passwd() already checked the old passwd. It won't get here
77                  * if the old passwd is not matched.
78                  * We are just preparing the passwd update packet here.
79                  */
80
81                 if ((yppasswd.oldpass = strdup(old)) == NULL) {
82                         retcode = PAM_BUF_ERR;
83                         goto out;
84                 }
85
86                 if (nis_pwd->pw_passwd) {
87                         memset(nis_pwd->pw_passwd, 0,
88                                         strlen(nis_pwd->pw_passwd));
89                         free(nis_pwd->pw_passwd);
90                 }
91                 nis_pwd->pw_passwd = *data;     /* encrypted new passwd */
92         } else {
93                 /*
94                  * prompt for passwd: required for the options
95                  * nis_pwd struct will be modified by update_nisattr().
96                  * The encrypted passwd remains the same because we are not
97                  * changing passwd here.
98                  */
99
100                 retcode = __pam_get_authtok(pamh, PAM_PROMPT, 0, PASSWORD_LEN,
101                         PAM_MSG(pamh, 62, "Enter login(NIS) password: "),
102                         &(yppasswd.oldpass));
103                 if (retcode != PAM_SUCCESS)
104                         goto out;
105
106                 if ((retcode = update_nisattr(pamh, field, data,
107                         nis_pwd, privileged, nowarn)) != PAM_SUCCESS) {
108
109                         if (retcode == -1) {
110                                 /* finger, shell, or gecos info unchanged */
111                                 retcode = PAM_SUCCESS;
112                         }
113                         goto out;
114                 }
115         }
116
117         yppasswd.newpw = *nis_pwd;
118         if (yp_get_default_domain(&domain) != 0) {
119                 syslog(LOG_ERR, "%s%s: can't get domain",
120                         prognamep, NIS_MSG);
121                 retcode = PAM_SYSTEM_ERR;
122                 goto out;
123         }
124
125         if (yp_master(domain, "passwd.byname", &master) != 0) {
126                 syslog(LOG_ERR, "%s%s: can't get master for passwd map",
127                         prognamep, NIS_MSG);
128                 retcode = PAM_SYSTEM_ERR;
129                 goto out;
130         }
131         client = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
132         if (client == NULL) {
133                 syslog(LOG_ERR,
134                         "%s%s: couldn't create client to YP master",
135                         prognamep, NIS_MSG);
136                 retcode = PAM_SYSTEM_ERR;
137                 goto out;
138         }
139
140         timeout.tv_usec = 0;
141         timeout.tv_sec = 55;    /* npd uses 55 seconds */
142
143         ans = CLNT_CALL(client, YPPASSWDPROC_UPDATE, xdr_yppasswd,
144                 (char *)&yppasswd, xdr_int, (char *)&ok, timeout);
145         (void) clnt_destroy(client);
146         if (ans != RPC_SUCCESS) {
147                 sprintf(messages[0], PAM_MSG(pamh, 100,
148                         "%s%s: couldn't change passwd/attributes"),
149                         prognamep, NIS_MSG);
150                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
151                         1, messages, NULL);
152
153                 retcode = PAM_PERM_DENIED;
154                 goto out;
155         }
156
157         if (ok != 0) {
158                 sprintf(messages[0], PAM_MSG(pamh, 101,
159                         "%s%s: Couldn't change passwd/attributes for %s"),
160                         prognamep, NIS_MSG, usrname);
161                 (void) __pam_display_msg(pamh, PAM_ERROR_MSG,
162                         1, messages, NULL);
163
164                 retcode = PAM_PERM_DENIED;
165                 goto out;
166         }
167
168         sprintf(messages[0], PAM_MSG(pamh, 102,
169                 "NIS(YP) passwd/attributes changed on %s"),
170                 master);
171         (void) __pam_display_msg(pamh, PAM_TEXT_INFO,
172                 1, messages, NULL);
173
174         reencrypt_secret(pamh, domain, old, new, nowarn);
175
176         retcode = PAM_SUCCESS;
177 out:
178         if (yppasswd.oldpass) {
179                 memset(yppasswd.oldpass, 0, strlen(yppasswd.oldpass));
180                 free(yppasswd.oldpass);
181         }
182         return (retcode);
183 }
184
185
186 static int
187 update_nisattr(pam_handle_t *pamh, char *field, char **data,
188                 struct passwd *nis_pwd, int privileged, int nowarn)
189 {
190         char            *username;
191         char            *value;
192         char            messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
193
194         if (nis_pwd == NULL) {
195                 if (!nowarn) {
196                         pam_get_item(pamh, PAM_USER, (void **)&username);
197                         sprintf(messages[0], PAM_MSG(pamh, 103,
198                                 "System error: no NIS passwd record for %s"),
199                                 username);
200                         (void) __pam_display_msg(pamh,
201                                 PAM_ERROR_MSG, 1, messages, NULL);
202                 }
203                 return (PAM_USER_UNKNOWN);
204         }
205
206         if (strcmp(field, "attr") == 0) {
207
208                 while (*data != NULL) {
209                         /* AUTHTOK_DEL: not applicable */
210
211                         if ((value = attr_match("AUTHTOK_SHELL", *data))
212                             != NULL) {
213                                 if (strcmp(value, "1") != 0) {
214                                         if (!nowarn) {
215                                             sprintf(messages[0],
216                                             PAM_MSG(pamh, 104,
217                     "%s: System error%s: shell is set illegally"),
218                                             value, NIS_MSG);
219                                         (void) __pam_display_msg(pamh,
220                                             PAM_ERROR_MSG, 1,
221                                             messages, NULL);
222                                         }
223                                         return (PAM_SYSTEM_ERR);
224                                 }
225                                 nis_pwd->pw_shell =
226                                     getloginshell(pamh, nis_pwd->pw_shell,
227                                         privileged, nowarn);
228                                 /* if NULL, shell unchanged */
229                                 if (nis_pwd->pw_shell == NULL)
230                                         return (-1);
231                                 data++;
232                                 continue;
233                         }
234
235                         if ((value = attr_match("AUTHTOK_HOMEDIR", *data))
236                             != NULL) {
237                                 /* home directory */
238                                 if (strcmp(value, "1") != 0) {
239                                         if (!nowarn) {
240                                                 sprintf(messages[0],
241                                                 PAM_MSG(pamh, 105,
242                         "System error%s: homedir is set illegally."),
243                                                 NIS_MSG);
244                                                 (void) __pam_display_msg(
245                                                         pamh,
246                                                         PAM_ERROR_MSG, 1,
247                                                         messages, NULL);
248                                         }
249                                         return (PAM_SYSTEM_ERR);
250                                 }
251                                 nis_pwd->pw_dir =
252                                     gethomedir(pamh, nis_pwd->pw_dir, nowarn);
253                                 /* if NULL, homedir unchanged */
254                                 if (nis_pwd->pw_dir == NULL)
255                                         return (-1);
256                                 data++;
257                                 continue;
258                         }
259
260                         if ((value = attr_match("AUTHTOK_GECOS", *data))
261                             != NULL) {
262                                 /* finger information */
263                                 if (strcmp(value, "1") != 0) {
264                                         if (!nowarn) {
265                                                 sprintf(messages[0],
266                                                 PAM_MSG(pamh, 106,
267                                 "System error: gecos is set illegally."));
268                                                 (void) __pam_display_msg(
269                                                         pamh,
270                                                         PAM_ERROR_MSG, 1,
271                                                         messages, NULL);
272                                         }
273                                         return (PAM_SYSTEM_ERR);
274                                 }
275                                 nis_pwd->pw_gecos =
276                                     getfingerinfo(pamh, nis_pwd->pw_gecos,
277                                                 nowarn);
278                                 /* if NULL, gecos unchanged */
279                                 if (nis_pwd->pw_gecos == NULL)
280                                         return (-1);
281                                 data++;
282                                 continue;
283                         }
284                 } /* while */
285                 return (PAM_SUCCESS);
286         }
287         return (PAM_AUTHTOK_ERR);
288         /* NOTREACHED */
289 }
290
291 /*
292  * If the user has a secret key, reencrypt it.
293  * Otherwise, be quiet.
294  */
295 static void
296 reencrypt_secret(pam_handle_t *pamh, char *domain, char *oldpass,
297                 char *newpass, int nowarn)
298 {
299 #ifdef PAM_SECURE_RPC
300         char who[MAXNETNAMELEN+1];
301         char secret[HEXKEYBYTES+1];
302         char public[HEXKEYBYTES+1];
303         char crypt[HEXKEYBYTES + KEYCHECKSUMSIZE + 1];
304         char pkent[sizeof (crypt) + sizeof (public) + 1];
305         char *master;
306         char messages[PAM_MAX_NUM_MSG][PAM_MAX_MSG_SIZE];
307
308         getnetname(who);
309         if (!getsecretkey(who, secret, oldpass)) {
310                 /*
311                  * Quiet: net is not running secure RPC
312                  */
313                 return;
314         }
315         if (secret[0] == 0) {
316                 /*
317                  * Quiet: user has no secret key
318                  */
319                 return;
320         }
321         if (getpublickey(who, public) == FALSE) {
322                 return;
323         }
324         (void) memcpy(crypt, secret, HEXKEYBYTES);
325         (void) memcpy(crypt + HEXKEYBYTES, secret, KEYCHECKSUMSIZE);
326         crypt[HEXKEYBYTES + KEYCHECKSUMSIZE] = 0;
327         (void) xencrypt(crypt, newpass);
328         (void) sprintf(pkent, "%s:%s", public, crypt);
329         if (yp_update(domain, PKMAP, YPOP_STORE,
330             who, strlen(who), pkent, strlen(pkent)) != 0) {
331
332                 return;
333         }
334         if (yp_master(domain, PKMAP, &master) != 0) {
335                 master = "yp master";   /* should never happen */
336         }
337
338         sprintf(messages[0], PAM_MSG(pamh, 107,
339                 "%s: secret key reencrypted for %s on %s"),
340                 NIS_MSG, who, master);
341         __pam_display_msg(pamh, PAM_TEXT_INFO, 1, messages, NULL);
342 #else
343         return;
344 #endif /* PAM_SECURE_RPC */
345
346 }
347
348 #endif /* PAM_NIS */