Print this page
5910 libnisdb won't build with modern GCC
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libnisdb/yptol/shim_changepasswd.c
+++ new/usr/src/lib/libnisdb/yptol/shim_changepasswd.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 + * Copyright 2015 Gary Mills
22 23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 24 * Use is subject to license terms.
24 25 */
25 26
26 -#pragma ident "%Z%%M% %I% %E% SMI"
27 -
28 27 /*
29 28 * DESCRIPTION: This is the N2L equivalent of changepasswd.c. The traditional
30 29 * version modifies the NIS source files and then initiates a
31 30 * ypmake to make the maps and push them.
32 31 *
33 32 * For N2L there are no source files and the policy is that the
34 33 * definitive information is that contained in the DIT. Old
35 34 * information is read from LDAP. Assuming this authenticates, and
36 35 * the change is acceptable, this information is modified and
37 36 * written back to LDAP.
38 37 *
39 38 * Related map entries are then found and updated finally
40 39 * yppushes of the changed maps are initiated. Since the
41 40 * definitive information has already correctly been updated the
42 41 * code is tolerant of some errors during this operation.
43 42 *
44 43 * What was previously in the maps is irrelevant.
45 44 *
46 45 * Some less than perfect code (like inline constants for
47 46 * return values and a few globals) is retained from the original.
48 47 */
49 48
50 49 #include <sys/types.h>
51 50 #include <sys/stat.h>
52 51 #include <ctype.h>
53 52 #include <unistd.h>
54 53 #include <stdlib.h>
55 54 #include <string.h>
56 55 #include <stdio.h>
57 56 #include <errno.h>
58 57 #include <syslog.h>
59 58 #include <pwd.h>
60 59 #include <signal.h>
61 60 #include <crypt.h>
62 61 #include <rpc/rpc.h>
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
63 62 #include <rpcsvc/yppasswd.h>
64 63 #include <utmpx.h>
65 64 #include <shadow.h>
66 65
67 66 #include <ndbm.h>
68 67 /* DO NOT INCLUDE SHIM_HOOKS.H */
69 68 #include "shim.h"
70 69 #include "yptol.h"
71 70 #include "../ldap_util.h"
72 71
72 +/*
73 + * Undocumented external function in libnsl
74 + */
75 +extern int getdomainname(char *, int);
76 +
73 77 /* Constants */
74 78 #define CRYPTPWSIZE CRYPT_MAXCIPHERTEXTLEN
75 79 #define STRSIZE 100
76 80 #define FINGERSIZE (4 * STRSIZE - 4)
77 81 #define SHELLSIZE (STRSIZE - 2)
78 82
79 83 #define UTUSERLEN (sizeof (((struct utmpx *)0)->ut_user))
80 84 #define COLON_CHAR ':'
81 85
82 86 /*
83 87 * Path to DBM files. This is only required for N2L mode. Traditional mode
84 88 * works with the source files and uses the NIS Makefile to generate the maps.
85 89 * Seems to be hard coded in the rest of NIS so same is done here.
86 90 */
87 91 #define YPDBPATH "/var/yp"
88 92
89 93 /* Names of password and adjunct mappings. Used to access DIT */
90 94 #define BYNAME ".byname"
91 95 #define BYUID ".byuid"
92 96 #define BYGID ".bygid"
93 97 #define PASSWD_MAPPING "passwd" BYNAME
94 98 #define PASSWD_ADJUNCT_MAPPING "passwd.adjunct" BYNAME
95 99 #define AGEING_MAPPING "ageing" BYNAME
96 100
97 101 /* Bitmasks used in list of fields to change */
98 102 #define CNG_PASSWD 0x0001
99 103 #define CNG_SH 0x0002
100 104 #define CNG_GECOS 0x0004
101 105
102 106 /* Globals :-( */
103 107 extern int single, nogecos, noshell, nopw, mflag;
104 108
105 109 /*
106 110 * Structure for containing the information is currently in the DIT. This is
107 111 * similar to the passwd structure defined in getpwent(3C) apart from.
108 112 *
109 113 * 1. Since GID and UID are never changed they are not converted to integers.
110 114 * 2. There are extra fields to hold adjunct information.
111 115 * 3. There are extra fields to hold widely used information.
112 116 */
113 117 struct passwd_entry {
114 118 char *pw_name;
115 119 char *pw_passwd;
116 120 char *pw_uid;
117 121 char *pw_gid;
118 122 char *pw_gecos;
119 123 char *pw_dir;
120 124 char *pw_shell;
121 125 char *adjunct_tail; /* Tail of adjunct entry (opaque) */
122 126 bool_t adjunct; /* Flag indicating if DIT has adjunct info */
123 127 char *pwd_str; /* New password string */
124 128 char *adjunct_str; /* New adjunct string */
125 129 };
126 130
127 131 /* Prototypes */
128 132 extern bool_t validloginshell(char *sh, char *arg, int);
129 133 extern int validstr(char *str, size_t size);
130 134
131 135 suc_code write_shadow_info(char *, struct spwd *);
132 136 int put_new_info(struct passwd_entry *, char *);
133 137 char *create_pwd_str(struct passwd_entry *, bool_t);
134 138 int proc_domain(struct yppasswd *, bool_t, char *);
135 139 int proc_request(struct yppasswd *, struct passwd_entry *, bool_t, char *);
136 140 int modify_ent(struct yppasswd *, struct passwd_entry *t, bool_t, char *);
137 141 int get_change_list(struct yppasswd *, struct passwd_entry *);
138 142 struct passwd_entry *get_old_info(char *, char *);
139 143 static char *get_next_token(char *, char **, char *);
140 144 void free_pwd_entry(struct passwd_entry *);
141 145 struct spwd *get_old_shadow(char *, char *);
142 146 suc_code decode_shadow_entry(datum *, struct spwd *);
143 147 void free_shadow_entry(struct spwd *);
144 148 int proc_maps(char *, struct passwd_entry *);
145 149 int proc_map_list(char **, char *, struct passwd_entry *, bool_t);
146 150 int update_single_map(char *, struct passwd_entry *, bool_t);
147 151 bool_t strend(char *s1, char *s2);
148 152
149 153 /*
150 154 * FUNCTION: shim_changepasswd()
151 155 *
152 156 * DESCRIPTION: N2L version of changepasswd(). When this is called 'useshadow'
153 157 * etc. will have been set up but are meaningless. We work out
154 158 * what to change based on information from the DIT.
155 159 *
156 160 * INPUTS: Identical to changepasswd()
157 161 *
158 162 * OUTPUTS: Identical to changepasswd()
159 163 */
160 164 void
161 165 shim_changepasswd(SVCXPRT *transp)
162 166 {
163 167 struct yppasswd yppwd;
164 168 bool_t root_on_master = FALSE;
165 169 char domain[MAXNETNAMELEN+1];
166 170 char **domain_list;
167 171 int dom_count, i;
168 172
169 173 int ret, ans = 2; /* Answer codes */
170 174
171 175 /* Clean out yppwd ... maybe we don't trust RPC */
172 176 memset(&yppwd, 0, sizeof (struct yppasswd));
173 177
174 178 /* Get the RPC args */
175 179 if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) {
176 180 svcerr_decode(transp);
177 181 return;
178 182 }
179 183
180 184 /* Perform basic validation */
181 185 if ((!validstr(yppwd.newpw.pw_passwd, CRYPTPWSIZE)) ||
182 186 (!validstr(yppwd.newpw.pw_name, UTUSERLEN)) ||
183 187 (!validstr(yppwd.newpw.pw_gecos, FINGERSIZE)) ||
184 188 (!validstr(yppwd.newpw.pw_shell, SHELLSIZE))) {
185 189 svcerr_decode(transp);
186 190 return;
187 191 }
188 192
189 193 /*
190 194 * Special case: root on the master server can change other
191 195 * users' passwords without first entering the old password.
192 196 * We need to ensure that this is indeed root on the master
193 197 * server. (bug 1253949)
194 198 */
195 199 if (strcmp(transp->xp_netid, "ticlts") == 0) {
196 200 svc_local_cred_t cred;
197 201 if (!svc_get_local_cred(transp, &cred)) {
198 202 logmsg(MSG_NOTIMECHECK, LOG_ERR,
199 203 "Couldn't get local user credentials");
200 204 } else if (cred.ruid == 0)
201 205 root_on_master = TRUE;
202 206 }
203 207
204 208 /*
205 209 * Get the domain name. This is tricky because a N2L server may be
206 210 * handling multiple domains. There is nothing in the request to
207 211 * indicate which one we are trying to change a passwd for. First
208 212 * we try to get a list of password related domains from the mapping
209 213 * file.
210 214 */
211 215 if (0 !=
212 216 (dom_count = get_mapping_yppasswdd_domain_list(&domain_list))) {
213 217 /* Got a domain list ... process all the domains */
214 218 for (i = 0; i < dom_count; i ++) {
215 219 ret = proc_domain(&yppwd, root_on_master,
216 220 domain_list[i]);
217 221
218 222 /* If one has worked don't care if others fail */
219 223 if (0 != ans)
220 224 ans = ret;
221 225 }
222 226 }
223 227 else
224 228 {
225 229 /*
226 230 * There was no domain list in the mapping file. The
227 231 * traditional version of this code calls ypmake which picks
228 232 * up the domain returned by getdomainname(). Fall back to the
229 233 * same mechanism.
230 234 */
231 235 if (0 > getdomainname(domain, MAXNETNAMELEN+1)) {
232 236 logmsg(MSG_NOTIMECHECK, LOG_ERR,
233 237 "Could not get any domain info");
234 238 } else {
235 239 /* Got one domain ... process it. */
236 240 ans = proc_domain(&yppwd, root_on_master, domain);
237 241 }
238 242 }
239 243
240 244 /* Send reply packet */
241 245 if (!svc_sendreply(transp, xdr_int, (char *)&ans))
242 246 logmsg(MSG_NOTIMECHECK, LOG_WARNING,
243 247 "could not reply to RPC call");
244 248 }
245 249
246 250 /*
247 251 * FUNCTION : proc_domain()
248 252 *
249 253 * DESCRIPTION: Process a request for one domain
250 254 *
251 255 * GIVEN : Pointer to the request.
252 256 * Root on master flag
253 257 * Domain
254 258 *
255 259 * OUTPUTS : Answer code for reply
256 260 */
257 261 int
258 262 proc_domain(struct yppasswd *yppwd, bool_t root_on_master, char *domain)
259 263 {
260 264 struct passwd_entry *old_pwd;
261 265 char *p;
262 266 int ans = 2;
263 267
264 268 /* security hole fix from original source */
265 269 for (p = yppwd->newpw.pw_name; (*p != '\0'); p++)
266 270 if ((*p == ':') || !(isprint(*p)))
267 271 *p = '$'; /* you lose buckwheat */
268 272 for (p = yppwd->newpw.pw_passwd; (*p != '\0'); p++)
269 273 if ((*p == ':') || !(isprint(*p)))
270 274 *p = '$'; /* you lose buckwheat */
271 275
272 276 /* Get old info from DIT for this domain */
273 277 old_pwd = get_old_info(yppwd->newpw.pw_name, domain);
274 278 if (NULL == old_pwd) {
275 279 logmsg(MSG_NOTIMECHECK, LOG_ERR,
276 280 "Could not get old information for %s in "
277 281 "domain %s", yppwd->newpw.pw_name, domain);
278 282 return (ans);
279 283 }
280 284
281 285 /* Have a request that can be replied to */
282 286 ans = proc_request(yppwd, old_pwd, root_on_master, domain);
283 287 free_pwd_entry(old_pwd);
284 288
285 289 return (ans);
286 290 }
287 291
288 292 /*
289 293 * FUNCTION : proc_request()
290 294 *
291 295 * DESCRIPTION: Process a request
292 296 *
293 297 * GIVEN : Pointer to the request.
294 298 * Pointer to old information from LDAP
295 299 * Root on master flag
296 300 * Domain
297 301 *
298 302 * OUTPUTS : Answer code for reply
299 303 */
300 304 int
301 305 proc_request(struct yppasswd *yppwd, struct passwd_entry *old_pwd,
302 306 bool_t root_on_master, char *domain)
303 307 {
304 308 struct sigaction sa, osa1, osa2, osa3;
305 309 int ans;
306 310
307 311 /* Authenticate */
308 312 if ((0 != strcmp(crypt(yppwd->oldpass, old_pwd->pw_passwd),
309 313 old_pwd->pw_passwd)) && !root_on_master) {
310 314 logmsg(MSG_NOTIMECHECK, LOG_NOTICE, "Passwd incorrect %s",
311 315 yppwd->newpw.pw_name);
312 316 return (7);
313 317 }
314 318
315 319 /* Work out what we have to change and change it */
316 320 ans = modify_ent(yppwd, old_pwd, root_on_master, domain);
317 321 if (0 != ans)
318 322 return (ans);
319 323
320 324 /*
321 325 * Generate passwd and adjunct map entries. This creates extra
322 326 * malloced strings in old_pwd. These will be freed when
323 327 * free_pwd_entry() is called to free up the rest of the structure.
324 328 */
325 329 old_pwd->pwd_str = create_pwd_str(old_pwd, FALSE);
326 330 if (NULL == old_pwd->pwd_str) {
327 331 logmsg(MSG_NOTIMECHECK, LOG_ERR,
328 332 "Could not create passwd entry");
329 333 return (2);
330 334 }
331 335 if (old_pwd->adjunct) {
332 336 old_pwd->adjunct_str = create_pwd_str(old_pwd, TRUE);
333 337 if (NULL == old_pwd->adjunct_str) {
334 338 logmsg(MSG_NOTIMECHECK, LOG_ERR,
335 339 "Could not create adjunct entry");
336 340 return (2);
337 341 }
338 342 } else {
339 343 old_pwd->adjunct_str = NULL;
340 344 }
341 345
342 346 /* Put the information back to DIT */
343 347 ans = put_new_info(old_pwd, domain);
344 348 if (0 != ans) {
345 349 return (ans);
346 350 }
347 351
348 352 /* Are going to be forking pushes, set up signals */
349 353 memset(&sa, 0, sizeof (struct sigaction));
350 354 sa.sa_handler = SIG_IGN;
351 355 sigaction(SIGTSTP, &sa, (struct sigaction *)0);
352 356 sigaction(SIGHUP, &sa, &osa1);
353 357 sigaction(SIGINT, &sa, &osa2);
354 358 sigaction(SIGQUIT, &sa, &osa3);
355 359
356 360 /* Update and push all the maps */
357 361 ans = proc_maps(domain, old_pwd);
358 362
359 363 /* Tidy up signals */
360 364 sigaction(SIGHUP, &osa1, (struct sigaction *)0);
361 365 sigaction(SIGINT, &osa2, (struct sigaction *)0);
362 366 sigaction(SIGQUIT, &osa3, (struct sigaction *)0);
363 367
364 368 return (ans);
365 369 }
366 370
367 371 /*
368 372 * FUNCTION: proc_maps()
369 373 *
370 374 * DESCRIPTION: Gets all the map lists and processes them.
371 375 *
372 376 * INPUTS: Domain name
373 377 * New info to write into maps
374 378 *
375 379 * OUTPUT : Answer code
376 380 */
377 381 int
378 382 proc_maps(char *domain, struct passwd_entry *pwd)
379 383 {
380 384 char **map_list; /* Array of passwd or adjunct maps */
381 385 int ans = 0;
382 386
383 387 /* Get list of passwd maps from mapping file */
384 388 map_list = get_passwd_list(FALSE, domain);
385 389 if (map_list != NULL) {
386 390 /* Process list of passwd maps */
387 391 ans = proc_map_list(map_list, domain, pwd, FALSE);
388 392 free_passwd_list(map_list);
389 393 if (0 != ans)
390 394 return (ans);
391 395 }
392 396
393 397 /*
394 398 * If we get here either there were no passwd maps or there were
395 399 * some and they were processed successfully. Either case is good
396 400 * continue and process passwd.adjunct maps.
397 401 */
398 402
399 403 /* Get list of adjunct maps from mapping file */
400 404 map_list = get_passwd_list(TRUE, domain);
401 405 if (map_list != NULL) {
402 406 /*
403 407 * Process list of adjunct maps. If the required information
404 408 * is not present in LDAP then the updates attempts will log
405 409 * an error. No need to make the check here
406 410 */
407 411 ans = proc_map_list(map_list, domain, pwd, TRUE);
408 412 free_passwd_list(map_list);
409 413 }
410 414
411 415 return (ans);
412 416 }
413 417
414 418 /*
415 419 * FUNCTION: proc_map_list()
416 420 *
417 421 * DESCRIPTION: Finds entries in one list of map that need to be updated.
418 422 * updates them and writes them back.
419 423 *
420 424 * INPUTS: Null terminated list of maps to process.
421 425 * Domain name
422 426 * Information to write (including user name)
423 427 * Flag indicating if this is the adjunct list
424 428 *
425 429 * OUTPUTS: An error code
↓ open down ↓ |
343 lines elided |
↑ open up ↑ |
426 430 */
427 431 int
428 432 proc_map_list(char **map_list, char *domain,
429 433 struct passwd_entry *pwd, bool_t adjunct_flag)
430 434 {
431 435 char *myself = "proc_map_list";
432 436 char *map_name;
433 437 char cmdbuf[BUFSIZ];
434 438 int map_name_len = 0;
435 439 int index, ans = 0;
436 - int res;
437 440
438 441 /* If this is a adjunct list check LDAP had some adjunct info */
439 442 if ((adjunct_flag) && (!pwd->adjunct)) {
440 443 logmsg(MSG_NOTIMECHECK, LOG_INFO,
441 444 "Have adjunct map list but no adjunct data in DIT");
442 445 /* Not a disaster */
443 446 return (0);
444 447 }
445 448
446 449 /* Allocate enough buffer to take longest map name */
447 450 for (index = 0; map_list[index] != NULL; index ++)
448 451 if (map_name_len < strlen(map_list[index]))
449 452 map_name_len = strlen(map_list[index]);
450 453 map_name_len += strlen(YPDBPATH);
451 454 map_name_len += strlen(NTOL_PREFIX);
452 455 map_name_len += strlen(domain);
453 456 map_name_len += 3;
454 457 if (NULL == (map_name = am(myself, map_name_len))) {
455 458 logmsg(MSG_NOMEM, LOG_ERR, "Could not alloc map name");
456 459 return (2);
457 460 }
458 461
459 462 /* For all maps in list */
460 463 for (index = 0; map_list[index] != NULL; index ++) {
461 464
462 465 /* Generate full map name */
463 466 strcpy(map_name, YPDBPATH);
464 467 add_separator(map_name);
465 468 strcat(map_name, domain);
466 469 add_separator(map_name);
467 470 strcat(map_name, NTOL_PREFIX);
468 471 strcat(map_name, map_list[index]);
469 472
470 473 if (0 != (ans = update_single_map(map_name, pwd, adjunct_flag)))
471 474 break;
472 475 }
473 476
474 477 /* Done with full map path */
475 478 sfree(map_name);
476 479
477 480 /*
478 481 * If (ans != 0) then one more maps have failed. LDAP has however been
479 482 * updates. This is the definitive source for information there is no
480 483 * need to unwind. (This was probably due to maps that were already
481 484 * corrupt).
482 485 */
483 486
484 487 /*
485 488 * If it all worked fork off push operations for the maps. Since we
486 489 * want the map to end up with it's traditional name on the slave send
487 490 * the name without its LDAP_ prefix. The slave will call ypxfrd
488 491 * which, since it is running in N2L mode, will put the prefix back on
489 492 * before reading the file.
490 493 */
491 494 if (mflag && (0 == ans)) {
492 495 for (index = 0; (map_name = map_list[index]) != NULL;
493 496 index ++) {
494 497 if (fork() == 0) {
495 498 /*
496 499 * Define full path to yppush. Probably also
497 500 * best for security.
498 501 */
499 502 strcpy(cmdbuf, "/usr/lib/netsvc/yp/yppush ");
500 503 strcat(cmdbuf, map_name);
501 504 if (0 > system(cmdbuf))
502 505 logmsg(MSG_NOTIMECHECK, LOG_ERR,
503 506 "Could not initiate yppush");
504 507 exit(0);
505 508 }
506 509 }
507 510 }
508 511 return (ans);
509 512 }
510 513
511 514 /*
512 515 * FUNCTION : update_single_map()
513 516 *
514 517 * DESCRIPTION: Updates one map. This is messy because we want to lock the map
515 518 * to prevent other processes from updating it at the same time.
516 519 * This mandates that we open it using the shim. When we
517 520 * write to it however we DO NOT want to write through to LDAP
518 521 * i.e. do not want to use the shim.
519 522 *
520 523 * Solution : Do not include shim_hooks.h but call the shim
521 524 * versions of dbm_functions explicitly where needed.
522 525 *
523 526 * INPUT : Full name of map
524 527 * Information to write (including user name)
525 528 * Flag indicating if this is an adjunct map.
526 529 *
527 530 * OUTPUT : Answer code
528 531 *
529 532 */
530 533 int
531 534 update_single_map(char *map_name, struct passwd_entry *pwd, bool_t adjunct_flag)
532 535 {
533 536 DBM *map;
534 537 int res;
535 538 datum data, key;
536 539
537 540 /* Set up data */
538 541 if (adjunct_flag)
539 542 data.dptr = pwd->adjunct_str;
540 543 else
541 544 data.dptr = pwd->pwd_str;
542 545 data.dsize = strlen(data.dptr);
543 546
544 547 /* Set up key dependent on which type of map this is */
545 548 key.dptr = NULL;
546 549 if (strend(map_name, BYNAME))
547 550 key.dptr = pwd->pw_name;
548 551 if (strend(map_name, BYUID))
549 552 key.dptr = pwd->pw_uid;
550 553 if (strend(map_name, BYGID))
551 554 key.dptr = pwd->pw_gid;
552 555
553 556 if (NULL == key.dptr) {
554 557 logmsg(MSG_NOTIMECHECK, LOG_ERR,
555 558 "Unrecognized map type %s", map_name);
556 559 return (0); /* Next map */
557 560 }
558 561 key.dsize = strlen(key.dptr);
559 562
560 563 /* Open the map */
561 564 map = shim_dbm_open(map_name, O_RDWR, 0600);
562 565 if (NULL == map) {
563 566 logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not open %s", map_name);
564 567 return (0); /* Next map */
565 568 }
566 569
567 570 /* Lock map for update. Painful and may block but have to do it */
568 571 if (SUCCESS != lock_map_update((map_ctrl *)map)) {
569 572 logmsg(MSG_NOTIMECHECK, LOG_ERR,
570 573 "Could not lock map %s for update", map_name);
571 574 shim_dbm_close(map);
572 575 return (2);
573 576 }
574 577
575 578 /* Do the update use simple DBM operation */
576 579 res = dbm_store(((map_ctrl *)map)->entries, key, data, DBM_REPLACE);
577 580
578 581 /* update entry TTL. If we fail not a problem will just timeout early */
579 582 update_entry_ttl((map_ctrl *)map, &key, TTL_RAND);
580 583
581 584 /*
582 585 * Map has been modified so update YP_LAST_MODIFIED. In the vanilla
583 586 * NIS case this would have been done by the ypmake done after updating
584 587 * the passwd source file. If this fails not a great problem the map
585 588 */
586 589 if (FAILURE == update_timestamp(((map_ctrl *)map)->entries)) {
587 590 logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not update "
588 591 "YP_LAST_MODIFIED %s will not be pushed this time",
589 592 map_name);
590 593 }
591 594
592 595 /*
593 596 * Possibly should hold the lock until after push is complete
594 597 * but this could deadlock if client is slow and ypxfrd also
595 598 * decides to do an update.
596 599 */
597 600 unlock_map_update((map_ctrl *)map);
598 601
599 602 /* Close the map */
600 603 shim_dbm_close(map);
601 604
602 605 if (0 != res) {
603 606 logmsg(MSG_NOTIMECHECK, LOG_ERR,
604 607 "Could not update map %s", map_name);
605 608 return (2);
606 609 }
607 610
608 611 return (0);
609 612 }
610 613
611 614 /*
612 615 * FUNCTION : strend()
613 616 *
614 617 * DESCRIPTION: Determines if one string ends with another.
615 618 */
616 619 bool_t
617 620 strend(char *s1, char *s2)
618 621 {
619 622 int len_dif;
620 623
621 624 len_dif = strlen(s1) - strlen(s2);
622 625 if (0 > len_dif)
623 626 return (FALSE);
624 627 if (0 == strcmp(s1 + len_dif, s2))
625 628 return (TRUE);
626 629 return (FALSE);
627 630 }
628 631
629 632 /*
630 633 * FUNCTION: modify_ent()
631 634 *
632 635 * DESCRIPTION: Modify an entry to reflect a request.
633 636 *
634 637 * INPUT: Pointer to the request.
635 638 * Pointer to the entry to modify.
636 639 * Flag indication if we are root on master
637 640 * Domain
638 641 *
639 642 * OUTPUT: Error code
640 643 */
641 644 int
642 645 modify_ent(struct yppasswd *yppwd, struct passwd_entry *old_ent,
643 646 bool_t root_on_master, char *domain)
644 647 {
645 648 int change_list;
646 649 struct spwd *shadow;
647 650 time_t now;
648 651
649 652 /* Get list of changes */
650 653 change_list = get_change_list(yppwd, old_ent);
651 654
652 655 if (!change_list) {
653 656 logmsg(MSG_NOTIMECHECK, LOG_NOTICE,
654 657 "No change for %s", yppwd->newpw.pw_name);
655 658 return (3);
656 659 }
657 660
658 661 /* Check that the shell we have been given is acceptable. */
659 662 if ((change_list & CNG_SH) && (!validloginshell(old_ent->pw_shell,
660 663 yppwd->newpw.pw_shell, root_on_master)))
661 664 return (2);
662 665
663 666 /*
664 667 * If changing the password do any aging checks.
665 668 * Since there are no shadow maps this is done by accessing
666 669 * attributes in the DIT via the mapping system.
667 670 */
668 671 if (change_list & CNG_PASSWD) {
669 672
670 673 /* Try to get shadow information */
671 674 shadow = get_old_shadow(yppwd->newpw.pw_name, domain);
672 675
673 676 /* If there is shadow information make password aging checks */
674 677 if (NULL != shadow) {
675 678 now = DAY_NOW;
676 679 /* password aging - bug for bug compatibility */
677 680 if (shadow->sp_max != -1) {
678 681 if (now < shadow->sp_lstchg + shadow->sp_min) {
679 682 logmsg(MSG_NOTIMECHECK, LOG_ERR,
680 683 "Sorry: < %ld days since "
681 684 "the last change", shadow->sp_min);
682 685 free_shadow_entry(shadow);
683 686 return (2);
684 687 }
685 688 }
686 689
687 690 /* Update time of change */
688 691 shadow->sp_lstchg = now;
689 692
690 693 /* Write it back */
691 694 write_shadow_info(domain, shadow);
692 695
693 696 free_shadow_entry(shadow);
694 697 }
695 698 }
696 699
697 700 /* Make changes to old entity */
698 701 if (change_list & CNG_GECOS) {
699 702 if (NULL != old_ent->pw_gecos)
700 703 sfree(old_ent->pw_gecos);
701 704 old_ent->pw_gecos = strdup(yppwd->newpw.pw_gecos);
702 705 if (NULL == old_ent->pw_gecos) {
703 706 logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate gecos");
704 707 return (2);
705 708 }
706 709 }
707 710
708 711 if (change_list & CNG_SH) {
709 712 if (NULL != old_ent->pw_shell)
710 713 sfree(old_ent->pw_shell);
711 714 old_ent->pw_shell = strdup(yppwd->newpw.pw_shell);
712 715 if (NULL == old_ent->pw_shell) {
713 716 logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate shell");
714 717 return (2);
715 718 }
716 719 }
717 720
718 721 if (change_list & CNG_PASSWD) {
719 722 if (NULL != old_ent->pw_passwd)
720 723 sfree(old_ent->pw_passwd);
721 724 old_ent->pw_passwd = strdup(yppwd->newpw.pw_passwd);
722 725 if (NULL == old_ent->pw_passwd) {
723 726 logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate passwd");
724 727 return (2);
725 728 }
726 729 }
727 730
728 731 return (0);
729 732 }
730 733
731 734 /*
732 735 * FUNCTION : get_change_list()
733 736 *
734 737 * DESCRIPTION: Works out what we have to change.
735 738 *
736 739 * INPUTS : Request.
737 740 * Structure containing current state of entry
738 741 *
739 742 * OUTPUTS : A bitmask signaling what to change. (Implemented in this
740 743 * way to make it easy to pass between functions).
741 744 */
742 745 int
743 746 get_change_list(struct yppasswd *yppwd, struct passwd_entry *old_ent)
744 747 {
745 748 int list = 0;
746 749 char *p;
747 750
748 751 p = yppwd->newpw.pw_passwd;
749 752 if ((!nopw) &&
750 753 p && *p &&
751 754 !(*p++ == '#' && *p++ == '#' &&
752 755 (strcmp(p, old_ent->pw_name) == 0)) &&
753 756 (strcmp(crypt(old_ent->pw_passwd,
754 757 yppwd->newpw.pw_passwd), yppwd->newpw.pw_passwd) != 0))
755 758 list |= CNG_PASSWD;
756 759
757 760 if ((NULL != old_ent->pw_shell) &&
758 761 (!noshell) &&
759 762 (strcmp(old_ent->pw_shell, yppwd->newpw.pw_shell) != 0)) {
760 763 if (single)
761 764 list = 0;
762 765 list |= CNG_SH;
763 766 }
764 767
765 768 if ((NULL != old_ent->pw_gecos) &&
766 769 (!nogecos) &&
767 770 (strcmp(old_ent->pw_gecos, yppwd->newpw.pw_gecos) != 0)) {
768 771 if (single)
769 772 list = 0;
770 773 list |= CNG_GECOS;
771 774 }
772 775
773 776 return (list);
774 777 }
775 778
776 779 /*
777 780 * FUNCTION : decode_pwd_entry()
778 781 *
779 782 * DESCRIPTION: Pulls apart a password entry. Because the password entry has
780 783 * come from the mapping system it can be assumed to be correctly
781 784 * formatted and relatively simple parsing can be done.
782 785 *
783 786 * Substrings are put into malloced memory. Caller to free.
784 787 *
785 788 * For adjunct files most of it is left empty.
786 789 *
787 790 * It would be nice to use getpwent and friends for this work but
788 791 * these only seem to exist for files and it seems excessive to
789 792 * create a temporary file for this operation.
790 793 *
791 794 * INPUTS: Pointer to datum containing password string.
792 795 * Pointer to structure in which to return results
793 796 * Flag indicating if we are decoding passwd or passwd.adjunct
794 797 *
795 798 * OUTPUTS: SUCCESS = Decoded successfully
796 799 * FAILURE = Not decoded successfully. Caller to tidy up.
797 800 */
798 801 suc_code
799 802 decode_pwd_entry(datum *data, struct passwd_entry *pwd, bool_t adjunct)
800 803 {
801 804 char *myself = "decode_pwd_entry";
802 805 char *p, *str_end, *temp;
803 806
804 807 /* Work out last location in string */
805 808 str_end = data->dptr + data->dsize;
806 809
807 810 /* Name */
808 811 if (NULL == (p = get_next_token(data->dptr, &temp, str_end)))
809 812 return (FAILURE);
810 813 if (adjunct) {
811 814 /* If we found an adjunct version this is the one to use */
812 815 if (NULL != pwd->pw_name)
813 816 sfree(pwd->pw_name);
814 817 }
815 818 pwd->pw_name = temp;
816 819
817 820 /* Password */
818 821 if (NULL == (p = get_next_token(p, &temp, str_end)))
819 822 return (FAILURE);
820 823 if (adjunct) {
821 824 /* If we found an adjunct version this is the one to use */
822 825 if (NULL != pwd->pw_passwd)
823 826 sfree(pwd->pw_passwd);
824 827 }
825 828 pwd->pw_passwd = temp;
826 829
827 830 if (adjunct) {
828 831 /* Store adjunct information in opaque string */
829 832 pwd->adjunct_tail = am(myself, str_end - p + 1);
830 833 if (NULL == pwd->adjunct_tail)
831 834 return (FAILURE);
832 835 strncpy(pwd->adjunct_tail, p, str_end - p);
833 836 pwd->adjunct_tail[str_end - p] = '\0';
834 837
835 838 /* Remember that LDAP contained adjunct data */
836 839 pwd->adjunct = TRUE;
837 840 return (SUCCESS);
838 841 }
839 842
840 843 /* If we get here not adjunct. Decode rest of passwd */
841 844
842 845 /* UID */
843 846 if (NULL == (p = get_next_token(p, &(pwd->pw_uid), str_end)))
844 847 return (FAILURE);
845 848
846 849 /* GID */
847 850 if (NULL == (p = get_next_token(p, &(pwd->pw_gid), str_end)))
848 851 return (FAILURE);
849 852
850 853 /* Gecos */
851 854 if (NULL == (p = get_next_token(p, &(pwd->pw_gecos), str_end)))
852 855 return (FAILURE);
853 856
854 857 /* Home dir */
855 858 if (NULL == (p = get_next_token(p, &(pwd->pw_dir), str_end)))
856 859 return (FAILURE);
857 860
858 861 /* Shell may not be present so don't check return */
859 862 get_next_token(p, &(pwd->pw_shell), str_end);
860 863
861 864 if (NULL == pwd->pw_shell)
862 865 return (FAILURE);
863 866
864 867 return (SUCCESS);
865 868 }
866 869
867 870 /*
868 871 * FUNCTION : get_next_token()
869 872 *
870 873 * DESCRIPTION: Gets the next token from a string upto the next colon or the
871 874 * end of the string. The duplicates this token into malloced
872 875 * memory removing any spaces.
873 876 *
874 877 * INPUTS : String to search for token. NOT NULL TERMINATED
875 878 * Location to return result (NULL if result not required)
876 879 * Last location in string
877 880 *
878 881 * OUTPUT : Pointer into the string immediately after the token.
879 882 * NULL if end of string reached or error.
880 883 */
881 884 static char *
882 885 get_next_token(char *str, char **op, char *str_end)
883 886 {
884 887 char *myself = "get_next_token";
885 888 char *p, *tok_start, *tok_end;
886 889
887 890 p = str;
888 891 /* Skip leading whitespace */
889 892 while (' ' == *p)
890 893 p++;
891 894 tok_start = p;
892 895 tok_end = p;
893 896
894 897 while ((str_end + 1 != p) && (COLON_CHAR != *p)) {
895 898 if (' ' != *p)
896 899 tok_end = p;
897 900 p++;
898 901 }
899 902
900 903 /* Required string is now between start and end */
901 904 if (NULL != op) {
902 905 *op = am(myself, tok_end - tok_start + 2);
903 906 if (NULL == *op) {
904 907 logmsg(MSG_NOMEM, LOG_ERR,
905 908 "Could not alloc memory for token");
906 909 return (NULL);
907 910 }
908 911 strncpy(*op, tok_start, tok_end - tok_start + 1);
909 912
910 913 /* Terminate token */
911 914 (*op)[tok_end - tok_start + 1] = '\0';
912 915
913 916 }
914 917
915 918 /* Check if we reached the end of the input string */
916 919 if ('\0' == *p)
917 920 return (NULL);
918 921
919 922 /* There is some more */
920 923 p++;
921 924 return (p);
922 925 }
923 926
924 927 /*
925 928 * FUNCTION : free_pwd_entry()
926 929 *
927 930 * DESCRIPTION: Frees up a pwd_entry structure and its contents.
928 931 *
929 932 * INPUTS: Pointer to the structure to free.
930 933 *
931 934 * OUTPUT: Nothing
932 935 */
933 936 void
934 937 free_pwd_entry(struct passwd_entry *pwd)
935 938 {
936 939 /* Free up strings */
937 940 if (NULL != pwd->pw_name)
938 941 sfree(pwd->pw_name);
939 942
940 943 if (NULL != pwd->pw_passwd)
941 944 sfree(pwd->pw_passwd);
942 945
943 946 if (NULL != pwd->pw_gecos)
944 947 sfree(pwd->pw_gecos);
945 948
946 949 if (NULL != pwd->pw_shell)
947 950 sfree(pwd->pw_shell);
948 951
949 952 if (NULL != pwd->pw_dir)
950 953 sfree(pwd->pw_dir);
951 954
952 955 if (NULL != pwd->adjunct_tail)
953 956 sfree(pwd->adjunct_tail);
954 957
955 958 if (NULL != pwd->pwd_str)
956 959 sfree(pwd->pwd_str);
957 960
958 961 if (NULL != pwd->adjunct_str)
959 962 sfree(pwd->adjunct_str);
960 963
961 964 /* Free up structure */
962 965 sfree(pwd);
963 966 }
964 967
965 968 /*
966 969 * FUNCTION : create_pwd_str()
967 970 *
968 971 * DESCRIPTION: Builds up a new password entity string from a passwd structure.
969 972 *
970 973 * INPUTS : Structure containing password details
971 974 * Flag indicating if we should create an adjunct or passwd string.
972 975 *
973 976 * OUTPUTS : String in malloced memory (to be freed by caller).
974 977 * NULL on failure.
975 978 */
976 979 char *
977 980 create_pwd_str(struct passwd_entry *pwd, bool_t adjunct)
978 981 {
979 982 char *myself = "create_pwd_str";
980 983 char *s;
981 984 int len;
982 985
983 986 /* Separator string so we can strcat separator onto things */
984 987 char sep_str[2] = {COLON_CHAR, '\0'};
985 988
986 989 /* Work out the size */
987 990 len = strlen(pwd->pw_name) + 1;
988 991 len += strlen(pwd->pw_passwd) + 1;
989 992 if (adjunct) {
990 993 len += strlen(pwd->adjunct_tail) + 1;
991 994 } else {
992 995 len += strlen(pwd->pw_uid) + 1;
993 996 len += strlen(pwd->pw_gid) + 1;
994 997 len += strlen(pwd->pw_gecos) + 1;
995 998 len += strlen(pwd->pw_dir) + 1;
996 999 len += strlen(pwd->pw_shell) + 1;
997 1000 }
998 1001
999 1002 /* Allocate some memory for it */
1000 1003 s = am(myself, len);
1001 1004 if (NULL == s)
1002 1005 return (NULL);
1003 1006
1004 1007 strcpy(s, pwd->pw_name);
1005 1008 strcat(s, sep_str);
1006 1009 if (!adjunct) {
1007 1010 /* Build up a passwd string */
1008 1011
1009 1012 /* If LDAP contains adjunct info then passwd is 'x' */
1010 1013 if (pwd->adjunct) {
1011 1014 strcat(s, "##");
1012 1015 strcat(s, pwd->pw_name);
1013 1016 } else {
1014 1017 strcat(s, pwd->pw_passwd);
1015 1018 }
1016 1019 strcat(s, sep_str);
1017 1020 strcat(s, pwd->pw_uid);
1018 1021 strcat(s, sep_str);
1019 1022 strcat(s, pwd->pw_gid);
1020 1023 strcat(s, sep_str);
1021 1024 strcat(s, pwd->pw_gecos);
1022 1025 strcat(s, sep_str);
1023 1026 strcat(s, pwd->pw_dir);
1024 1027 strcat(s, sep_str);
1025 1028 strcat(s, pwd->pw_shell);
1026 1029 } else {
1027 1030 /* Build up a passwd_adjunct string */
1028 1031 strcat(s, pwd->pw_passwd);
1029 1032 strcat(s, sep_str);
1030 1033 strcat(s, pwd->adjunct_tail);
1031 1034 }
1032 1035
1033 1036 return (s);
1034 1037 }
1035 1038
1036 1039 /*
1037 1040 * FUNCTION: get_old_info()
1038 1041 *
1039 1042 * DESCRIPTION: Gets as much information as possible from LDAP about one user.
1040 1043 *
1041 1044 * This goes through the mapping system. This is messy because
1042 1045 * them mapping system will build up a password entry from the
1043 1046 * contents of the DIT. We then have to parse this to recover
1044 1047 * it's individual fields.
1045 1048 *
1046 1049 * INPUT: Pointer to user name
↓ open down ↓ |
600 lines elided |
↑ open up ↑ |
1047 1050 * Domain
1048 1051 *
1049 1052 * OUTPUT: The info in malloced space. To be freed by caller.
1050 1053 * NULL on failure.
1051 1054 */
1052 1055 struct passwd_entry *
1053 1056 get_old_info(char *name, char *domain)
1054 1057 {
1055 1058 char *myself = "get_old_info";
1056 1059 struct passwd_entry *old_passwd;
1057 - char *p;
1058 1060 datum key, data;
1059 1061 suc_code res;
1060 1062
1061 1063 /* Get the password entry */
1062 1064 key.dptr = name;
1063 1065 key.dsize = strlen(key.dptr);
1064 1066 read_from_dit(PASSWD_MAPPING, domain, &key, &data);
1065 1067 if (NULL == data.dptr) {
1066 1068 logmsg(MSG_NOTIMECHECK, LOG_ERR,
1067 1069 "Could not read old pwd for %s", name);
1068 1070 return (NULL);
1069 1071 }
1070 1072
1071 1073 /* Pull password apart */
1072 1074 old_passwd = am(myself, sizeof (struct passwd_entry));
1073 1075 if (NULL == old_passwd) {
1074 1076 logmsg(MSG_NOMEM, LOG_ERR, "Could not alloc for pwd decode");
1075 1077 sfree(data.dptr);
1076 1078 return (NULL);
1077 1079 }
1078 1080
1079 1081 /* No data yet */
1080 1082 old_passwd->pw_name = NULL;
1081 1083 old_passwd->pw_passwd = NULL;
1082 1084 old_passwd->pw_uid = NULL;
1083 1085 old_passwd->pw_gid = NULL;
1084 1086 old_passwd->pw_gecos = NULL;
1085 1087 old_passwd->pw_dir = NULL;
1086 1088 old_passwd->pw_shell = NULL;
1087 1089 old_passwd->adjunct_tail = NULL;
1088 1090 old_passwd->pwd_str = NULL;
1089 1091 old_passwd->adjunct_str = NULL;
1090 1092 old_passwd->adjunct = FALSE;
1091 1093
1092 1094 res = decode_pwd_entry(&data, old_passwd, FALSE);
1093 1095 sfree(data.dptr);
1094 1096 if (SUCCESS != res) {
1095 1097 free_pwd_entry(old_passwd);
1096 1098 return (NULL);
1097 1099 }
1098 1100
1099 1101 /* Try to get the adjunct entry */
1100 1102 read_from_dit(PASSWD_ADJUNCT_MAPPING, domain, &key, &data);
1101 1103 if (NULL == data.dptr) {
1102 1104 /* Fine just no adjunct data */
1103 1105 old_passwd->adjunct = FALSE;
1104 1106 } else {
1105 1107 res = decode_pwd_entry(&data, old_passwd, TRUE);
1106 1108 sfree(data.dptr);
1107 1109 if (SUCCESS != res) {
1108 1110 free_pwd_entry(old_passwd);
1109 1111 return (NULL);
1110 1112 }
1111 1113 }
1112 1114
1113 1115 return (old_passwd);
1114 1116 }
1115 1117
1116 1118 /*
1117 1119 * FUNCTION : put_new_info()
1118 1120 *
1119 1121 * DESCRIPTION: Generates new map strings and puts them back to LDAP
1120 1122 *
1121 1123 * INPUTS: Info to put back
1122 1124 * Domain
1123 1125 *
1124 1126 * OUTPUT: Answer code.
1125 1127 */
1126 1128 int
1127 1129 put_new_info(struct passwd_entry *pwd, char *domain)
1128 1130 {
1129 1131 datum key, data;
1130 1132
1131 1133 /* Write it back to LDAP */
1132 1134 data.dptr = pwd->pwd_str;
1133 1135 data.dsize = strlen(data.dptr);
1134 1136 key.dptr = pwd->pw_name;
1135 1137 key.dsize = strlen(key.dptr);
1136 1138 if (SUCCESS != write_to_dit(PASSWD_MAPPING, domain, key, data,
1137 1139 TRUE, FALSE))
1138 1140 return (2);
1139 1141
1140 1142
1141 1143 /* If DIT contains adjunct information do the same for adjunct */
1142 1144 if (pwd->adjunct) {
1143 1145 data.dptr = pwd->adjunct_str;
1144 1146 data.dsize = strlen(data.dptr);
1145 1147 key.dptr = pwd->pw_name;
1146 1148 key.dsize = strlen(key.dptr);
1147 1149 if (SUCCESS != write_to_dit(PASSWD_ADJUNCT_MAPPING, domain,
1148 1150 key, data, TRUE, FALSE))
1149 1151 return (2);
1150 1152 }
1151 1153
1152 1154 return (0);
1153 1155
1154 1156 }
1155 1157
1156 1158 /*
1157 1159 * FUNCTION : get_old_shadow()
1158 1160 *
1159 1161 * DESCRIPTION :Extracts and decodes shadow information from the DIT
1160 1162 * See also comments under decode_pwd_entry().
1161 1163 *
1162 1164 * INPUTS : User name
1163 1165 * Domain name
1164 1166 *
1165 1167 * OUTPUT : Shadow information in malloced memory. To be freed by caller.
1166 1168 */
1167 1169 struct spwd *
1168 1170 get_old_shadow(char *name, char *domain)
1169 1171 {
1170 1172 char *myself = "get_old_shadow";
1171 1173 struct spwd *sp;
1172 1174 datum key, data;
1173 1175 suc_code res;
1174 1176
1175 1177 /* Get the info */
1176 1178 key.dptr = name;
1177 1179 key.dsize = strlen(key.dptr); /* Len excluding terminator */
1178 1180 read_from_dit(AGEING_MAPPING, domain, &key, &data);
1179 1181
1180 1182 if (NULL == data.dptr) {
1181 1183 /* OK just have no shadow info in DIT */
1182 1184 return (NULL);
1183 1185 }
1184 1186
1185 1187 /* Pull shadow apart */
1186 1188 if (NULL == (sp = am(myself, sizeof (struct spwd)))) {
1187 1189 logmsg(MSG_NOMEM, LOG_ERR,
1188 1190 "Could not alloc for shadow decode");
1189 1191 sfree(data.dptr);
1190 1192 return (NULL);
1191 1193 }
1192 1194 sp->sp_namp = NULL;
1193 1195 sp->sp_pwdp = NULL;
1194 1196
1195 1197 res = decode_shadow_entry(&data, sp);
1196 1198 sfree(data.dptr);
1197 1199 if (SUCCESS != res) {
1198 1200 free_shadow_entry(sp);
1199 1201 return (NULL);
1200 1202 }
1201 1203
1202 1204 return (sp);
1203 1205 }
1204 1206
1205 1207 /*
1206 1208 * FUNCTION : decode_shadow_entry()
1207 1209 *
1208 1210 * DESCRIPTION: Pulls apart ageing information. For convenience this is stored
1209 1211 * in a partially filled spwd structure.
1210 1212 *
1211 1213 * SEE COMMENTS FOR decode_pwd_entry()
1212 1214 */
1213 1215 suc_code
1214 1216 decode_shadow_entry(datum *data, struct spwd *sp)
1215 1217 {
1216 1218 char *p, *str_end, *temp;
1217 1219
1218 1220 /* Work out last location in string */
1219 1221 str_end = data->dptr + data->dsize;
1220 1222
1221 1223 /* Name */
1222 1224 if (NULL == (p = get_next_token(data->dptr, &(sp->sp_namp), str_end)))
1223 1225 return (FAILURE);
1224 1226
1225 1227 /* date of last change */
1226 1228 if (NULL == (p = get_next_token(p, &temp, str_end)))
1227 1229 return (FAILURE);
1228 1230 sp->sp_lstchg = atoi(temp);
1229 1231
1230 1232 /* min days to passwd change */
1231 1233 if (NULL == (p = get_next_token(p, &temp, str_end)))
1232 1234 return (FAILURE);
1233 1235 sp->sp_min = atoi(temp);
1234 1236
1235 1237 /* max days to passwd change */
1236 1238 if (NULL == (p = get_next_token(p, &temp, str_end)))
1237 1239 return (FAILURE);
1238 1240 sp->sp_max = atoi(temp);
1239 1241
1240 1242 /* warning period */
1241 1243 if (NULL == (p = get_next_token(p, &temp, str_end)))
1242 1244 return (FAILURE);
1243 1245 sp->sp_warn = atoi(temp);
1244 1246
1245 1247 /* max days inactive */
1246 1248 if (NULL == (p = get_next_token(p, &temp, str_end)))
1247 1249 return (FAILURE);
1248 1250 sp->sp_inact = atoi(temp);
1249 1251
1250 1252 /* account expiry date */
1251 1253 if (NULL == (p = get_next_token(p, &temp, str_end)))
1252 1254 return (FAILURE);
1253 1255 sp->sp_expire = atoi(temp);
1254 1256
1255 1257 /* flag */
1256 1258 if (NULL != (p = get_next_token(p, &temp, str_end)))
1257 1259 return (FAILURE);
1258 1260 sp->sp_flag = atoi(temp);
1259 1261
1260 1262 return (SUCCESS);
1261 1263 }
1262 1264
1263 1265 /*
1264 1266 * FUNCTION : write_shadow_info()
1265 1267 *
1266 1268 * DESCRIPTION: Writes shadow information back to the DIT.
1267 1269 *
1268 1270 * INPUTS : Domain
1269 1271 * Information to write
1270 1272 *
1271 1273 * OUTPUT : Success code
1272 1274 *
1273 1275 */
1274 1276 suc_code
1275 1277 write_shadow_info(char *domain, struct spwd *sp)
1276 1278 {
1277 1279 char *myself = "write_shadow_info";
1278 1280 datum key, data;
1279 1281 char *str;
1280 1282 suc_code res;
1281 1283 int len;
1282 1284
1283 1285 /* Work out how long string will be */
1284 1286 len = strlen(sp->sp_namp) + 1;
1285 1287
1286 1288 /*
1287 1289 * Bit crude but if we assume 1 byte is 3 decimal characters
1288 1290 * will get enough buffer for the longs and some spare.
1289 1291 */
1290 1292 len += 7 * (3 * sizeof (long) + 1);
1291 1293
1292 1294 /* Allocate some memory */
1293 1295 str = am(myself, len);
1294 1296 if (NULL == str) {
1295 1297 logmsg(MSG_NOMEM, LOG_ERR, "Could not aloc for shadow write");
1296 1298 return (FAILURE);
1297 1299 }
1298 1300
1299 1301 /* Build up shadow string */
1300 1302 sprintf(str, "%s%c%d%c%d%c%d%c%d%c%d%c%d%c%d",
1301 1303 sp->sp_namp, COLON_CHAR,
1302 1304 sp->sp_lstchg, COLON_CHAR,
1303 1305 sp->sp_min, COLON_CHAR,
1304 1306 sp->sp_max, COLON_CHAR,
1305 1307 sp->sp_warn, COLON_CHAR,
1306 1308 sp->sp_inact, COLON_CHAR,
1307 1309 sp->sp_expire, COLON_CHAR,
1308 1310 sp->sp_flag);
1309 1311
1310 1312 /* Write it */
1311 1313 data.dptr = str;
1312 1314 data.dsize = strlen(data.dptr);
1313 1315 key.dptr = sp->sp_namp;
1314 1316 key.dsize = strlen(key.dptr);
1315 1317 res = write_to_dit(AGEING_MAPPING, domain, key, data, TRUE, FALSE);
1316 1318
1317 1319 sfree(str);
1318 1320 return (res);
1319 1321 }
1320 1322
1321 1323 /*
1322 1324 * FUNCTION : free_shadow_entry()
1323 1325 *
1324 1326 * DESCRIPTION: Frees up a shadow information structure
1325 1327 *
1326 1328 * INPUTS : Structure to free
1327 1329 *
1328 1330 * OUTPUTS : Nothing
1329 1331 */
1330 1332 void
1331 1333 free_shadow_entry(struct spwd *spwd)
1332 1334 {
1333 1335 if (NULL != spwd->sp_namp)
1334 1336 sfree(spwd->sp_namp);
1335 1337
1336 1338 if (NULL != spwd->sp_pwdp)
1337 1339 sfree(spwd->sp_pwdp);
1338 1340
1339 1341 /* No need to free numerics */
1340 1342
1341 1343 /* Free up structure */
1342 1344 sfree(spwd);
1343 1345 }
↓ open down ↓ |
276 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX