1/*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * auth.c - PPP authentication and phase control.
25 *
26 * Copyright (c) 1993-2002 Paul Mackerras. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 *
32 * 1. Redistributions of source code must retain the above copyright
33 *    notice, this list of conditions and the following disclaimer.
34 *
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in
37 *    the documentation and/or other materials provided with the
38 *    distribution.
39 *
40 * 3. The name(s) of the authors of this software must not be used to
41 *    endorse or promote products derived from this software without
42 *    prior written permission.
43 *
44 * 4. Redistributions of any form whatsoever must retain the following
45 *    acknowledgment:
46 *    "This product includes software developed by Paul Mackerras
47 *     <paulus@samba.org>".
48 *
49 * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
50 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
51 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
52 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
53 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
54 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
55 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
56 *
57 * Derived from main.c, which is:
58 *
59 * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
60 *
61 * Redistribution and use in source and binary forms, with or without
62 * modification, are permitted provided that the following conditions
63 * are met:
64 *
65 * 1. Redistributions of source code must retain the above copyright
66 *    notice, this list of conditions and the following disclaimer.
67 *
68 * 2. Redistributions in binary form must reproduce the above copyright
69 *    notice, this list of conditions and the following disclaimer in
70 *    the documentation and/or other materials provided with the
71 *    distribution.
72 *
73 * 3. The name "Carnegie Mellon University" must not be used to
74 *    endorse or promote products derived from this software without
75 *    prior written permission. For permission or any legal
76 *    details, please contact
77 *      Office of Technology Transfer
78 *      Carnegie Mellon University
79 *      5000 Forbes Avenue
80 *      Pittsburgh, PA  15213-3890
81 *      (412) 268-4387, fax: (412) 268-7395
82 *      tech-transfer@andrew.cmu.edu
83 *
84 * 4. Redistributions of any form whatsoever must retain the following
85 *    acknowledgment:
86 *    "This product includes software developed by Computing Services
87 *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
88 *
89 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
90 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
91 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
92 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
93 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
94 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
95 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
96 */
97
98#define RCSID	"$Id: auth.c,v 1.21.20.1 2006/04/17 18:37:14 callie Exp $"
99
100#include <stdio.h>
101#include <stddef.h>
102#include <stdlib.h>
103#include <unistd.h>
104#include <pwd.h>
105#include <grp.h>
106#include <string.h>
107#include <sys/types.h>
108#include <sys/stat.h>
109#include <sys/socket.h>
110#include <utmpx.h>
111#include <fcntl.h>
112#if defined(_PATH_LASTLOG) && defined(__linux__)
113#include <lastlog.h>
114#endif
115
116#include <netdb.h>
117#include <netinet/in.h>
118#include <arpa/inet.h>
119
120#ifdef USE_PAM
121#include <security/pam_appl.h>
122#endif
123
124#ifdef HAS_SHADOW
125#include <shadow.h>
126#ifndef PW_PPP
127#define PW_PPP PW_LOGIN
128#endif
129#endif
130#include <time.h>
131
132#include "pppd.h"
133#include "fsm.h"
134#include "lcp.h"
135#include "ccp.h"
136#include "ecp.h"
137#include "ipcp.h"
138#include "upap.h"
139#include "chap-new.h"
140#include "eap.h"
141#ifdef CBCP_SUPPORT
142#include "cbcp.h"
143#endif
144#include "pathnames.h"
145
146#ifndef lint
147static const char rcsid[] = RCSID;
148#endif
149
150/* Bits in scan_authfile return value */
151#define NONWILD_SERVER	1
152#define NONWILD_CLIENT	2
153
154#define ISWILD(word)	(word[0] == '*' && word[1] == 0)
155
156/* The name by which the peer authenticated itself to us. */
157char peer_authname[MAXNAMELEN];
158
159/* Records which authentication operations haven't completed yet. */
160static int auth_pending[NUM_PPP];
161
162/* Records which authentication operations have been completed. */
163int auth_done[NUM_PPP];
164
165/* Set if we have successfully called plogin() */
166static int logged_in;
167
168/* List of addresses which the peer may use. */
169static struct permitted_ip *addresses[NUM_PPP];
170
171/* Wordlist giving addresses which the peer may use
172   without authenticating itself. */
173static struct wordlist *noauth_addrs;
174
175/* Remote telephone number, if available */
176char remote_number[MAXNAMELEN];
177
178/* Wordlist giving remote telephone numbers which may connect. */
179static struct wordlist *permitted_numbers;
180
181/* Extra options to apply, from the secrets file entry for the peer. */
182static struct wordlist *extra_options;
183
184/* Number of network protocols which we have opened. */
185static int num_np_open;
186
187/* Number of network protocols which have come up. */
188static int num_np_up;
189
190/* Set if we got the contents of passwd[] from the pap-secrets file. */
191static int passwd_from_file;
192
193/* Set if we require authentication only because we have a default route. */
194static bool default_auth;
195
196/* Hook to enable a plugin to control the idle time limit */
197int (*idle_time_hook) __P((struct ppp_idle *)) = NULL;
198
199/* Hook for a plugin to say whether we can possibly authenticate any peer */
200int (*pap_check_hook) __P((void)) = NULL;
201
202/* Hook for a plugin to check the PAP user and password */
203int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp,
204			  struct wordlist **paddrs,
205			  struct wordlist **popts)) = NULL;
206
207/* Hook for a plugin to know about the PAP user logout */
208void (*pap_logout_hook) __P((void)) = NULL;
209
210/* Hook for a plugin to get the PAP password for authenticating us */
211int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL;
212
213/* Hook for a plugin to say if we can possibly authenticate a peer using CHAP */
214int (*chap_check_hook) __P((void)) = NULL;
215
216/* Hook for a plugin to get the CHAP password for authenticating us */
217int (*chap_passwd_hook) __P((char *user, char *passwd)) = NULL;
218
219#ifdef __APPLE__
220/* Hook for access control list to verify if user should have access */
221int (*acl_hook) __P((u_char *user, int len)) = NULL;
222/* Hook to change password, for authentication methods that support it */
223int (*change_password_hook) __P((u_char *msg))		= NULL;
224/* Hook to retry password, for authentication methods that support it */
225int (*retry_password_hook) __P((u_char *msg))		= NULL;
226#endif
227
228#ifdef __APPLE__
229struct notifier *auth_start_notify = NULL;
230struct notifier *auth_withpeer_fail_notify = NULL;
231struct notifier *auth_withpeer_success_notify = NULL;
232struct notifier *auth_peer_success_notify = NULL;
233#endif
234
235/* Hook for a plugin to say whether it is OK if the peer
236   refuses to authenticate. */
237int (*null_auth_hook) __P((struct wordlist **paddrs,
238			   struct wordlist **popts)) = NULL;
239
240int (*allowed_address_hook) __P((u_int32_t addr)) = NULL;
241
242/* A notifier for when the peer has authenticated itself,
243   and we are proceeding to the network phase. */
244struct notifier *auth_up_notifier = NULL;
245
246/* A notifier for when the link goes down. */
247struct notifier *link_down_notifier = NULL;
248
249/*
250 * This is used to ensure that we don't start an auth-up/down
251 * script while one is already running.
252 */
253enum script_state {
254    s_down,
255    s_up
256};
257
258static enum script_state auth_state = s_down;
259static enum script_state auth_script_state = s_down;
260static pid_t auth_script_pid = 0;
261
262static int used_login;		/* peer authenticated against login database */
263
264/*
265 * Option variables.
266 */
267bool uselogin = 0;		/* Use /etc/passwd for checking PAP */
268bool cryptpap = 0;		/* Passwords in pap-secrets are encrypted */
269bool refuse_pap = 0;		/* Don't wanna auth. ourselves with PAP */
270bool refuse_chap = 0;		/* Don't wanna auth. ourselves with CHAP */
271bool refuse_eap = 0;		/* Don't wanna auth. ourselves with EAP */
272#ifdef CHAPMS
273bool refuse_mschap = 0;		/* Don't wanna auth. ourselves with MS-CHAP */
274bool refuse_mschap_v2 = 0;	/* Don't wanna auth. ourselves with MS-CHAPv2 */
275#else
276bool refuse_mschap = 1;		/* Don't wanna auth. ourselves with MS-CHAP */
277bool refuse_mschap_v2 = 1;	/* Don't wanna auth. ourselves with MS-CHAPv2 */
278#endif
279bool usehostname = 0;		/* Use hostname for our_name */
280bool auth_required = 0;		/* Always require authentication from peer */
281bool allow_any_ip = 0;		/* Allow peer to use any IP address */
282bool explicit_remote = 0;	/* User specified explicit remote name */
283char remote_name[MAXNAMELEN];	/* Peer's name for authentication */
284
285#ifdef __APPLE__
286int	tokencard = 0;		/* Token card authentication. default is just name/password */
287#endif
288
289static char *uafname;		/* name of most recent +ua file */
290
291extern char *crypt __P((const char *, const char *));
292
293/* Prototypes for procedures local to this file. */
294
295static void network_phase __P((int));
296#ifndef __APPLE__
297static void check_idle __P((void *));
298#endif
299#ifdef __APPLE__
300static int keychainpassword __P((char **));
301static int userkeychainpassword __P((char **));
302#endif
303static void connect_time_expired __P((void *));
304static int  plogin __P((char *, char *, char **));
305static void plogout __P((void));
306static int  null_login __P((int));
307static int  get_pap_passwd __P((char *));
308static int  have_pap_secret __P((int *));
309static int  have_chap_secret __P((char *, char *, int, int *));
310#ifndef __APPLE__
311static int  have_srp_secret __P((char *client, char *server, int need_ip,
312    int *lacks_ipp));
313#endif
314static int  ip_addr_check __P((u_int32_t, struct permitted_ip *));
315static int  scan_authfile __P((FILE *, char *, char *, char *,
316			       struct wordlist **, struct wordlist **,
317			       char *, int));
318static void free_wordlist __P((struct wordlist *));
319static void auth_script __P((char *));
320static void auth_script_done __P((void *));
321static void set_allowed_addrs __P((int, struct wordlist *, struct wordlist *));
322static int  some_ip_ok __P((struct wordlist *));
323static int  setupapfile __P((char **));
324static int  privgroup __P((char **));
325static int  set_noauth_addr __P((char **));
326static int  set_permitted_number __P((char **));
327static void check_access __P((FILE *, char *));
328static int  wordlist_count __P((struct wordlist *));
329
330#ifdef MAXOCTETS
331static void check_maxoctets __P((void *));
332#endif
333
334/*
335 * Authentication-related options.
336 */
337option_t auth_options[] = {
338    { "auth", o_bool, &auth_required,
339      "Require authentication from peer", OPT_PRIO | 1 },
340    { "noauth", o_bool, &auth_required,
341      "Don't require peer to authenticate", OPT_PRIOSUB | OPT_PRIV,
342      &allow_any_ip },
343    { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
344      "Require PAP authentication from peer",
345      OPT_PRIOSUB | 1, &auth_required },
346    { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
347      "Require PAP authentication from peer",
348      OPT_ALIAS | OPT_PRIOSUB | 1, &auth_required },
349    { "require-chap", o_bool, &auth_required,
350      "Require CHAP authentication from peer",
351      OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
352      &lcp_wantoptions[0].chap_mdtype },
353    { "+chap", o_bool, &auth_required,
354      "Require CHAP authentication from peer",
355      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MD5,
356      &lcp_wantoptions[0].chap_mdtype },
357#ifdef CHAPMS
358    { "require-mschap", o_bool, &auth_required,
359      "Require MS-CHAP authentication from peer",
360      OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
361      &lcp_wantoptions[0].chap_mdtype },
362    { "+mschap", o_bool, &auth_required,
363      "Require MS-CHAP authentication from peer",
364      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
365      &lcp_wantoptions[0].chap_mdtype },
366    { "require-mschap-v2", o_bool, &auth_required,
367      "Require MS-CHAPv2 authentication from peer",
368      OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
369      &lcp_wantoptions[0].chap_mdtype },
370    { "+mschap-v2", o_bool, &auth_required,
371      "Require MS-CHAPv2 authentication from peer",
372      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
373      &lcp_wantoptions[0].chap_mdtype },
374#ifdef __APPLE__
375// for compatibility
376    { "require-chapms", o_bool, &auth_required,
377      "Require MS-CHAP authentication from peer",
378      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
379      &lcp_wantoptions[0].chap_mdtype },
380    { "+chapms", o_bool, &auth_required,
381      "Require MS-CHAP authentication from peer",
382      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT,
383      &lcp_wantoptions[0].chap_mdtype },
384    { "require-chapms-v2", o_bool, &auth_required,
385      "Require MS-CHAPv2 authentication from peer",
386      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
387      &lcp_wantoptions[0].chap_mdtype },
388    { "+chapms-v2", o_bool, &auth_required,
389      "Require MS-CHAPv2 authentication from peer",
390      OPT_ALIAS | OPT_PRIOSUB | OPT_A2OR | MDTYPE_MICROSOFT_V2,
391      &lcp_wantoptions[0].chap_mdtype },
392#endif
393#endif
394
395    { "refuse-pap", o_bool, &refuse_pap,
396      "Don't agree to auth to peer with PAP", 1 },
397    { "-pap", o_bool, &refuse_pap,
398      "Don't allow PAP authentication with peer", OPT_ALIAS | 1 },
399    { "refuse-chap", o_bool, &refuse_chap,
400      "Don't agree to auth to peer with CHAP",
401      OPT_A2CLRB | MDTYPE_MD5,
402      &lcp_allowoptions[0].chap_mdtype },
403    { "-chap", o_bool, &refuse_chap,
404      "Don't allow CHAP authentication with peer",
405      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
406      &lcp_allowoptions[0].chap_mdtype },
407#ifdef __APPLE__
408// for compatibility
409    { "refuse-chap-md5", o_bool, &refuse_chap,
410      "Don't allow CHAP authentication with peer",
411      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
412      &lcp_allowoptions[0].chap_mdtype },
413    { "-chap-md5", o_bool, &refuse_chap,
414      "Don't allow CHAP authentication with peer",
415      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MD5,
416      &lcp_allowoptions[0].chap_mdtype },
417#endif
418#ifdef CHAPMS
419    { "refuse-mschap", o_bool, &refuse_mschap,
420      "Don't agree to auth to peer with MS-CHAP",
421      OPT_A2CLRB | MDTYPE_MICROSOFT,
422      &lcp_allowoptions[0].chap_mdtype },
423    { "-mschap", o_bool, &refuse_mschap,
424      "Don't allow MS-CHAP authentication with peer",
425      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
426      &lcp_allowoptions[0].chap_mdtype },
427    { "refuse-mschap-v2", o_bool, &refuse_mschap_v2,
428      "Don't agree to auth to peer with MS-CHAPv2",
429      OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
430      &lcp_allowoptions[0].chap_mdtype },
431    { "-mschap-v2", o_bool, &refuse_mschap_v2,
432      "Don't allow MS-CHAPv2 authentication with peer",
433      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
434      &lcp_allowoptions[0].chap_mdtype },
435#ifdef __APPLE__
436// for compatibility
437    { "refuse-chapms", o_bool, &refuse_mschap,
438      "Don't agree to auth to peer with MS-CHAP",
439      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
440      &lcp_allowoptions[0].chap_mdtype },
441    { "-chapms", o_bool, &refuse_mschap,
442      "Don't allow MS-CHAP authentication with peer",
443      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT,
444      &lcp_allowoptions[0].chap_mdtype },
445    { "refuse-chapms-v2", o_bool, &refuse_mschap_v2,
446      "Don't agree to auth to peer with MS-CHAPv2",
447      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
448      &lcp_allowoptions[0].chap_mdtype },
449    { "-chapms-v2", o_bool, &refuse_mschap_v2,
450      "Don't allow MS-CHAPv2 authentication with peer",
451      OPT_ALIAS | OPT_A2CLRB | MDTYPE_MICROSOFT_V2,
452      &lcp_allowoptions[0].chap_mdtype },
453#endif
454#endif
455
456    { "require-eap", o_bool, &lcp_wantoptions[0].neg_eap,
457      "Require EAP authentication from peer", OPT_PRIOSUB | 1,
458      &auth_required },
459    { "refuse-eap", o_bool, &refuse_eap,
460      "Don't agree to authenticate to peer with EAP", 1 },
461
462    { "name", o_string, our_name,
463      "Set local name for authentication",
464      OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, MAXNAMELEN },
465
466    { "+ua", o_special, (void *)setupapfile,
467      "Get PAP user and password from file",
468      OPT_PRIO | OPT_A2STRVAL, &uafname },
469
470    { "user", o_string, user,
471#ifdef __APPLE__
472      "Set name for auth with peer", OPT_PRIO | OPT_STATIC | OPT_A2COPY, username, MAXNAMELEN },
473#else
474      "Set name for auth with peer", OPT_PRIO | OPT_STATIC, NULL, MAXNAMELEN },
475#endif
476
477    { "password", o_string, passwd,
478      "Password for authenticating us to the peer",
479      OPT_PRIO | OPT_STATIC | OPT_HIDE, NULL, MAXSECRETLEN },
480
481#ifdef __APPLE__
482    { "keychainpassword", o_special, (void *)keychainpassword,
483      "Get password from keychain", OPT_PRIV },
484
485    { "userkeychainpassword", o_special, (void *)userkeychainpassword,
486      "Get password from userkeychain", OPT_PRIV },
487
488    { "tokencard", o_int, &tokencard,
489      "Token card type for authentication instead of name/password" },
490#endif
491
492    { "usehostname", o_bool, &usehostname,
493      "Must use hostname for authentication", 1 },
494
495    { "remotename", o_string, remote_name,
496      "Set remote name for authentication", OPT_PRIO | OPT_STATIC,
497      &explicit_remote, MAXNAMELEN },
498
499    { "login", o_bool, &uselogin,
500      "Use system password database for PAP", 1 },
501
502    { "papcrypt", o_bool, &cryptpap,
503      "PAP passwords are encrypted", 1 },
504
505    { "privgroup", o_special, (void *)privgroup,
506      "Allow group members to use privileged options", OPT_PRIV | OPT_A2LIST },
507
508    { "allow-ip", o_special, (void *)set_noauth_addr,
509      "Set IP address(es) which can be used without authentication",
510      OPT_PRIV | OPT_A2LIST },
511
512    { "remotenumber", o_string, remote_number,
513      "Set remote telephone number for authentication", OPT_PRIO | OPT_STATIC,
514      NULL, MAXNAMELEN },
515
516    { "allow-number", o_special, (void *)set_permitted_number,
517      "Set telephone number(s) which are allowed to connect",
518      OPT_PRIV | OPT_A2LIST },
519
520    { NULL }
521};
522
523/*
524 * setupapfile - specifies UPAP info for authenticating with peer.
525 */
526static int
527setupapfile(argv)
528    char **argv;
529{
530    FILE *ufile;
531    int l;
532    char u[MAXNAMELEN], p[MAXSECRETLEN];
533    char *fname;
534
535    lcp_allowoptions[0].neg_upap = 1;
536
537    /* open user info file */
538    fname = strdup(*argv);
539    if (fname == NULL)
540	novm("+ua file name");
541    seteuid(getuid());
542    ufile = fopen(fname, "r");
543    seteuid(0);
544    if (ufile == NULL) {
545	option_error("unable to open user login data file %s", fname);
546	return 0;
547    }
548    check_access(ufile, fname);
549    uafname = fname;
550
551    /* get username */
552    if (fgets(u, MAXNAMELEN - 1, ufile) == NULL
553	|| fgets(p, MAXSECRETLEN - 1, ufile) == NULL) {
554	fclose(ufile);
555	option_error("unable to read user login data file %s", fname);
556	return 0;
557    }
558    fclose(ufile);
559
560    /* get rid of newlines */
561    l = strlen(u);
562    if (l > 0 && u[l-1] == '\n')
563	u[l-1] = 0;
564    l = strlen(p);
565    if (l > 0 && p[l-1] == '\n')
566	p[l-1] = 0;
567
568    if (override_value("user", option_priority, fname))
569	strlcpy(user, u, sizeof(user));
570    if (override_value("passwd", option_priority, fname))
571	strlcpy(passwd, p, sizeof(passwd));
572
573    return (1);
574}
575
576
577/*
578 * privgroup - allow members of the group to have privileged access.
579 */
580static int
581privgroup(argv)
582    char **argv;
583{
584    struct group *g;
585    int i;
586
587    g = getgrnam(*argv);
588    if (g == 0) {
589	option_error("group %s is unknown", *argv);
590	return 0;
591    }
592    for (i = 0; i < ngroups; ++i) {
593	if (groups[i] == g->gr_gid) {
594	    privileged = 1;
595	    break;
596	}
597    }
598    return 1;
599}
600
601
602/*
603 * set_noauth_addr - set address(es) that can be used without authentication.
604 * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets.
605 */
606static int
607set_noauth_addr(argv)
608    char **argv;
609{
610    char *addr = *argv;
611    int l = strlen(addr) + 1;
612    struct wordlist *wp;
613
614    wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l);
615    if (wp == NULL)
616	novm("allow-ip argument");
617    wp->word = (char *) (wp + 1);
618    wp->next = noauth_addrs;
619    BCOPY(addr, wp->word, l);
620    noauth_addrs = wp;
621    return 1;
622}
623
624
625/*
626 * set_permitted_number - set remote telephone number(s) that may connect.
627 */
628static int
629set_permitted_number(argv)
630    char **argv;
631{
632    char *number = *argv;
633    int l = strlen(number) + 1;
634    struct wordlist *wp;
635
636    wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l);
637    if (wp == NULL)
638	novm("allow-number argument");
639    wp->word = (char *) (wp + 1);
640    wp->next = permitted_numbers;
641    BCOPY(number, wp->word, l);
642    permitted_numbers = wp;
643    return 1;
644}
645
646
647/*
648 * An Open on LCP has requested a change from Dead to Establish phase.
649 * Do what's necessary to bring the physical layer up.
650 */
651void
652link_required(unit)
653    int unit;
654{
655}
656
657/*
658 * LCP has terminated the link; go to the Dead phase and take the
659 * physical layer down.
660 */
661void
662link_terminated(unit)
663    int unit;
664{
665    if (phase == PHASE_DEAD)
666	return;
667    if (pap_logout_hook) {
668	pap_logout_hook();
669    } else {
670	if (logged_in)
671	    plogout();
672    }
673    new_phase(PHASE_DEAD);
674    notice("Connection terminated.");
675}
676
677/*
678 * LCP has gone down; it will either die or try to re-establish.
679 */
680void
681link_down(unit)
682    int unit;
683{
684    int i;
685    struct protent *protp;
686
687    notify(link_down_notifier, 0);
688    auth_state = s_down;
689    if (auth_script_state == s_up && auth_script_pid == 0) {
690	update_link_stats(unit);
691	auth_script_state = s_down;
692	auth_script(_PATH_AUTHDOWN);
693    }
694    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
695	if (!protp->enabled_flag)
696	    continue;
697        if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
698	    (*protp->lowerdown)(unit);
699        if (protp->protocol < 0xC000 && protp->close != NULL)
700	    (*protp->close)(unit, "LCP down");
701    }
702    num_np_open = 0;
703    num_np_up = 0;
704    if (phase != PHASE_DEAD)
705#ifdef __APPLE__
706        // going into ESTABLISH phase, even if is correct, will give the wrong status to dialers
707	new_phase(PHASE_TERMINATE);
708#else
709	new_phase(PHASE_ESTABLISH);
710#endif
711}
712
713/*
714 * The link is established.
715 * Proceed to the Dead, Authenticate or Network phase as appropriate.
716 */
717void
718link_established(unit)
719    int unit;
720{
721    int auth;
722    lcp_options *wo = &lcp_wantoptions[unit];
723    lcp_options *go = &lcp_gotoptions[unit];
724    lcp_options *ho = &lcp_hisoptions[unit];
725    int i;
726    struct protent *protp;
727
728    /*
729     * Tell higher-level protocols that LCP is up.
730     */
731    for (i = 0; (protp = protocols[i]) != NULL; ++i)
732        if (protp->protocol != PPP_LCP && protp->enabled_flag
733	    && protp->lowerup != NULL)
734	    (*protp->lowerup)(unit);
735
736    if (!auth_required && noauth_addrs != NULL)
737	set_allowed_addrs(unit, NULL, NULL);
738
739    if (auth_required && !(go->neg_upap || go->neg_chap || go->neg_eap)) {
740	/*
741	 * We wanted the peer to authenticate itself, and it refused:
742	 * if we have some address(es) it can use without auth, fine,
743	 * otherwise treat it as though it authenticated with PAP using
744	 * a username of "" and a password of "".  If that's not OK,
745	 * boot it out.
746	 */
747	if (noauth_addrs != NULL) {
748	    set_allowed_addrs(unit, NULL, NULL);
749	} else if (!wo->neg_upap || uselogin || !null_login(unit)) {
750	    warning("peer refused to authenticate: terminating link");
751	    lcp_close(unit, "peer refused to authenticate");
752	    status = EXIT_PEER_AUTH_FAILED;
753	    return;
754	}
755    }
756
757    new_phase(PHASE_AUTHENTICATE);
758    used_login = 0;
759    auth = 0;
760    if (go->neg_eap) {
761	EapAuthPeer(unit, our_name);
762	auth |= EAP_PEER;
763    } else if (go->neg_chap) {
764	chap_auth_peer(unit, our_name, CHAP_DIGEST(go->chap_mdtype));
765	auth |= CHAP_PEER;
766    } else if (go->neg_upap) {
767	upap_authpeer(unit);
768	auth |= PAP_PEER;
769    }
770    if (ho->neg_eap) {
771	EapAuthWithPeer(unit, user);
772	auth |= EAP_WITHPEER;
773    } else if (ho->neg_chap) {
774	chap_auth_with_peer(unit, user, CHAP_DIGEST(ho->chap_mdtype));
775	auth |= CHAP_WITHPEER;
776    } else if (ho->neg_upap) {
777	if (passwd[0] == 0) {
778	    passwd_from_file = 1;
779	    if (!get_pap_passwd(passwd))
780		error("No secret found for PAP login");
781	}
782	upap_authwithpeer(unit, user, passwd);
783	auth |= PAP_WITHPEER;
784    }
785    auth_pending[unit] = auth;
786    auth_done[unit] = 0;
787
788#ifdef __APPLE__
789    if (auth)
790        notify(auth_start_notify, auth);
791#endif
792
793    if (!auth)
794	network_phase(unit);
795}
796
797#ifdef __APPLE__
798/*
799 * Received an unexpected network packet while in authentication phase.
800	return 1 if packet is really unexpected,
801	return 0 if it is ok to process the packet
802 */
803int
804unexpected_network_packet(unit, protocol)
805    int unit, protocol;
806{
807
808	if ((phase == PHASE_AUTHENTICATE)
809		&& (lcp_hisoptions[unit].neg_eap)
810		&& (protocol & 0x8000)) {
811		/*
812			we receive a NCP while still authenticating
813			we lost the EAP Success message
814		*/
815		EapLostSuccess(unit);
816	}
817
818	return (phase <= PHASE_AUTHENTICATE);
819}
820#endif
821
822/*
823 * Proceed to the network phase.
824 */
825static void
826network_phase(unit)
827    int unit;
828{
829    lcp_options *go = &lcp_gotoptions[unit];
830
831#ifdef __APPLE__
832	/*
833	 * dont' go through the network phase changes repeatedly; particularly
834	 * in the case of frequent (server-initiated) chap reauths.
835	 */
836    if (phase == PHASE_NETWORK || phase == PHASE_RUNNING) {
837        return;
838    }
839#endif // __APPLE__
840
841    /* Log calling number. */
842    if (*remote_number)
843	notice("peer from calling number %q authorized", remote_number);
844
845    /*
846     * If the peer had to authenticate, run the auth-up script now.
847     */
848    if (go->neg_chap || go->neg_upap || go->neg_eap) {
849	notify(auth_up_notifier, 0);
850	auth_state = s_up;
851	if (auth_script_state == s_down && auth_script_pid == 0) {
852	    auth_script_state = s_up;
853	    auth_script(_PATH_AUTHUP);
854	}
855    }
856
857#ifdef CBCP_SUPPORT
858    /*
859     * If we negotiated callback, do it now.
860     */
861    if (go->neg_cbcp) {
862	new_phase(PHASE_CALLBACK);
863	(*cbcp_protent.open)(unit);
864	return;
865    }
866#endif
867
868    /*
869     * Process extra options from the secrets file
870     */
871    if (extra_options) {
872	options_from_list(extra_options, 1);
873	free_wordlist(extra_options);
874	extra_options = 0;
875    }
876    start_networks(unit);
877}
878
879void
880start_networks(unit)
881    int unit;
882{
883    int i;
884    struct protent *protp;
885    int ecp_required, mppe_required;
886
887    new_phase(PHASE_NETWORK);
888
889#ifdef HAVE_MULTILINK
890    if (multilink) {
891	if (mp_join_bundle()) {
892	    if (updetach && !nodetach)
893		detach();
894	    return;
895	}
896    }
897#endif /* HAVE_MULTILINK */
898
899#ifdef PPP_FILTER
900    if (!demand)
901	set_filters(&pass_filter, &active_filter);
902#endif
903    /* Start CCP and ECP */
904    for (i = 0; (protp = protocols[i]) != NULL; ++i)
905	if ((protp->protocol == PPP_ECP || protp->protocol == PPP_CCP)
906	    && protp->enabled_flag && protp->open != NULL)
907	    (*protp->open)(0);
908
909    /*
910     * Bring up other network protocols iff encryption is not required.
911     */
912    ecp_required = ecp_gotoptions[unit].required;
913    mppe_required = ccp_gotoptions[unit].mppe;
914    if (!ecp_required && !mppe_required)
915	continue_networks(unit);
916}
917
918void
919continue_networks(unit)
920    int unit;
921{
922    int i;
923    struct protent *protp;
924
925    /*
926     * Start the "real" network protocols.
927     */
928    for (i = 0; (protp = protocols[i]) != NULL; ++i)
929	if (protp->protocol < 0xC000
930	    && protp->protocol != PPP_CCP && protp->protocol != PPP_ECP
931	    && protp->enabled_flag && protp->open != NULL) {
932	    (*protp->open)(0);
933	    ++num_np_open;
934	}
935
936    if (num_np_open == 0)
937	/* nothing to do */
938	lcp_close(0, "No network protocols running");
939}
940
941/*
942 * Test if all of the waiting protocols have completed or failed.
943 */
944void
945check_protocols_ready(void)
946{
947    int i;
948    struct protent *protp;
949    int state;
950
951    if (num_np_open == 0) {
952        return;
953    }
954
955    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
956        if (protp->protocol < 0xC000
957            && protp->protocol != PPP_CCP && protp->protocol != PPP_ECP
958            && protp->enabled_flag && protp->open != NULL) {
959            state = (protp->state)(0);
960
961            if (state != STOPPED && state != OPENED) {
962                /* Some protocols not yet ready */
963                return;
964            }
965        }
966    }
967
968    /* If we are here, all protocols are ready */
969    notify(protocolsready_notifier,0);
970    return;
971}
972
973/*
974 * The peer has failed to authenticate himself using `protocol'.
975 */
976void
977auth_peer_fail(unit, protocol)
978    int unit, protocol;
979{
980    /*
981     * Authentication failure: take the link down
982     */
983    lcp_close(unit, "Authentication failed");
984    status = EXIT_PEER_AUTH_FAILED;
985}
986
987/*
988 * The peer has been successfully authenticated using `protocol'.
989 */
990void
991auth_peer_success(unit, protocol, prot_flavor, name, namelen)
992    int unit, protocol, prot_flavor;
993    u_char *name;
994    int namelen;
995{
996    int bit;
997
998#ifdef __APPLE__
999    struct auth_peer_success_info note;
1000
1001    /* if acl module present - check if user authorized */
1002    if (acl_hook) {
1003        if (acl_hook(name, namelen) == 0) {
1004            lcp_close(unit, "Authorization failed");
1005            status = EXIT_PEER_NOT_AUTHORIZED;
1006            return;
1007        }
1008    }
1009    note.protocol = protocol;
1010    note.protocol_flavor = prot_flavor;
1011    note.name = (char*)name;
1012    note.namelen = namelen;
1013    notify_with_ptr(auth_peer_success_notify, (uintptr_t)&note);
1014#endif
1015
1016    switch (protocol) {
1017    case PPP_CHAP:
1018	bit = CHAP_PEER;
1019	switch (prot_flavor) {
1020	case CHAP_MD5:
1021	    bit |= CHAP_MD5_PEER;
1022	    break;
1023#ifdef CHAPMS
1024	case CHAP_MICROSOFT:
1025	    bit |= CHAP_MS_PEER;
1026	    break;
1027	case CHAP_MICROSOFT_V2:
1028	    bit |= CHAP_MS2_PEER;
1029	    break;
1030#endif
1031	}
1032	break;
1033    case PPP_PAP:
1034	bit = PAP_PEER;
1035	break;
1036    case PPP_EAP:
1037	bit = EAP_PEER;
1038	break;
1039    default:
1040	warning("auth_peer_success: unknown protocol %x", protocol);
1041	return;
1042    }
1043
1044    /*
1045     * Save the authenticated name of the peer for later.
1046     */
1047    if (namelen > sizeof(peer_authname) - 1)
1048	namelen = sizeof(peer_authname) - 1;
1049    BCOPY(name, peer_authname, namelen);
1050    peer_authname[namelen] = 0;
1051    script_setenv("PEERNAME", peer_authname, 0);
1052
1053    /* Save the authentication method for later. */
1054    auth_done[unit] |= bit;
1055
1056    /*
1057     * If there is no more authentication still to be done,
1058     * proceed to the network (or callback) phase.
1059     */
1060    if ((auth_pending[unit] &= ~bit) == 0)
1061        network_phase(unit);
1062}
1063
1064/*
1065 * We have failed to authenticate ourselves to the peer using `protocol'.
1066 */
1067void
1068auth_withpeer_fail(unit, protocol)
1069    int unit, protocol;
1070{
1071
1072#ifdef __APPLE__
1073    notify(auth_withpeer_fail_notify, protocol);
1074#endif
1075
1076    if (passwd_from_file)
1077	BZERO(passwd, MAXSECRETLEN);
1078    /*
1079     * We've failed to authenticate ourselves to our peer.
1080     * Some servers keep sending CHAP challenges, but there
1081     * is no point in persisting without any way to get updated
1082     * authentication secrets.
1083     */
1084    lcp_close(unit, "Failed to authenticate ourselves to peer");
1085    status = EXIT_AUTH_TOPEER_FAILED;
1086}
1087
1088#if __APPLE__
1089/*
1090 * We have failed to authenticate ourselves to the peer using `protocol'.
1091 */
1092void
1093auth_withpeer_cancelled(unit, protocol)
1094    int unit, protocol;
1095{
1096
1097    if (passwd_from_file)
1098	BZERO(passwd, MAXSECRETLEN);
1099
1100    lcp_close(unit, "User cancelled authentication");
1101    status = EXIT_USER_REQUEST;
1102}
1103#endif
1104
1105/*
1106 * We have successfully authenticated ourselves with the peer using `protocol'.
1107 */
1108void
1109auth_withpeer_success(unit, protocol, prot_flavor)
1110    int unit, protocol, prot_flavor;
1111{
1112    int bit;
1113
1114#ifdef __APPLE__
1115    notify(auth_withpeer_success_notify, protocol);
1116#endif
1117
1118    switch (protocol) {
1119    case PPP_CHAP:
1120	bit = CHAP_WITHPEER;
1121	switch (prot_flavor) {
1122	case CHAP_MD5:
1123	    bit |= CHAP_MD5_WITHPEER;
1124	    break;
1125#ifdef CHAPMS
1126	case CHAP_MICROSOFT:
1127	    bit |= CHAP_MS_WITHPEER;
1128	    break;
1129	case CHAP_MICROSOFT_V2:
1130	    bit |= CHAP_MS2_WITHPEER;
1131	    break;
1132#endif
1133	}
1134	break;
1135    case PPP_PAP:
1136	if (passwd_from_file)
1137	    BZERO(passwd, MAXSECRETLEN);
1138	bit = PAP_WITHPEER;
1139	break;
1140    case PPP_EAP:
1141	bit = EAP_WITHPEER;
1142	break;
1143    default:
1144	warning("auth_withpeer_success: unknown protocol %x", protocol);
1145	bit = 0;
1146    }
1147
1148    /* Save the authentication method for later. */
1149    auth_done[unit] |= bit;
1150
1151    /*
1152     * If there is no more authentication still being done,
1153     * proceed to the network (or callback) phase.
1154     */
1155    if ((auth_pending[unit] &= ~bit) == 0)
1156	network_phase(unit);
1157}
1158
1159#ifdef __APPLE__
1160/*
1161 * option_change_idle - change idle parameter.
1162 */
1163void option_change_idle()
1164{
1165    int tlim;
1166
1167    UNTIMEOUT(check_idle, 0);
1168    if (phase == PHASE_RUNNING) {
1169		if (idle_time_hook != 0)
1170			tlim = (*idle_time_hook)(NULL);
1171		else
1172			tlim = idle_time_limit;
1173		if (tlim > 0)
1174			TIMEOUT(check_idle, NULL, tlim);
1175	}
1176}
1177#endif
1178
1179/*
1180 * np_up - a network protocol has come up.
1181 */
1182void
1183np_up(unit, proto)
1184    int unit, proto;
1185{
1186    int tlim;
1187
1188    if (num_np_up == 0) {
1189	/*
1190	 * At this point we consider that the link has come up successfully.
1191	 */
1192	status = EXIT_OK;
1193	unsuccess = 0;
1194	new_phase(PHASE_RUNNING);
1195
1196	if (idle_time_hook != 0)
1197	    tlim = (*idle_time_hook)(NULL);
1198	else
1199	    tlim = idle_time_limit;
1200	if (tlim > 0)
1201	    TIMEOUT(check_idle, NULL, tlim);
1202
1203	/*
1204	 * Set a timeout to close the connection once the maximum
1205	 * connect time has expired.
1206	 */
1207	if (maxconnect > 0)
1208	    TIMEOUT(connect_time_expired, 0, maxconnect);
1209
1210#ifdef MAXOCTETS
1211	if (maxoctets > 0)
1212	    TIMEOUT(check_maxoctets, NULL, maxoctets_timeout);
1213#endif
1214
1215	/*
1216	 * Detach now, if the updetach option was given.
1217	 */
1218	if (updetach && !nodetach)
1219	    detach();
1220    }
1221    ++num_np_up;
1222    check_protocols_ready();
1223}
1224
1225/*
1226 * np_down - a network protocol has gone down.
1227 */
1228void
1229np_down(unit, proto)
1230    int unit, proto;
1231{
1232    if (--num_np_up == 0) {
1233	UNTIMEOUT(check_idle, NULL);
1234	UNTIMEOUT(connect_time_expired, NULL);
1235#ifdef MAXOCTETS
1236	UNTIMEOUT(check_maxoctets, NULL);
1237#endif
1238#ifdef __APPLE__
1239	// stay in terminate, no need to go to network phase.
1240	if (phase != PHASE_TERMINATE)
1241#endif
1242	new_phase(PHASE_NETWORK);
1243    }
1244}
1245
1246/*
1247 * np_finished - a network protocol has finished using the link.
1248 */
1249void
1250np_finished(unit, proto)
1251    int unit, proto;
1252{
1253    if (--num_np_open <= 0) {
1254	/* no further use for the link: shut up shop. */
1255	lcp_close(0, "No network protocols running");
1256    }
1257    check_protocols_ready();
1258}
1259
1260#ifdef MAXOCTETS
1261static void
1262check_maxoctets(arg)
1263    void *arg;
1264{
1265    int diff;
1266    unsigned int used;
1267
1268    update_link_stats(ifunit);
1269    link_stats_valid=0;
1270
1271    switch(maxoctets_dir) {
1272	case PPP_OCTETS_DIRECTION_IN:
1273	    used = link_stats.bytes_in;
1274	    break;
1275	case PPP_OCTETS_DIRECTION_OUT:
1276	    used = link_stats.bytes_out;
1277	    break;
1278	case PPP_OCTETS_DIRECTION_MAXOVERAL:
1279	case PPP_OCTETS_DIRECTION_MAXSESSION:
1280	    used = (link_stats.bytes_in > link_stats.bytes_out) ? link_stats.bytes_in : link_stats.bytes_out;
1281	    break;
1282	default:
1283	    used = link_stats.bytes_in+link_stats.bytes_out;
1284	    break;
1285    }
1286    diff = maxoctets - used;
1287    if(diff < 0) {
1288	notice("Traffic limit reached. Limit: %u Used: %u", maxoctets, used);
1289	lcp_close(0, "Traffic limit");
1290	need_holdoff = 0;
1291	status = EXIT_TRAFFIC_LIMIT;
1292    } else {
1293        TIMEOUT(check_maxoctets, NULL, maxoctets_timeout);
1294    }
1295}
1296#endif
1297
1298/*
1299 * check_idle - check whether the link has been idle for long
1300 * enough that we can shut it down.
1301 */
1302#ifndef __APPLE__
1303static
1304#endif
1305void
1306check_idle(arg)
1307    void *arg;
1308{
1309    struct ppp_idle idle;
1310    time_t itime;
1311    int tlim;
1312
1313    if (!get_idle_time(0, &idle))
1314	return;
1315    if (idle_time_hook != 0) {
1316	tlim = idle_time_hook(&idle);
1317    } else {
1318        if (noidlerecv)
1319            itime = idle.xmit_idle;
1320        else if (noidlesend)
1321            itime = idle.recv_idle;
1322        else
1323            itime = MIN(idle.xmit_idle, idle.recv_idle);
1324	tlim = idle_time_limit - itime;
1325    }
1326    if (tlim <= 0) {
1327	/* link is idle: shut it down. */
1328	notice("Terminating connection due to lack of activity.");
1329	lcp_close(0, "Link inactive");
1330	need_holdoff = 0;
1331	status = EXIT_IDLE_TIMEOUT;
1332    } else {
1333	TIMEOUT(check_idle, NULL, tlim);
1334    }
1335}
1336
1337/*
1338 * connect_time_expired - log a message and close the connection.
1339 */
1340static void
1341connect_time_expired(arg)
1342    void *arg;
1343{
1344    info("Connect time expired");
1345    lcp_close(0, "Connect time expired");	/* Close connection */
1346    status = EXIT_CONNECT_TIME;
1347}
1348
1349#ifdef __APPLE__
1350/*
1351 * link connection becomes on hold.
1352 */
1353void auth_hold(int unit)
1354{
1355    UNTIMEOUT(check_idle, NULL);
1356    UNTIMEOUT(connect_time_expired, NULL);
1357}
1358
1359/*
1360 * link connection resumes.
1361 */
1362void auth_cont(int unit)
1363{
1364    int tlim;
1365
1366    if (idle_time_hook != 0)
1367        tlim = (*idle_time_hook)(NULL);
1368    else
1369        tlim = idle_time_limit;
1370    if (tlim > 0)
1371        TIMEOUT(check_idle, NULL, tlim);
1372
1373    // XXX how should we handle the max connext timer in regard to connection on hold ?
1374    if (maxconnect > 0)
1375        TIMEOUT(connect_time_expired, 0, maxconnect);
1376}
1377
1378#endif
1379
1380/*
1381 * auth_check_options - called to check authentication options.
1382 */
1383void
1384auth_check_options()
1385{
1386    lcp_options *wo = &lcp_wantoptions[0];
1387    int can_auth;
1388    int lacks_ip;
1389
1390    /* Default our_name to hostname, and user to our_name */
1391    if (our_name[0] == 0 || usehostname)
1392	strlcpy(our_name, hostname, sizeof(our_name));
1393    if (user[0] == 0)
1394	strlcpy(user, our_name, sizeof(user));
1395
1396    /*
1397     * If we have a default route, require the peer to authenticate
1398     * unless the noauth option was given or the real user is root.
1399     */
1400    if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) {
1401	auth_required = 1;
1402	default_auth = 1;
1403    }
1404
1405    /* If we selected any CHAP flavors, we should probably negotiate it. :-) */
1406    if (wo->chap_mdtype)
1407	wo->neg_chap = 1;
1408
1409    /* If authentication is required, ask peer for CHAP, PAP, or EAP. */
1410    if (auth_required) {
1411	allow_any_ip = 0;
1412	if (!wo->neg_chap && !wo->neg_upap && !wo->neg_eap) {
1413	    wo->neg_chap = 1; wo->chap_mdtype = MDTYPE_ALL;
1414	    wo->neg_upap = 1;
1415	    wo->neg_eap = 1;
1416	}
1417    } else {
1418	wo->neg_chap = 0; wo->chap_mdtype = MDTYPE_NONE;
1419	wo->neg_upap = 0;
1420	wo->neg_eap = 0;
1421    }
1422
1423    /*
1424     * Check whether we have appropriate secrets to use
1425     * to authenticate the peer.  Note that EAP can authenticate by way
1426     * of a CHAP-like exchanges as well as SRP.
1427     */
1428    lacks_ip = 0;
1429    can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip));
1430    if (!can_auth && (wo->neg_chap || wo->neg_eap)) {
1431	can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
1432				    our_name, 1, &lacks_ip);
1433    }
1434    if (!can_auth && wo->neg_eap) {
1435#ifdef __APPLE__
1436      // check EAP plugins ???
1437      can_auth = 1;
1438#else
1439	can_auth = have_srp_secret((explicit_remote? remote_name: NULL),
1440				    our_name, 1, &lacks_ip);
1441#endif
1442    }
1443
1444    if (auth_required && !can_auth && noauth_addrs == NULL) {
1445	if (default_auth) {
1446	    option_error(
1447"By default the remote system is required to authenticate itself");
1448	    option_error(
1449"(because this system has a default route to the internet)");
1450	} else if (explicit_remote)
1451	    option_error(
1452"The remote system (%s) is required to authenticate itself",
1453			 remote_name);
1454	else
1455	    option_error(
1456"The remote system is required to authenticate itself");
1457	option_error(
1458"but I couldn't find any suitable secret (password) for it to use to do so.");
1459	if (lacks_ip)
1460	    option_error(
1461"(None of the available passwords would let it use an IP address.)");
1462
1463	exit(1);
1464    }
1465
1466    /*
1467     * Early check for remote number authorization.
1468     */
1469    if (!auth_number()) {
1470	warning("calling number %q is not authorized", remote_number);
1471	exit(EXIT_CNID_AUTH_FAILED);
1472    }
1473}
1474
1475/*
1476 * auth_reset - called when LCP is starting negotiations to recheck
1477 * authentication options, i.e. whether we have appropriate secrets
1478 * to use for authenticating ourselves and/or the peer.
1479 */
1480void
1481auth_reset(unit)
1482    int unit;
1483{
1484    lcp_options *go = &lcp_gotoptions[unit];
1485    lcp_options *ao = &lcp_allowoptions[unit];
1486    int hadchap;
1487
1488    hadchap = -1;
1489    ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
1490    ao->neg_chap = (!refuse_chap || !refuse_mschap || !refuse_mschap_v2)
1491	&& (passwd[0] != 0 ||
1492	    (hadchap = have_chap_secret(user, (explicit_remote? remote_name:
1493					       NULL), 0, NULL)));
1494#ifdef __APPLE__
1495    // check eap plugins for pasword ???
1496    ao->neg_eap = !refuse_eap;
1497#else
1498    ao->neg_eap = !refuse_eap && (
1499	passwd[0] != 0 ||
1500	(hadchap == 1 || (hadchap == -1 && have_chap_secret(user,
1501	    (explicit_remote? remote_name: NULL), 0, NULL))) ||
1502	have_srp_secret(user, (explicit_remote? remote_name: NULL), 0, NULL));
1503#endif
1504
1505    hadchap = -1;
1506    if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
1507	go->neg_upap = 0;
1508    if (go->neg_chap) {
1509	if (!(hadchap = have_chap_secret((explicit_remote? remote_name: NULL),
1510			      our_name, 1, NULL)))
1511	    go->neg_chap = 0;
1512    }
1513
1514#ifdef __APPLE__
1515    // check eap plugins ?
1516    if (go->neg_eap) {
1517      // go->neg_eap;
1518    }
1519#else
1520    if (go->neg_eap &&
1521	(hadchap == 0 || (hadchap == -1 &&
1522	    !have_chap_secret((explicit_remote? remote_name: NULL), our_name,
1523		1, NULL))) &&
1524	!have_srp_secret((explicit_remote? remote_name: NULL), our_name, 1,
1525	    NULL))
1526	go->neg_eap = 0;
1527#endif
1528}
1529
1530
1531/*
1532 * check_passwd - Check the user name and passwd against the PAP secrets
1533 * file.  If requested, also check against the system password database,
1534 * and login the user if OK.
1535 *
1536 * returns:
1537 *	UPAP_AUTHNAK: Authentication failed.
1538 *	UPAP_AUTHACK: Authentication succeeded.
1539 * In either case, msg points to an appropriate message.
1540 */
1541int
1542check_passwd(unit, auser, userlen, apasswd, passwdlen, msg)
1543    int unit;
1544    u_char *auser;
1545    int userlen;
1546    u_char *apasswd;
1547    int passwdlen;
1548    char **msg;
1549{
1550    int ret;
1551    char *filename;
1552    FILE *f;
1553    struct wordlist *addrs = NULL, *opts = NULL;
1554    char passwd[256], user[256];
1555    char secret[MAXWORDLEN];
1556    static int attempts = 0;
1557
1558    /*
1559     * Make copies of apasswd and auser, then null-terminate them.
1560     * If there are unprintable characters in the password, make
1561     * them visible.
1562     */
1563    slprintf(passwd, sizeof(passwd), "%.*v", passwdlen, apasswd);
1564    slprintf(user, sizeof(user), "%.*v", userlen, auser);
1565    *msg = "";
1566
1567    /*
1568     * Check if a plugin wants to handle this.
1569     */
1570    if (pap_auth_hook) {
1571	ret = (*pap_auth_hook)(user, passwd, msg, &addrs, &opts);
1572	if (ret >= 0) {
1573	    if (ret)
1574		set_allowed_addrs(unit, addrs, opts);
1575	    BZERO(passwd, sizeof(passwd));
1576	    if (addrs != 0)
1577		free_wordlist(addrs);
1578	    if (opts != 0) {
1579		free_wordlist(opts);
1580	    }
1581	    return ret? UPAP_AUTHACK: UPAP_AUTHNAK;
1582	}
1583    }
1584
1585    /*
1586     * Open the file of pap secrets and scan for a suitable secret
1587     * for authenticating this user.
1588     */
1589    filename = _PATH_UPAPFILE;
1590    addrs = opts = NULL;
1591    ret = UPAP_AUTHNAK;
1592    f = fopen(filename, "r");
1593    if (f == NULL) {
1594	error("Can't open PAP password file %s: %m", filename);
1595
1596    } else {
1597	check_access(f, filename);
1598	if (scan_authfile(f, user, our_name, secret, &addrs, &opts, filename, 0) < 0) {
1599	    warning("no PAP secret found for %s", user);
1600	} else {
1601	    /*
1602	     * If the secret is "@login", it means to check
1603	     * the password against the login database.
1604	     */
1605	    int login_secret = strcmp(secret, "@login") == 0;
1606	    ret = UPAP_AUTHACK;
1607	    if (uselogin || login_secret) {
1608		/* login option or secret is @login */
1609		if ((ret = plogin(user, passwd, msg)) == UPAP_AUTHACK)
1610		    used_login = 1;
1611	    }
1612	    if (secret[0] != 0 && !login_secret) {
1613		/* password given in pap-secrets - must match */
1614		if ((cryptpap || strcmp(passwd, secret) != 0)
1615		    && strcmp(crypt(passwd, secret), secret) != 0)
1616		    ret = UPAP_AUTHNAK;
1617	    }
1618	}
1619	fclose(f);
1620    }
1621
1622    if (ret == UPAP_AUTHNAK) {
1623        if (**msg == 0)
1624	    *msg = "Login incorrect";
1625	/*
1626	 * XXX can we ever get here more than once??
1627	 * Frustrate passwd stealer programs.
1628	 * Allow 10 tries, but start backing off after 3 (stolen from login).
1629	 * On 10'th, drop the connection.
1630	 */
1631	if (attempts++ >= 10) {
1632	    warning("%d LOGIN FAILURES ON %s, %s", attempts, devnam, user);
1633	    lcp_close(unit, "login failed");
1634	}
1635	if (attempts > 3)
1636	    sleep((u_int) (attempts - 3) * 5);
1637	if (opts != NULL)
1638	    free_wordlist(opts);
1639
1640    } else {
1641	attempts = 0;			/* Reset count */
1642	if (**msg == 0)
1643	    *msg = "Login ok";
1644	set_allowed_addrs(unit, addrs, opts);
1645    }
1646
1647    if (addrs != NULL)
1648	free_wordlist(addrs);
1649    BZERO(passwd, sizeof(passwd));
1650    BZERO(secret, sizeof(secret));
1651
1652    return ret;
1653}
1654
1655/*
1656 * This function is needed for PAM.
1657 */
1658
1659#ifdef USE_PAM
1660/* Static variables used to communicate between the conversation function
1661 * and the server_login function
1662 */
1663static char *PAM_username;
1664static char *PAM_password;
1665static int PAM_error = 0;
1666static pam_handle_t *pamh = NULL;
1667
1668/* PAM conversation function
1669 * Here we assume (for now, at least) that echo on means login name, and
1670 * echo off means password.
1671 */
1672
1673static int PAM_conv (int num_msg,
1674#ifndef SOL2
1675    const
1676#endif
1677    struct pam_message **msg,
1678    struct pam_response **resp, void *appdata_ptr)
1679{
1680    int replies = 0;
1681    struct pam_response *reply = NULL;
1682
1683#define COPY_STRING(s) (s) ? strdup(s) : NULL
1684
1685    reply = malloc(sizeof(struct pam_response) * num_msg);
1686    if (!reply) return PAM_CONV_ERR;
1687
1688    for (replies = 0; replies < num_msg; replies++) {
1689        switch (msg[replies]->msg_style) {
1690            case PAM_PROMPT_ECHO_ON:
1691                reply[replies].resp_retcode = PAM_SUCCESS;
1692                reply[replies].resp = COPY_STRING(PAM_username);
1693                /* PAM frees resp */
1694                break;
1695            case PAM_PROMPT_ECHO_OFF:
1696                reply[replies].resp_retcode = PAM_SUCCESS;
1697                reply[replies].resp = COPY_STRING(PAM_password);
1698                /* PAM frees resp */
1699                break;
1700            case PAM_TEXT_INFO:
1701                /* fall through */
1702            case PAM_ERROR_MSG:
1703                /* ignore it, but pam still wants a NULL response... */
1704                reply[replies].resp_retcode = PAM_SUCCESS;
1705                reply[replies].resp = NULL;
1706                break;
1707            default:
1708                /* Must be an error of some sort... */
1709                free (reply);
1710                PAM_error = 1;
1711                return PAM_CONV_ERR;
1712        }
1713    }
1714    *resp = reply;
1715    return PAM_SUCCESS;
1716}
1717
1718static struct pam_conv PAM_conversation = {
1719    &PAM_conv,
1720    NULL
1721};
1722#endif  /* USE_PAM */
1723
1724/*
1725 * plogin - Check the user name and password against the system
1726 * password database, and login the user if OK.
1727 *
1728 * returns:
1729 *	UPAP_AUTHNAK: Login failed.
1730 *	UPAP_AUTHACK: Login succeeded.
1731 * In either case, msg points to an appropriate message.
1732 */
1733
1734static int
1735plogin(user, passwd, msg)
1736    char *user;
1737    char *passwd;
1738    char **msg;
1739{
1740    char *tty;
1741
1742#ifdef USE_PAM
1743    int pam_error;
1744
1745    pam_error = pam_start ("ppp", user, &PAM_conversation, &pamh);
1746    if (pam_error != PAM_SUCCESS) {
1747        *msg = (char *) pam_strerror (pamh, pam_error);
1748	reopen_log();
1749	return UPAP_AUTHNAK;
1750    }
1751    /*
1752     * Define the fields for the credential validation
1753     */
1754
1755    PAM_username = user;
1756    PAM_password = passwd;
1757    PAM_error = 0;
1758    pam_set_item (pamh, PAM_TTY, devnam); /* this might be useful to some modules */
1759
1760    /*
1761     * Validate the user
1762     */
1763    pam_error = pam_authenticate (pamh, PAM_SILENT);
1764    if (pam_error == PAM_SUCCESS && !PAM_error) {
1765        pam_error = pam_acct_mgmt (pamh, PAM_SILENT);
1766        if (pam_error == PAM_SUCCESS)
1767	    pam_error = pam_open_session (pamh, PAM_SILENT);
1768    }
1769
1770    *msg = (char *) pam_strerror (pamh, pam_error);
1771
1772    /*
1773     * Clean up the mess
1774     */
1775    reopen_log();	/* apparently the PAM stuff does closelog() */
1776    PAM_username = NULL;
1777    PAM_password = NULL;
1778    if (pam_error != PAM_SUCCESS)
1779        return UPAP_AUTHNAK;
1780#else /* #ifdef USE_PAM */
1781
1782/*
1783 * Use the non-PAM methods directly
1784 */
1785
1786#ifdef HAS_SHADOW
1787    struct spwd *spwd;
1788    struct spwd *getspnam();
1789#endif
1790    struct passwd *pw = getpwnam(user);
1791
1792    endpwent();
1793    if (pw == NULL)
1794	return (UPAP_AUTHNAK);
1795
1796#ifdef HAS_SHADOW
1797    spwd = getspnam(user);
1798    endspent();
1799    if (spwd) {
1800	/* check the age of the password entry */
1801	long now = time(NULL) / 86400L;
1802
1803	if ((spwd->sp_expire > 0 && now >= spwd->sp_expire)
1804	    || ((spwd->sp_max >= 0 && spwd->sp_max < 10000)
1805		&& spwd->sp_lstchg >= 0
1806		&& now >= spwd->sp_lstchg + spwd->sp_max)) {
1807	    warning("Password for %s has expired", user);
1808	    return (UPAP_AUTHNAK);
1809	}
1810	pw->pw_passwd = spwd->sp_pwdp;
1811    }
1812#endif
1813
1814    /*
1815     * If no passwd, don't let them login.
1816     */
1817    if (pw->pw_passwd == NULL || strlen(pw->pw_passwd) < 2
1818	|| strcmp(crypt(passwd, pw->pw_passwd), pw->pw_passwd) != 0)
1819	return (UPAP_AUTHNAK);
1820
1821#endif /* #ifdef USE_PAM */
1822
1823    /*
1824     * Write a wtmp entry for this user.
1825     */
1826
1827    tty = devnam;
1828    if (strncmp(tty, "/dev/", 5) == 0)
1829	tty += 5;
1830#ifdef UTMPX_AUTOFILL_MASK
1831    {
1832	struct utmpx utx;
1833
1834	bzero(&utx, sizeof(utx));
1835	/*
1836	 * This will automatically create a lastlog entry, as well as
1837	 * creating a utmpx and wtmpx entry.
1838	 */
1839	utx.ut_type = UTMPX_AUTOFILL_MASK | LOGIN_PROCESS;
1840	(void)strncpy(utx.ut_line, tty, sizeof(utx.ut_line));
1841	(void)pututxline(&utx);
1842    }
1843#else /* !UTMPX_AUTOFILL_MASK */
1844    logwtmp(tty, user, ifname);		/* Add wtmp login entry */
1845
1846#if defined(_PATH_LASTLOG) && !defined(USE_PAM)
1847    if (pw != (struct passwd *)NULL) {
1848	    struct lastlog ll;
1849	    int fd;
1850
1851	    if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) {
1852		(void)lseek(fd, (off_t)(pw->pw_uid * sizeof(ll)), SEEK_SET);
1853		memset((void *)&ll, 0, sizeof(ll));
1854		(void)time(&ll.ll_time);
1855		(void)strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
1856		(void)write(fd, (char *)&ll, sizeof(ll));
1857		(void)close(fd);
1858	    }
1859    }
1860#endif /* _PATH_LASTLOG and not USE_PAM */
1861#endif /* UTMPX_AUTOFILL_MASK */
1862
1863    info("user %s logged in", user);
1864    logged_in = 1;
1865
1866    return (UPAP_AUTHACK);
1867}
1868
1869/*
1870 * plogout - Logout the user.
1871 */
1872static void
1873plogout()
1874{
1875#ifdef USE_PAM
1876    int pam_error;
1877
1878    if (pamh != NULL) {
1879	pam_error = pam_close_session (pamh, PAM_SILENT);
1880	pam_end (pamh, pam_error);
1881	pamh = NULL;
1882    }
1883    /* Apparently the pam stuff does closelog(). */
1884    reopen_log();
1885#else /* ! USE_PAM */
1886    char *tty;
1887
1888    tty = devnam;
1889    if (strncmp(tty, "/dev/", 5) == 0)
1890	tty += 5;
1891#ifdef UTMPX_AUTOFILL_MASK
1892    {
1893	struct utmpx utx;
1894
1895	bzero(&utx, sizeof(utx));
1896	/*
1897	 * This will clear out the utmpx and wtmpx entries, provided
1898	 * the plogin pututxline succeeded
1899	 */
1900	utx.ut_type = UTMPX_AUTOFILL_MASK | UTMPX_DEAD_IF_CORRESPONDING_MASK
1901			| DEAD_PROCESS;
1902	(void)strncpy(utx.ut_line, tty, sizeof(utx.ut_line));
1903	(void)pututxline(&utx);
1904    }
1905#else /* !UTMPX_AUTOFILL_MASK */
1906    logwtmp(tty, "", "");		/* Wipe out utmp logout entry */
1907#endif /* UTMPX_AUTOFILL_MASK */
1908#endif /* ! USE_PAM */
1909    logged_in = 0;
1910}
1911
1912
1913/*
1914 * null_login - Check if a username of "" and a password of "" are
1915 * acceptable, and iff so, set the list of acceptable IP addresses
1916 * and return 1.
1917 */
1918static int
1919null_login(unit)
1920    int unit;
1921{
1922    char *filename;
1923    FILE *f;
1924    int i, ret;
1925    struct wordlist *addrs, *opts;
1926    char secret[MAXWORDLEN];
1927
1928    /*
1929     * Check if a plugin wants to handle this.
1930     */
1931    ret = -1;
1932    if (null_auth_hook)
1933	ret = (*null_auth_hook)(&addrs, &opts);
1934
1935    /*
1936     * Open the file of pap secrets and scan for a suitable secret.
1937     */
1938    if (ret <= 0) {
1939	filename = _PATH_UPAPFILE;
1940	addrs = NULL;
1941	f = fopen(filename, "r");
1942	if (f == NULL)
1943	    return 0;
1944	check_access(f, filename);
1945
1946	i = scan_authfile(f, "", our_name, secret, &addrs, &opts, filename, 0);
1947	ret = i >= 0 && secret[0] == 0;
1948	BZERO(secret, sizeof(secret));
1949	fclose(f);
1950    }
1951
1952    if (ret)
1953	set_allowed_addrs(unit, addrs, opts);
1954    else if (opts != 0)
1955	free_wordlist(opts);
1956    if (addrs != 0)
1957	free_wordlist(addrs);
1958
1959    return ret;
1960}
1961
1962
1963/*
1964 * get_pap_passwd - get a password for authenticating ourselves with
1965 * our peer using PAP.  Returns 1 on success, 0 if no suitable password
1966 * could be found.
1967 * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null).
1968 */
1969static int
1970get_pap_passwd(passwd)
1971    char *passwd;
1972{
1973    char *filename;
1974    FILE *f;
1975    int ret;
1976    char secret[MAXWORDLEN];
1977
1978    /*
1979     * Check whether a plugin wants to supply this.
1980     */
1981    if (pap_passwd_hook) {
1982	ret = (*pap_passwd_hook)(user, passwd);
1983	if (ret >= 0)
1984	    return ret;
1985    }
1986
1987    filename = _PATH_UPAPFILE;
1988    f = fopen(filename, "r");
1989    if (f == NULL)
1990	return 0;
1991    check_access(f, filename);
1992    ret = scan_authfile(f, user,
1993			(remote_name[0]? remote_name: NULL),
1994			secret, NULL, NULL, filename, 0);
1995    fclose(f);
1996    if (ret < 0)
1997	return 0;
1998    if (passwd != NULL)
1999	strlcpy(passwd, secret, MAXSECRETLEN);
2000    BZERO(secret, sizeof(secret));
2001    return 1;
2002}
2003
2004
2005/*
2006 * have_pap_secret - check whether we have a PAP file with any
2007 * secrets that we could possibly use for authenticating the peer.
2008 */
2009static int
2010have_pap_secret(lacks_ipp)
2011    int *lacks_ipp;
2012{
2013    FILE *f;
2014    int ret;
2015    char *filename;
2016    struct wordlist *addrs;
2017
2018    /* let the plugin decide, if there is one */
2019    if (pap_check_hook) {
2020	ret = (*pap_check_hook)();
2021	if (ret >= 0)
2022	    return ret;
2023    }
2024
2025    filename = _PATH_UPAPFILE;
2026    f = fopen(filename, "r");
2027    if (f == NULL)
2028	return 0;
2029
2030    ret = scan_authfile(f, (explicit_remote? remote_name: NULL), our_name,
2031			NULL, &addrs, NULL, filename, 0);
2032    fclose(f);
2033    if (ret >= 0 && !some_ip_ok(addrs)) {
2034	if (lacks_ipp != 0)
2035	    *lacks_ipp = 1;
2036	ret = -1;
2037    }
2038    if (addrs != 0)
2039	free_wordlist(addrs);
2040
2041    return ret >= 0;
2042}
2043
2044
2045/*
2046 * have_chap_secret - check whether we have a CHAP file with a
2047 * secret that we could possibly use for authenticating `client'
2048 * on `server'.  Either can be the null string, meaning we don't
2049 * know the identity yet.
2050 */
2051static int
2052have_chap_secret(client, server, need_ip, lacks_ipp)
2053    char *client;
2054    char *server;
2055    int need_ip;
2056    int *lacks_ipp;
2057{
2058    FILE *f;
2059    int ret;
2060    char *filename;
2061    struct wordlist *addrs;
2062
2063    if (chap_check_hook) {
2064	ret = (*chap_check_hook)();
2065	if (ret >= 0) {
2066	    return ret;
2067	}
2068    }
2069
2070    filename = _PATH_CHAPFILE;
2071    f = fopen(filename, "r");
2072    if (f == NULL)
2073	return 0;
2074
2075    if (client != NULL && client[0] == 0)
2076	client = NULL;
2077    else if (server != NULL && server[0] == 0)
2078	server = NULL;
2079
2080    ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0);
2081    fclose(f);
2082    if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
2083	if (lacks_ipp != 0)
2084	    *lacks_ipp = 1;
2085	ret = -1;
2086    }
2087    if (addrs != 0)
2088	free_wordlist(addrs);
2089
2090    return ret >= 0;
2091}
2092
2093#ifndef __APPLE__
2094/*
2095 * have_srp_secret - check whether we have a SRP file with a
2096 * secret that we could possibly use for authenticating `client'
2097 * on `server'.  Either can be the null string, meaning we don't
2098 * know the identity yet.
2099 */
2100static int
2101have_srp_secret(client, server, need_ip, lacks_ipp)
2102    char *client;
2103    char *server;
2104    int need_ip;
2105    int *lacks_ipp;
2106{
2107    FILE *f;
2108    int ret;
2109    char *filename;
2110    struct wordlist *addrs;
2111
2112    filename = _PATH_SRPFILE;
2113    f = fopen(filename, "r");
2114    if (f == NULL)
2115	return 0;
2116
2117    if (client != NULL && client[0] == 0)
2118	client = NULL;
2119    else if (server != NULL && server[0] == 0)
2120	server = NULL;
2121
2122    ret = scan_authfile(f, client, server, NULL, &addrs, NULL, filename, 0);
2123    fclose(f);
2124    if (ret >= 0 && need_ip && !some_ip_ok(addrs)) {
2125	if (lacks_ipp != 0)
2126	    *lacks_ipp = 1;
2127	ret = -1;
2128    }
2129    if (addrs != 0)
2130	free_wordlist(addrs);
2131
2132    return ret >= 0;
2133}
2134#endif
2135
2136/*
2137 * get_secret - open the CHAP secret file and return the secret
2138 * for authenticating the given client on the given server.
2139 * (We could be either client or server).
2140 */
2141int
2142get_secret(unit, client, server, secret, secret_len, am_server)
2143    int unit;
2144    u_char *client;
2145    u_char *server;
2146    u_char *secret;
2147    int *secret_len;
2148    int am_server;
2149{
2150    FILE *f;
2151    int ret, len;
2152    char *filename;
2153    struct wordlist *addrs, *opts;
2154    char secbuf[MAXWORDLEN];
2155
2156    if (!am_server && passwd[0] != 0) {
2157	strlcpy(secbuf, passwd, sizeof(secbuf));
2158    } else if (!am_server && chap_passwd_hook) {
2159	if ( (*chap_passwd_hook)((char*)client, secbuf) < 0) {
2160	    error("Unable to obtain CHAP password for %s on %s from plugin",
2161		  client, server);
2162	    return 0;
2163	}
2164    } else {
2165	filename = _PATH_CHAPFILE;
2166	addrs = NULL;
2167	secbuf[0] = 0;
2168
2169	f = fopen(filename, "r");
2170	if (f == NULL) {
2171	    error("Can't open chap secret file %s: %m", filename);
2172	    return 0;
2173	}
2174	check_access(f, filename);
2175
2176	ret = scan_authfile(f, (char*)client, (char*)server, secbuf, &addrs, &opts, filename, 0);
2177	fclose(f);
2178	if (ret < 0)
2179	    return 0;
2180
2181	if (am_server)
2182	    set_allowed_addrs(unit, addrs, opts);
2183	else if (opts != 0)
2184	    free_wordlist(opts);
2185	if (addrs != 0)
2186	    free_wordlist(addrs);
2187    }
2188
2189    len = strlen(secbuf);
2190    if (len > MAXSECRETLEN) {
2191	error("Secret for %s on %s is too long", client, server);
2192	len = MAXSECRETLEN;
2193    }
2194    BCOPY(secbuf, secret, len);
2195    BZERO(secbuf, sizeof(secbuf));
2196    *secret_len = len;
2197
2198    return 1;
2199}
2200
2201
2202/*
2203 * get_srp_secret - open the SRP secret file and return the secret
2204 * for authenticating the given client on the given server.
2205 * (We could be either client or server).
2206 */
2207int
2208get_srp_secret(unit, client, server, secret, am_server)
2209    int unit;
2210    char *client;
2211    char *server;
2212    char *secret;
2213    int am_server;
2214{
2215    FILE *fp;
2216    int ret;
2217    char *filename;
2218    struct wordlist *addrs, *opts;
2219
2220    if (!am_server && passwd[0] != '\0') {
2221	strlcpy(secret, passwd, MAXWORDLEN);
2222    } else {
2223	filename = _PATH_SRPFILE;
2224	addrs = NULL;
2225
2226	fp = fopen(filename, "r");
2227	if (fp == NULL) {
2228	    error("Can't open srp secret file %s: %m", filename);
2229	    return 0;
2230	}
2231	check_access(fp, filename);
2232
2233	secret[0] = '\0';
2234	ret = scan_authfile(fp, client, server, secret, &addrs, &opts,
2235	    filename, am_server);
2236	fclose(fp);
2237	if (ret < 0)
2238	    return 0;
2239
2240	if (am_server)
2241	    set_allowed_addrs(unit, addrs, opts);
2242	else if (opts != NULL)
2243	    free_wordlist(opts);
2244	if (addrs != NULL)
2245	    free_wordlist(addrs);
2246    }
2247
2248    return 1;
2249}
2250
2251/*
2252 * set_allowed_addrs() - set the list of allowed addresses.
2253 * Also looks for `--' indicating options to apply for this peer
2254 * and leaves the following words in extra_options.
2255 */
2256static void
2257set_allowed_addrs(unit, addrs, opts)
2258    int unit;
2259    struct wordlist *addrs;
2260    struct wordlist *opts;
2261{
2262    int n;
2263    struct wordlist *ap, **plink;
2264    struct permitted_ip *ip;
2265    char *ptr_word, *ptr_mask;
2266    struct hostent *hp;
2267    struct netent *np;
2268    u_int32_t a, mask, ah, offset;
2269    struct ipcp_options *wo = &ipcp_wantoptions[unit];
2270    u_int32_t suggested_ip = 0;
2271
2272    if (addresses[unit] != NULL)
2273	free(addresses[unit]);
2274    addresses[unit] = NULL;
2275    if (extra_options != NULL)
2276	free_wordlist(extra_options);
2277    extra_options = opts;
2278
2279    /*
2280     * Count the number of IP addresses given.
2281     */
2282    n = wordlist_count(addrs) + wordlist_count(noauth_addrs);
2283    if (n == 0)
2284	return;
2285    ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip));
2286    if (ip == 0)
2287	return;
2288
2289    /* temporarily append the noauth_addrs list to addrs */
2290    for (plink = &addrs; *plink != NULL; plink = &(*plink)->next)
2291	;
2292    *plink = noauth_addrs;
2293
2294    n = 0;
2295    for (ap = addrs; ap != NULL; ap = ap->next) {
2296	/* "-" means no addresses authorized, "*" means any address allowed */
2297	ptr_word = ap->word;
2298	if (strcmp(ptr_word, "-") == 0)
2299	    break;
2300	if (strcmp(ptr_word, "*") == 0) {
2301	    ip[n].permit = 1;
2302	    ip[n].base = ip[n].mask = 0;
2303	    ++n;
2304	    break;
2305	}
2306
2307	ip[n].permit = 1;
2308	if (*ptr_word == '!') {
2309	    ip[n].permit = 0;
2310	    ++ptr_word;
2311	}
2312
2313	mask = ~ (u_int32_t) 0;
2314	offset = 0;
2315	ptr_mask = strchr (ptr_word, '/');
2316	if (ptr_mask != NULL) {
2317	    int bit_count;
2318	    char *endp;
2319
2320	    bit_count = (int) strtol (ptr_mask+1, &endp, 10);
2321	    if (bit_count <= 0 || bit_count > 32) {
2322		warning("invalid address length %v in auth. address list",
2323		     ptr_mask+1);
2324		continue;
2325	    }
2326	    bit_count = 32 - bit_count;	/* # bits in host part */
2327	    if (*endp == '+') {
2328		offset = ifunit + 1;
2329		++endp;
2330	    }
2331	    if (*endp != 0) {
2332		warning("invalid address length syntax: %v", ptr_mask+1);
2333		continue;
2334	    }
2335	    *ptr_mask = '\0';
2336	    mask <<= bit_count;
2337	}
2338
2339	hp = gethostbyname(ptr_word);
2340	if (hp != NULL && hp->h_addrtype == AF_INET) {
2341        memcpy(&a, hp->h_addr, sizeof(u_int32_t));      // Wcast-align fix - use memcpy for unknown alignment
2342	} else {
2343	    np = getnetbyname (ptr_word);
2344	    if (np != NULL && np->n_addrtype == AF_INET) {
2345		a = htonl ((u_int32_t)np->n_net);
2346		if (ptr_mask == NULL) {
2347		    /* calculate appropriate mask for net */
2348		    ah = ntohl(a);
2349		    if (IN_CLASSA(ah))
2350			mask = IN_CLASSA_NET;
2351		    else if (IN_CLASSB(ah))
2352			mask = IN_CLASSB_NET;
2353		    else if (IN_CLASSC(ah))
2354			mask = IN_CLASSC_NET;
2355		}
2356	    } else {
2357		a = inet_addr (ptr_word);
2358	    }
2359	}
2360
2361	if (ptr_mask != NULL)
2362	    *ptr_mask = '/';
2363
2364	if (a == (u_int32_t)-1L) {
2365	    warning("unknown host %s in auth. address list", ap->word);
2366	    continue;
2367	}
2368	if (offset != 0) {
2369	    if (offset >= ~mask) {
2370		warning("interface unit %d too large for subnet %v",
2371		     ifunit, ptr_word);
2372		continue;
2373	    }
2374	    a = htonl((ntohl(a) & mask) + offset);
2375	    mask = ~(u_int32_t)0;
2376	}
2377	ip[n].mask = htonl(mask);
2378	ip[n].base = a & ip[n].mask;
2379	++n;
2380	if (~mask == 0 && suggested_ip == 0)
2381	    suggested_ip = a;
2382    }
2383    *plink = NULL;
2384
2385    ip[n].permit = 0;		/* make the last entry forbid all addresses */
2386    ip[n].base = 0;		/* to terminate the list */
2387    ip[n].mask = 0;
2388
2389    addresses[unit] = ip;
2390
2391    /*
2392     * If the address given for the peer isn't authorized, or if
2393     * the user hasn't given one, AND there is an authorized address
2394     * which is a single host, then use that if we find one.
2395     */
2396    if (suggested_ip != 0
2397	&& (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr))) {
2398	wo->hisaddr = suggested_ip;
2399	/*
2400	 * Do we insist on this address?  No, if there are other
2401	 * addresses authorized than the suggested one.
2402	 */
2403	if (n > 1)
2404	    wo->accept_remote = 1;
2405    }
2406}
2407
2408/*
2409 * auth_ip_addr - check whether the peer is authorized to use
2410 * a given IP address.  Returns 1 if authorized, 0 otherwise.
2411 */
2412int
2413auth_ip_addr(unit, addr)
2414    int unit;
2415    u_int32_t addr;
2416{
2417    int ok;
2418
2419    /* don't allow loopback or multicast address */
2420    if (bad_ip_adrs(addr))
2421	return 0;
2422
2423    if (allowed_address_hook) {
2424	ok = allowed_address_hook(addr);
2425	if (ok >= 0) return ok;
2426    }
2427
2428#ifdef __APPLE__
2429    // check with the EAP plugin...
2430    if (auth_done[unit] & EAP_PEER) {
2431	ok = EAPAllowedAddr(unit, addr);
2432	if (ok >= 0) return ok;
2433    }
2434#endif
2435
2436    if (addresses[unit] != NULL) {
2437	ok = ip_addr_check(addr, addresses[unit]);
2438	if (ok >= 0)
2439	    return ok;
2440    }
2441
2442    if (auth_required)
2443	return 0;		/* no addresses authorized */
2444    return allow_any_ip || privileged || !have_route_to(addr);
2445}
2446
2447static int
2448ip_addr_check(addr, addrs)
2449    u_int32_t addr;
2450    struct permitted_ip *addrs;
2451{
2452    for (; ; ++addrs)
2453	if ((addr & addrs->mask) == addrs->base)
2454	    return addrs->permit;
2455}
2456
2457/*
2458 * bad_ip_adrs - return 1 if the IP address is one we don't want
2459 * to use, such as an address in the loopback net or a multicast address.
2460 * addr is in network byte order.
2461 */
2462int
2463bad_ip_adrs(addr)
2464    u_int32_t addr;
2465{
2466    addr = ntohl(addr);
2467
2468#ifdef __APPLE__
2469	/* some ISPs advertise their address as being in the loopback net
2470		it is ok, as long as the stack does not send/receive any packet with this address */
2471    return (addr == INADDR_LOOPBACK)
2472	|| IN_MULTICAST(addr) || IN_BADCLASS(addr);
2473#else
2474    return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
2475	|| IN_MULTICAST(addr) || IN_BADCLASS(addr);
2476#endif
2477}
2478
2479/*
2480 * some_ip_ok - check a wordlist to see if it authorizes any
2481 * IP address(es).
2482 */
2483static int
2484some_ip_ok(addrs)
2485    struct wordlist *addrs;
2486{
2487    for (; addrs != 0; addrs = addrs->next) {
2488	if (addrs->word[0] == '-')
2489	    break;
2490	if (addrs->word[0] != '!')
2491	    return 1;		/* some IP address is allowed */
2492    }
2493    return 0;
2494}
2495
2496/*
2497 * auth_number - check whether the remote number is allowed to connect.
2498 * Returns 1 if authorized, 0 otherwise.
2499 */
2500int
2501auth_number()
2502{
2503    struct wordlist *wp = permitted_numbers;
2504    int l;
2505
2506    /* Allow all if no authorization list. */
2507    if (!wp)
2508	return 1;
2509
2510    /* Allow if we have a match in the authorization list. */
2511    while (wp) {
2512	/* trailing '*' wildcard */
2513	l = strlen(wp->word);
2514	if ((wp->word)[l - 1] == '*')
2515	    l--;
2516	if (!strncasecmp(wp->word, remote_number, l))
2517	    return 1;
2518	wp = wp->next;
2519    }
2520
2521    return 0;
2522}
2523
2524/*
2525 * check_access - complain if a secret file has too-liberal permissions.
2526 */
2527static void
2528check_access(f, filename)
2529    FILE *f;
2530    char *filename;
2531{
2532    struct stat sbuf;
2533
2534    if (fstat(fileno(f), &sbuf) < 0) {
2535	warning("cannot stat secret file %s: %m", filename);
2536    } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
2537	warning("Warning - secret file %s has world and/or group access",
2538	     filename);
2539    }
2540}
2541
2542
2543/*
2544 * scan_authfile - Scan an authorization file for a secret suitable
2545 * for authenticating `client' on `server'.  The return value is -1
2546 * if no secret is found, otherwise >= 0.  The return value has
2547 * NONWILD_CLIENT set if the secret didn't have "*" for the client, and
2548 * NONWILD_SERVER set if the secret didn't have "*" for the server.
2549 * Any following words on the line up to a "--" (i.e. address authorization
2550 * info) are placed in a wordlist and returned in *addrs.  Any
2551 * following words (extra options) are placed in a wordlist and
2552 * returned in *opts.
2553 * We assume secret is NULL or points to MAXWORDLEN bytes of space.
2554  * Flags are non-zero if we need two colons in the secret in order to
2555 * match.
2556*/
2557static int
2558scan_authfile(f, client, server, secret, addrs, opts, filename, flags)
2559    FILE *f;
2560    char *client;
2561    char *server;
2562    char *secret;
2563    struct wordlist **addrs;
2564    struct wordlist **opts;
2565    char *filename;
2566    int flags;
2567{
2568    int newline, xxx;
2569    int got_flag, best_flag;
2570    FILE *sf;
2571    struct wordlist *ap, *addr_list, *alist, **app;
2572    char word[MAXWORDLEN];
2573    char atfile[MAXWORDLEN];
2574    char lsecret[MAXWORDLEN];
2575    char *cp;
2576
2577    if (addrs != NULL)
2578	*addrs = NULL;
2579    if (opts != NULL)
2580	*opts = NULL;
2581    addr_list = NULL;
2582    if (!getword(f, word, &newline, filename))
2583	return -1;		/* file is empty??? */
2584    newline = 1;
2585    best_flag = -1;
2586    for (;;) {
2587	/*
2588	 * Skip until we find a word at the start of a line.
2589	 */
2590	while (!newline && getword(f, word, &newline, filename))
2591	    ;
2592	if (!newline)
2593	    break;		/* got to end of file */
2594
2595	/*
2596	 * Got a client - check if it's a match or a wildcard.
2597	 */
2598	got_flag = 0;
2599	if (client != NULL && strcmp(word, client) != 0 && !ISWILD(word)) {
2600	    newline = 0;
2601	    continue;
2602	}
2603	if (!ISWILD(word))
2604	    got_flag = NONWILD_CLIENT;
2605
2606	/*
2607	 * Now get a server and check if it matches.
2608	 */
2609	if (!getword(f, word, &newline, filename))
2610	    break;
2611	if (newline)
2612	    continue;
2613	if (!ISWILD(word)) {
2614	    if (server != NULL && strcmp(word, server) != 0)
2615		continue;
2616	    got_flag |= NONWILD_SERVER;
2617	}
2618
2619	/*
2620	 * Got some sort of a match - see if it's better than what
2621	 * we have already.
2622	 */
2623	if (got_flag <= best_flag)
2624	    continue;
2625
2626	/*
2627	 * Get the secret.
2628	 */
2629	if (!getword(f, word, &newline, filename))
2630	    break;
2631	if (newline)
2632	    continue;
2633
2634	/*
2635	 * SRP-SHA1 authenticator should never be reading secrets from
2636	 * a file.  (Authenticatee may, though.)
2637	 */
2638	if (flags && ((cp = strchr(word, ':')) == NULL ||
2639	    strchr(cp + 1, ':') == NULL))
2640	    continue;
2641
2642	if (secret != NULL) {
2643	    /*
2644	     * Special syntax: @/pathname means read secret from file.
2645	     */
2646	    if (word[0] == '@' && word[1] == '/') {
2647		strlcpy(atfile, word+1, sizeof(atfile));
2648		if ((sf = fopen(atfile, "r")) == NULL) {
2649		    warning("can't open indirect secret file %s", atfile);
2650		    continue;
2651		}
2652		check_access(sf, atfile);
2653		if (!getword(sf, word, &xxx, atfile)) {
2654		    warning("no secret in indirect secret file %s", atfile);
2655		    fclose(sf);
2656		    continue;
2657		}
2658		fclose(sf);
2659	    }
2660	    strlcpy(lsecret, word, sizeof(lsecret));
2661	}
2662
2663	/*
2664	 * Now read address authorization info and make a wordlist.
2665	 */
2666	app = &alist;
2667	for (;;) {
2668	    if (!getword(f, word, &newline, filename) || newline)
2669		break;
2670		int	len = strlen(word) + 1;
2671	    ap = (struct wordlist *)
2672		    malloc(sizeof(struct wordlist) + len);
2673	    if (ap == NULL)
2674		novm("authorized addresses");
2675	    ap->word = (char *) (ap + 1);
2676	    strlcpy(ap->word, word, len);
2677	    *app = ap;
2678	    app = &ap->next;
2679	}
2680	*app = NULL;
2681
2682	/*
2683	 * This is the best so far; remember it.
2684	 */
2685	best_flag = got_flag;
2686	if (addr_list)
2687	    free_wordlist(addr_list);
2688	addr_list = alist;
2689	if (secret != NULL)
2690	    strlcpy(secret, lsecret, MAXWORDLEN);
2691
2692	if (!newline)
2693	    break;
2694    }
2695
2696    /* scan for a -- word indicating the start of options */
2697    for (app = &addr_list; (ap = *app) != NULL; app = &ap->next)
2698	if (strcmp(ap->word, "--") == 0)
2699	    break;
2700    /* ap = start of options */
2701    if (ap != NULL) {
2702	ap = ap->next;		/* first option */
2703	free(*app);			/* free the "--" word */
2704	*app = NULL;		/* terminate addr list */
2705    }
2706    if (opts != NULL)
2707	*opts = ap;
2708    else if (ap != NULL)
2709	free_wordlist(ap);
2710    if (addrs != NULL)
2711	*addrs = addr_list;
2712    else if (addr_list != NULL)
2713	free_wordlist(addr_list);
2714
2715    return best_flag;
2716}
2717
2718/*
2719 * wordlist_count - return the number of items in a wordlist
2720 */
2721static int
2722wordlist_count(wp)
2723    struct wordlist *wp;
2724{
2725    int n;
2726
2727    for (n = 0; wp != NULL; wp = wp->next)
2728	++n;
2729    return n;
2730}
2731
2732/*
2733 * free_wordlist - release memory allocated for a wordlist.
2734 */
2735static void
2736free_wordlist(wp)
2737    struct wordlist *wp;
2738{
2739    struct wordlist *next;
2740
2741    while (wp != NULL) {
2742	next = wp->next;
2743	free(wp);
2744	wp = next;
2745    }
2746}
2747
2748/*
2749 * auth_script_done - called when the auth-up or auth-down script
2750 * has finished.
2751 */
2752static void
2753auth_script_done(arg)
2754    void *arg;
2755{
2756    auth_script_pid = 0;
2757    switch (auth_script_state) {
2758    case s_up:
2759	if (auth_state == s_down) {
2760	    auth_script_state = s_down;
2761	    auth_script(_PATH_AUTHDOWN);
2762	}
2763	break;
2764    case s_down:
2765	if (auth_state == s_up) {
2766	    auth_script_state = s_up;
2767	    auth_script(_PATH_AUTHUP);
2768	}
2769	break;
2770    }
2771}
2772
2773/*
2774 * auth_script - execute a script with arguments
2775 * interface-name peer-name real-user tty speed
2776 */
2777static void
2778auth_script(script)
2779    char *script;
2780{
2781    char strspeed[32];
2782    struct passwd *pw;
2783    char struid[32];
2784    char *user_name;
2785    char *argv[8];
2786
2787    if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL)
2788	user_name = pw->pw_name;
2789    else {
2790	slprintf(struid, sizeof(struid), "%d", getuid());
2791	user_name = struid;
2792    }
2793    slprintf(strspeed, sizeof(strspeed), "%d", baud_rate);
2794
2795    argv[0] = script;
2796    argv[1] = ifname;
2797    argv[2] = peer_authname;
2798    argv[3] = user_name;
2799    argv[4] = devnam;
2800    argv[5] = strspeed;
2801    argv[6] = NULL;
2802
2803    auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL);
2804}
2805
2806#ifdef __APPLE__
2807
2808#include <CoreFoundation/CoreFoundation.h>
2809#include <Security/Security.h>
2810
2811#if !TARGET_OS_EMBEDDED
2812static int read_keychainpassword __P((SecPreferencesDomain , char *, char *, char *, int));
2813static int write_keychainpassword __P((SecPreferencesDomain , char *, char *, char *));
2814#endif
2815/*
2816 * get actual password from System keyChain.
2817 * the password passed is used as a key
2818 */
2819static int
2820keychainpassword(argv)
2821    char **argv;
2822{
2823#if !TARGET_OS_EMBEDDED
2824	if (read_keychainpassword(kSecPreferencesDomainSystem, *argv, 0, passwd, MAXSECRETLEN)) {
2825		strlcpy(passwdkey, *argv, sizeof(passwdkey));
2826		passwdfrom = PASSWDFROM_KEYCHAIN;
2827	}
2828	return 1;
2829#else
2830	option_error("no keychain support");
2831	return 1;
2832#endif
2833}
2834
2835/*
2836 * get actual password from User keyChain.
2837 * the password passed is used as a key
2838 */
2839static int
2840userkeychainpassword(argv)
2841    char **argv;
2842{
2843#if !TARGET_OS_EMBEDDED
2844	if (read_keychainpassword(kSecPreferencesDomainUser, *argv, 0, passwd, MAXSECRETLEN)) {
2845		strlcpy(passwdkey, *argv, sizeof(passwdkey));
2846		passwdfrom = PASSWDFROM_USERKEYCHAIN;
2847	}
2848	return 1;
2849#else
2850	option_error("no keychain support");
2851	return 1;
2852#endif
2853}
2854
2855/*
2856 * Save the new password to the keychain
2857 */
2858int
2859save_new_password()
2860{
2861	int ret = 0;
2862#if !TARGET_OS_EMBEDDED
2863	switch (passwdfrom) {
2864		case PASSWDFROM_KEYCHAIN:
2865			ret = write_keychainpassword(kSecPreferencesDomainSystem, passwdkey, 0, new_passwd);
2866			break;
2867		case PASSWDFROM_USERKEYCHAIN:
2868			ret = write_keychainpassword(kSecPreferencesDomainUser, passwdkey, 0, new_passwd);
2869			break;
2870	}
2871#endif
2872
2873	return ret;
2874}
2875
2876#if !TARGET_OS_EMBEDDED
2877
2878/*
2879 * read password from keyChain.
2880 */
2881static int
2882read_keychainpassword(SecPreferencesDomain domain, char *service, char *account,
2883						char *password, int maxlen)
2884
2885{
2886	SecKeychainRef keychain = NULL;
2887	void *cur_password = NULL;
2888	UInt32 cur_password_len	= 0;
2889	OSStatus status;
2890	int ret = 0;
2891
2892	if (domain == kSecPreferencesDomainUser)
2893		seteuid(getuid());
2894
2895	status = SecKeychainSetPreferenceDomain(domain);
2896	if (status != noErr) {
2897		option_error("failed to set %s keychain domain", domain == kSecPreferencesDomainUser ? "user" : "system");
2898		goto end;
2899	}
2900
2901	status = SecKeychainCopyDomainDefault(domain, &keychain);
2902	if (status != noErr) {
2903		option_error("failed to get %s keychain domain", domain == kSecPreferencesDomainUser ? "user" : "system");
2904		goto end;
2905	}
2906
2907	status = SecKeychainFindGenericPassword(keychain,
2908					        service ? strlen(service) : 0, service,
2909					        account ? strlen(account) : 0, account,
2910					        &cur_password_len, &cur_password,
2911					        NULL);
2912
2913	switch (status) {
2914
2915	    case noErr :
2916			break;
2917
2918	    case errSecItemNotFound :
2919			option_error("password not found in the %s keychain", domain == kSecPreferencesDomainUser ? "user" : "system");
2920			break;
2921
2922	    default :
2923			option_error("failed to get password from %s keychain (error %d)", domain == kSecPreferencesDomainUser ? "user" : "system", status);
2924	}
2925
2926end:
2927
2928	if (cur_password) {
2929		if (cur_password_len < maxlen) {
2930
2931			/*
2932			needs to be added and tested.
2933			Also need to add te change and save password case.
2934			CFStringRef aString = CFStringCreateWithBytes(NULL, cur_password, cur_password_len, kCFStringEncodingUTF8, FALSE);
2935			if (aString) {
2936				CFStringGetCString(aString, password, maxlen, kCFStringEncodingWindowsLatin1);
2937				CFRelease(aString);
2938			}
2939			*/
2940
2941			bcopy(cur_password, password, cur_password_len);
2942			password[cur_password_len] = 0;
2943			free(cur_password);
2944			ret = 1;
2945		}
2946		else
2947			option_error("password too long in %s keychain (error %d)", domain == kSecPreferencesDomainUser ? "user" : "system");
2948	}
2949
2950	if (keychain)
2951		CFRelease(keychain);
2952
2953	if (domain == kSecPreferencesDomainUser)
2954		seteuid(0);
2955
2956	return ret;
2957}
2958
2959/*
2960 * Save the new password to the keychain
2961 */
2962static int
2963write_keychainpassword(SecPreferencesDomain domain, char *service, char *account,
2964						char *password)
2965{
2966	SecKeychainRef keychain = NULL;
2967	OSStatus status;
2968	SecKeychainItemRef itemRef = NULL;
2969	void *cur_password = NULL;
2970	UInt32 cur_password_len	= 0;
2971	int	ret = 0;
2972
2973	if (domain == kSecPreferencesDomainUser)
2974		seteuid(getuid());
2975
2976	status = SecKeychainSetPreferenceDomain(domain);
2977	if (status != noErr) {
2978		warning("failed to set %s keychain domain", domain == kSecPreferencesDomainUser ? "user" : "system");
2979		goto end;
2980	}
2981
2982	status = SecKeychainCopyDomainDefault(domain, &keychain);
2983	if (status != noErr) {
2984		warning("failed to get %s keychain domain", domain == kSecPreferencesDomainUser ? "user" : "system");
2985		goto end;
2986	}
2987
2988	status = SecKeychainFindGenericPassword(keychain,
2989					        service ? strlen(service) : 0, service,
2990					        account ? strlen(account) : 0, account,
2991					        &cur_password_len, &cur_password,
2992					        &itemRef);
2993	switch (status) {
2994
2995	    case noErr :
2996			status = SecKeychainItemModifyContent(itemRef, NULL, strlen(password), password);
2997			switch (status) {
2998				case noErr :
2999					ret = 1;
3000					break;
3001				default :
3002					warning("Could not save the modify the keychain item (error %d)", status);
3003			}
3004			break;
3005
3006	    case errSecItemNotFound :
3007			option_error("password not found in the %s keychain", domain == kSecPreferencesDomainUser ? "user" : "system");
3008			break;
3009
3010		default :
3011			option_error("failed to get password from %s keychain (error %d)", domain == kSecPreferencesDomainUser ? "user" : "system");
3012	}
3013
3014end:
3015
3016	if (cur_password)
3017		free(cur_password);
3018
3019	if (itemRef)
3020		CFRelease(itemRef);
3021
3022	if (keychain)
3023		CFRelease(keychain);
3024
3025	if (domain == kSecPreferencesDomainUser)
3026		seteuid(0);
3027
3028	return ret;
3029}
3030#endif /* TARGET_OS_EMBEDDED */
3031#endif
3032