]> git.saurik.com Git - apple/system_cmds.git/blame - passwd.tproj/netinfo_passwd.c
system_cmds-279.1.tar.gz
[apple/system_cmds.git] / passwd.tproj / netinfo_passwd.c
CommitLineData
1815bff5
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d904471c
A
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
1815bff5
A
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
d904471c
A
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
1815bff5
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24#include <stdio.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <sys/param.h>
28#include <sys/socket.h>
29#include <net/if.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <sys/ioctl.h>
33#include <errno.h>
34#include <pwd.h>
35#include <netdb.h>
36#include <ctype.h>
37#include <string.h>
38#include <netinfo/ni.h>
39
40extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
41
42static int
43sys_ismyaddress(unsigned long addr)
44{
45 struct ifconf ifc;
46 struct ifreq *ifr;
47 char buf[1024]; /* XXX */
48 int offset;
49 int sock;
50 struct sockaddr_in *sin;
51 int i, len;
52
53 if (addr == htonl(INADDR_LOOPBACK)) return 1;
54
55 sock = socket(AF_INET, SOCK_DGRAM, 0);
56
57 if (sock < 0) return 0;
58
59 ifc.ifc_len = sizeof(buf);
60 ifc.ifc_buf = buf;
61
62 if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0)
63 {
64 close(sock);
65 return 0;
66 }
67
68 offset = 0;
69
70 while (offset <= ifc.ifc_len)
71 {
72 ifr = (struct ifreq *)(ifc.ifc_buf + offset);
73 offset += IFNAMSIZ + ifr->ifr_addr.sa_len;
74
75 if (ifr->ifr_addr.sa_family != AF_INET) continue;
76 if (ioctl(sock, SIOCGIFFLAGS, ifr) < 0) continue;
77
78 sin = (struct sockaddr_in *)&ifr->ifr_addr;
79 if ((ifr->ifr_flags & IFF_UP) &&
80 (!(ifr->ifr_flags & IFF_LOOPBACK)) &&
81 (sin->sin_addr.s_addr == addr))
82 {
83 close(sock);
84 return 1;
85 }
86 }
87
88 close(sock);
89 return 0;
90}
91
92static int
93is_root_on_master(void *d)
94{
95 int uid;
96 char myhostname[MAXHOSTNAMELEN + 1];
97 char *p;
98 ni_index where;
99 ni_proplist pl;
100 int status;
101 ni_id dir;
102 struct sockaddr_in addr;
103 char *tag;
104
105 uid = getuid();
106 if (uid != 0) return 0;
107
108 gethostname(myhostname, MAXHOSTNAMELEN);
109 p = strchr(myhostname, '.');
110 if (p != NULL) *p = '\0';
111
112 status = ni_root(d, &dir);
113 if (status != NI_OK) return 0;
114
115 status = ni_read(d, &dir, &pl);
116 if (status != NI_OK) return 0;
117
118 where = ni_proplist_match(pl, "master", NULL);
119 if (where == NI_INDEX_NULL)
120 {
121 ni_proplist_free(&pl);
122 return 0;
123 }
124
125 if (pl.ni_proplist_val[where].nip_val.ni_namelist_len == 0)
126 {
127 ni_proplist_free(&pl);
128 fprintf(stderr, "No value for NetInfo master property\n");
129 return 0;
130 }
131
132 p = strchr(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], '/');
133 if (p != NULL) *p = '\0';
134
135 p = strchr(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], '.');
136 if (p != NULL) *p = '\0';
137
138 if (!strcmp(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], myhostname))
139 {
140 ni_proplist_free(&pl);
141 return 1;
142 }
143
144 if (!strcmp(pl.ni_proplist_val[where].nip_val.ni_namelist_val[0], "localhost"))
145 {
146 ni_proplist_free(&pl);
147 ni_addrtag(d, &addr, &tag);
148 if (sys_ismyaddress(addr.sin_addr.s_addr)) return 1;
149 }
150
151 ni_proplist_free(&pl);
152 return 0;
153}
154
155static int
156secure_passwords()
157{
158 void *d, *d1;
159 int status;
160 ni_index where;
161 ni_id dir;
162 ni_namelist nl;
163
164 status = ni_open(NULL, ".", &d);
165 while (status == NI_OK)
166 {
167 dir.nii_object = 0;
168 status = ni_lookupprop(d, &dir, "security_options", &nl);
169 if (status == NI_OK)
170 {
171 where = ni_namelist_match(nl, "secure_passwords");
172 if (where != NI_INDEX_NULL)
173 {
174 ni_free(d);
175 return 1;
176 }
177 }
178
179 d1 = d;
180 status = ni_open(d1, "..", &d);
181 ni_free(d1);
182 }
183
184 return 0;
185}
186
187static void
188parse_server_tag(char *str, struct sockaddr_in *server, char **t)
189{
190 /* utility to parse a server/tag string */
191
192 int len, i;
193 char *host, *tag, *slash;
194 struct hostent *hent;
195
196 len = strlen(str);
197
198 /* find the "/" character */
199 slash = index(str, '/');
200
201 /* check to see if the "/" is missing */
202 if (slash == NULL)
203 {
204 fprintf(stderr, "incorrect format \"%s\" for domain name\n", str);
205 exit(1);
206 }
207
208 /* find the location of the '/' */
209 i = slash - str;
210
211 /* check if host string is empty */
212 if (i == 0)
213 {
214 fprintf(stderr, "incorrect format \"%s\" for domain name\n", str);
215 fprintf(stderr, "no server name specified\n");
216 exit(1);
217 }
218
219 /* check if tag string is empty */
220 if (i == (len - 1))
221 {
222 fprintf(stderr, "incorrect format \"%s\" for domain name\n", str);
223 fprintf(stderr, "no tag specified\n");
224 exit(1);
225 }
226
227 /* allocate some space for the host and tag */
228 host = (char *)malloc(i + 1);
229 *t = (char *)malloc(len - i);
230 tag = *t;
231
232 /* copy out the host */
233 strncpy(host, str, i);
234 host[i] = '\0';
235
236 /* copy out the tag */
237 strcpy(tag, slash + 1);
238
239 /* try interpreting the host portion as an address */
240 server->sin_addr.s_addr = inet_addr(host);
241
242 if (server->sin_addr.s_addr == -1)
243 {
244 /* This isn't a valid address. Is it a known hostname? */
245 hent = gethostbyname(host);
246 if (hent != NULL)
247 {
248 /* found a host with that name */
249 bcopy(hent->h_addr, &server->sin_addr, hent->h_length);
250 }
251 else
252 {
253 fprintf(stderr, "Can't find address for %s\n", host);
254 free(host);
255 free(tag);
256 exit(1);
257 }
258 }
259
260 free(host);
261}
262
263static void *
264domain_for_user(char *uname, char *locn, ni_id *dir)
265{
266 char *upath;
267 int status;
268 void *d, *d1;
269 struct sockaddr_in server;
270 char *tag;
271 int bytag;
272
273 /*
274 * Find the user in NetInfo.
275 */
276 upath = malloc(8 + strlen(uname));
277 sprintf(upath, "/users/%s", uname);
278
279 if (locn != NULL)
280 {
281 bytag = 1;
282
283 if (locn[0] == '/') bytag = 0;
284 else if (!strncmp(locn, "./", 2)) bytag = 0;
285 else if (!strncmp(locn, "../", 3)) bytag = 0;
286
287 if (bytag == 1)
288 {
289 parse_server_tag(locn, &server, &tag);
290 d = ni_connect(&server, tag);
291 if (d == (void *)NULL) return (void *)NULL;
292 }
293 else status = ni_open(NULL, locn, &d);
294 status = ni_pathsearch(d, dir, upath);
295 free(upath);
296
297 if (status == NI_OK) return d;
298
299 ni_free(d);
300 return (void *)NULL;
301 }
302
303 status = ni_open(NULL, ".", &d);
304 while (status == NI_OK)
305 {
306 status = ni_pathsearch(d, dir, upath);
307 if (status == NI_OK) break;
308 d1 = d;
309 status = ni_open(d1, "..", &d);
310 ni_free(d1);
311 }
312
313 free(upath);
314
315 if (status == NI_OK) return d;
316 return (void *)NULL;
317}
318
319int
320netinfo_passwd(char *uname, char *locn)
321{
322 char *oldpw;
323 char *newpw;
324 char *oc, *nc;
325 void *d;
326 int status, isroot;
327 ni_id dir;
328 ni_proplist pl;
329 ni_property p;
330 ni_namelist nl;
331 int ni_uid, uid, secure, minlen;
332 ni_index where;
333
334 d = domain_for_user(uname, locn, &dir);
335 if (d == (void *)NULL)
336 {
337 fprintf(stderr, "user %s not found in NetInfo\n", uname);
338 exit(1);
339 }
340
341 /*
342 * Read the passwd and uid from NetInfo.
343 */
344 status = ni_lookupprop(d, &dir, "passwd", &nl);
345 if (status == NI_NOPROP) nl.ni_namelist_len = 0;
346 else if (status != NI_OK)
347 {
348 ni_free(d);
349 fprintf(stderr, "NetInfo read failed: %s\n", ni_error(status));
350 exit(1);
351 }
352
353 oldpw = NULL;
354 if (nl.ni_namelist_len > 0) oldpw = nl.ni_namelist_val[0];
355
356 status = ni_lookupprop(d, &dir, "uid", &nl);
357 if (status != NI_OK)
358 {
359 ni_free(d);
360 fprintf(stderr, "NetInfo read failed: %s\n", ni_error(status));
361 exit(1);
362 }
363
364 ni_uid = -2;
365 if (nl.ni_namelist_len > 0) ni_uid = atoi(nl.ni_namelist_val[0]);
366
367 /*
368 * See if I'm uid 0 on the master host for the user's NetInfo domain.
369 */
370 isroot = is_root_on_master(d);
371 uid = getuid();
372 if ((isroot == 0) && (uid != ni_uid))
373 {
374 ni_free(d);
375 fprintf(stderr, "Permission denied\n");
376 exit(1);
377 }
378
379 /*
380 * Lock onto the master server.
381 */
382 ni_needwrite(d, 1);
383
384 /*
385 * Get the new password
386 */
387 secure = secure_passwords();
388 minlen = 5;
389 if (secure == 1) minlen = 8;
390 getpasswd(uname, isroot, minlen, 0, secure, oldpw, &newpw, &oc, &nc);
391
392 /*
393 * Authenticate if necessary
394 */
395 if (isroot == 0)
396 {
397 ni_setuser(d, uname);
398 ni_setpassword(d, oc);
399 }
400
401 /*
402 * Change the password in NetInfo.
403 */
404 status = ni_read(d, &dir, &pl);
405 if (status != NI_OK)
406 {
407 ni_free(d);
408 fprintf(stderr, "NetInfo read failed: %s\n", ni_error(status));
409 exit(1);
410 }
411
412 p.nip_name = "passwd";
413 p.nip_val.ni_namelist_len = 1;
414 p.nip_val.ni_namelist_val = (ni_name *)malloc(sizeof(ni_name));
415 p.nip_val.ni_namelist_val[0] = newpw;
416
417 where = ni_proplist_match(pl, p.nip_name, NULL);
418 if (where == NI_INDEX_NULL)
419 status = ni_createprop(d, &dir, p, NI_INDEX_NULL);
420 else
421 status = ni_writeprop(d, &dir, where, p.nip_val);
422
423 free(p.nip_val.ni_namelist_val);
424
425 if (status != NI_OK)
426 {
427 ni_free(d);
428 fprintf(stderr, "NetInfo write failed: %s\n", ni_error(status));
429 exit(1);
430 }
431
432 ni_free(d);
433 return (0);
434}