2 * "$Id: auth.c,v 1.41.2.2 2001/05/13 18:38:33 mike Exp $"
4 * Authorization routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2001 by Easy Software Products, all rights reserved.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
26 * AddLocation() - Add a location for authorization.
27 * AddName() - Add a name to a location...
28 * AllowHost() - Add a host name that is allowed to access the
30 * AllowIP() - Add an IP address or network that is allowed to
31 * access the location.
32 * CheckAuth() - Check authorization masks.
33 * CopyLocation() - Make a copy of a location...
34 * DeleteAllLocations() - Free all memory used for location authorization.
35 * DenyHost() - Add a host name that is not allowed to access the
37 * DenyIP() - Add an IP address or network that is not allowed
38 * to access the location.
39 * FindBest() - Find the location entry that best matches the
41 * FindLocation() - Find the named location.
42 * IsAuthorized() - Check to see if the user is authorized...
43 * add_allow() - Add an allow mask to the location.
44 * add_deny() - Add a deny mask to the location.
45 * get_md5_passwd() - Get an MD5 password.
46 * pam_func() - PAM conversation function.
50 * Include necessary headers...
58 #endif /* HAVE_SHADOW_H */
61 #endif /* HAVE_CRYPT_H */
63 # include <security/pam_appl.h>
64 #endif /* HAVE_LIBPAM */
67 #endif /* HAVE_USERSEC_H */
74 static authmask_t
*add_allow(location_t
*loc
);
75 static authmask_t
*add_deny(location_t
*loc
);
76 static char *get_md5_passwd(const char *username
, const char *group
,
79 static int pam_func(int, const struct pam_message
**,
80 struct pam_response
**, void *);
81 #endif /* HAVE_LIBPAM */
89 static client_t
*auth_client
; /* Current client being authenticated */
94 * 'AddLocation()' - Add a location for authorization.
97 location_t
* /* O - Pointer to new location record */
98 AddLocation(const char *location
) /* I - Location path */
100 location_t
*temp
; /* New location */
104 * Try to allocate memory for the new location.
107 if (NumLocations
== 0)
108 temp
= malloc(sizeof(location_t
));
110 temp
= realloc(Locations
, sizeof(location_t
) * (NumLocations
+ 1));
116 temp
+= NumLocations
;
120 * Initialize the record and copy the name over...
123 memset(temp
, 0, sizeof(location_t
));
124 strncpy(temp
->location
, location
, sizeof(temp
->location
) - 1);
125 temp
->length
= strlen(temp
->location
);
127 LogMessage(L_DEBUG
, "AddLocation: added location \'%s\'", location
);
130 * Return the new record...
138 * 'AddName()' - Add a name to a location...
142 AddName(location_t
*loc
, /* I - Location to add to */
143 char *name
) /* I - Name to add */
145 char **temp
; /* Pointer to names array */
148 if (loc
->num_names
== 0)
149 temp
= malloc(sizeof(char *));
151 temp
= realloc(loc
->names
, (loc
->num_names
+ 1) * sizeof(char *));
155 LogMessage(L_ERROR
, "Unable to add name to location %s: %s", loc
->location
,
162 if ((temp
[loc
->num_names
] = strdup(name
)) == NULL
)
164 LogMessage(L_ERROR
, "Unable to duplicate name for location %s: %s",
165 loc
->location
, strerror(errno
));
174 * 'AllowHost()' - Add a host name that is allowed to access the location.
178 AllowHost(location_t
*loc
, /* I - Location to add to */
179 char *name
) /* I - Name of host or domain to add */
181 authmask_t
*temp
; /* New host/domain mask */
184 if ((temp
= add_allow(loc
)) == NULL
)
187 temp
->type
= AUTH_NAME
;
188 temp
->mask
.name
.name
= strdup(name
);
189 temp
->mask
.name
.length
= strlen(name
);
191 LogMessage(L_DEBUG
, "AllowHost: %s allow %s", loc
->location
, name
);
196 * 'AllowIP()' - Add an IP address or network that is allowed to access the
201 AllowIP(location_t
*loc
, /* I - Location to add to */
202 unsigned address
[4], /* I - IP address to add */
203 unsigned netmask
[4]) /* I - Netmask of address */
205 authmask_t
*temp
; /* New host/domain mask */
208 if ((temp
= add_allow(loc
)) == NULL
)
211 temp
->type
= AUTH_IP
;
212 memcpy(temp
->mask
.ip
.address
, address
, sizeof(address
));
213 memcpy(temp
->mask
.ip
.netmask
, netmask
, sizeof(netmask
));
215 LogMessage(L_DEBUG
, "AllowIP: %s allow %08x/%08x", loc
->location
,
221 * 'CheckAuth()' - Check authorization masks.
224 int /* O - 1 if mask matches, 0 otherwise */
225 CheckAuth(unsigned ip
[4], /* I - Client address */
226 char *name
, /* I - Client hostname */
227 int name_len
, /* I - Length of hostname */
228 int num_masks
, /* I - Number of masks */
229 authmask_t
*masks
) /* I - Masks */
231 int i
; /* Looping var */
234 while (num_masks
> 0)
240 * Check for exact name match...
243 if (strcasecmp(name
, masks
->mask
.name
.name
) == 0)
247 * Check for domain match...
250 if (name_len
>= masks
->mask
.name
.length
&&
251 masks
->mask
.name
.name
[0] == '.' &&
252 strcasecmp(name
+ name_len
- masks
->mask
.name
.length
,
253 masks
->mask
.name
.name
) == 0)
259 * Check for IP/network address match...
262 for (i
= 0; i
< 4; i
++)
263 if ((ip
[i
] & masks
->mask
.ip
.netmask
[i
]) != masks
->mask
.ip
.address
[i
])
280 * 'CopyLocation()' - Make a copy of a location...
283 location_t
* /* O - New location */
284 CopyLocation(location_t
**loc
) /* IO - Original location */
286 int i
; /* Looping var */
287 int locindex
; /* Index into Locations array */
288 location_t
*temp
; /* New location */
292 * Add the new location, updating the original location
293 * pointer as needed...
296 locindex
= *loc
- Locations
;
298 if ((temp
= AddLocation((*loc
)->location
)) == NULL
)
301 *loc
= Locations
+ locindex
;
304 * Copy the information from the original location to the new one.
307 temp
->limit
= (*loc
)->limit
;
308 temp
->order_type
= (*loc
)->order_type
;
309 temp
->type
= (*loc
)->type
;
310 temp
->level
= (*loc
)->level
;
311 temp
->satisfy
= (*loc
)->satisfy
;
312 temp
->encryption
= (*loc
)->encryption
;
314 if ((temp
->num_names
= (*loc
)->num_names
) > 0)
317 * Copy the names array...
320 if ((temp
->names
= calloc(temp
->num_names
, sizeof(char *))) == NULL
)
322 LogMessage(L_ERROR
, "CopyLocation: Unable to allocate memory for %d names: %s",
323 temp
->num_names
, strerror(errno
));
328 for (i
= 0; i
< temp
->num_names
; i
++)
329 if ((temp
->names
[i
] = strdup((*loc
)->names
[i
])) == NULL
)
331 LogMessage(L_ERROR
, "CopyLocation: Unable to copy name \"%s\": %s",
332 (*loc
)->names
[i
], strerror(errno
));
339 if ((temp
->num_allow
= (*loc
)->num_allow
) > 0)
342 * Copy allow rules...
345 if ((temp
->allow
= calloc(temp
->num_allow
, sizeof(authmask_t
))) == NULL
)
347 LogMessage(L_ERROR
, "CopyLocation: Unable to allocate memory for %d allow rules: %s",
348 temp
->num_allow
, strerror(errno
));
353 for (i
= 0; i
< temp
->num_allow
; i
++)
354 switch (temp
->allow
[i
].type
= (*loc
)->allow
[i
].type
)
357 temp
->allow
[i
].mask
.name
.length
= (*loc
)->allow
[i
].mask
.name
.length
;
358 temp
->allow
[i
].mask
.name
.name
= strdup((*loc
)->allow
[i
].mask
.name
.name
);
360 if (temp
->allow
[i
].mask
.name
.name
== NULL
)
362 LogMessage(L_ERROR
, "CopyLocation: Unable to copy allow name \"%s\": %s",
363 (*loc
)->allow
[i
].mask
.name
.name
, strerror(errno
));
369 memcpy(&(temp
->allow
[i
].mask
.ip
), &((*loc
)->allow
[i
].mask
.ip
),
375 if ((temp
->num_deny
= (*loc
)->num_deny
) > 0)
381 if ((temp
->deny
= calloc(temp
->num_deny
, sizeof(authmask_t
))) == NULL
)
383 LogMessage(L_ERROR
, "CopyLocation: Unable to allocate memory for %d deny rules: %s",
384 temp
->num_deny
, strerror(errno
));
389 for (i
= 0; i
< temp
->num_deny
; i
++)
390 switch (temp
->deny
[i
].type
= (*loc
)->deny
[i
].type
)
393 temp
->deny
[i
].mask
.name
.length
= (*loc
)->deny
[i
].mask
.name
.length
;
394 temp
->deny
[i
].mask
.name
.name
= strdup((*loc
)->deny
[i
].mask
.name
.name
);
396 if (temp
->deny
[i
].mask
.name
.name
== NULL
)
398 LogMessage(L_ERROR
, "CopyLocation: Unable to copy deny name \"%s\": %s",
399 (*loc
)->deny
[i
].mask
.name
.name
, strerror(errno
));
405 memcpy(&(temp
->deny
[i
].mask
.ip
), &((*loc
)->deny
[i
].mask
.ip
),
416 * 'DeleteAllLocations()' - Free all memory used for location authorization.
420 DeleteAllLocations(void)
422 int i
, j
; /* Looping vars */
423 location_t
*loc
; /* Current location */
424 authmask_t
*mask
; /* Current mask */
428 * Free all of the allow/deny records first...
431 for (i
= NumLocations
, loc
= Locations
; i
> 0; i
--, loc
++)
433 for (j
= loc
->num_names
- 1; j
>= 0; j
--)
436 if (loc
->num_names
> 0)
439 for (j
= loc
->num_allow
, mask
= loc
->allow
; j
> 0; j
--, mask
++)
440 if (mask
->type
== AUTH_NAME
)
441 free(mask
->mask
.name
.name
);
443 if (loc
->num_allow
> 0)
446 for (j
= loc
->num_deny
, mask
= loc
->deny
; j
> 0; j
--, mask
++)
447 if (mask
->type
== AUTH_NAME
)
448 free(mask
->mask
.name
.name
);
450 if (loc
->num_deny
> 0)
455 * Then free the location array...
458 if (NumLocations
> 0)
467 * 'DenyHost()' - Add a host name that is not allowed to access the location.
471 DenyHost(location_t
*loc
, /* I - Location to add to */
472 char *name
) /* I - Name of host or domain to add */
474 authmask_t
*temp
; /* New host/domain mask */
477 if ((temp
= add_deny(loc
)) == NULL
)
480 temp
->type
= AUTH_NAME
;
481 temp
->mask
.name
.name
= strdup(name
);
482 temp
->mask
.name
.length
= strlen(name
);
484 LogMessage(L_DEBUG
, "DenyHost: %s deny %s", loc
->location
, name
);
489 * 'DenyIP()' - Add an IP address or network that is not allowed to access
494 DenyIP(location_t
*loc
, /* I - Location to add to */
495 unsigned address
[4], /* I - IP address to add */
496 unsigned netmask
[4]) /* I - Netmask of address */
498 authmask_t
*temp
; /* New host/domain mask */
501 if ((temp
= add_deny(loc
)) == NULL
)
504 temp
->type
= AUTH_IP
;
505 memcpy(temp
->mask
.ip
.address
, address
, sizeof(address
));
506 memcpy(temp
->mask
.ip
.netmask
, netmask
, sizeof(netmask
));
508 LogMessage(L_DEBUG
, "DenyIP: %s deny %08x/%08x\n", loc
->location
,
514 * 'FindBest()' - Find the location entry that best matches the resource.
517 location_t
* /* O - Location that matches */
518 FindBest(client_t
*con
) /* I - Connection */
520 int i
; /* Looping var */
521 location_t
*loc
, /* Current location */
522 *best
; /* Best match for location so far */
523 int bestlen
; /* Length of best match */
524 int limit
; /* Limit field */
525 static int limits
[] = /* Map http_status_t to AUTH_LIMIT_xyz */
545 * Loop through the list of locations to find a match...
548 limit
= limits
[con
->http
.state
];
552 for (i
= NumLocations
, loc
= Locations
; i
> 0; i
--, loc
++)
554 LogMessage(L_DEBUG2
, "FindBest: Location %s Limit %x",
555 loc
->location
, loc
->limit
);
557 if (loc
->length
> bestlen
&&
558 strncmp(con
->uri
, loc
->location
, loc
->length
) == 0 &&
559 loc
->location
[0] == '/' &&
560 (limit
& loc
->limit
) != 0)
563 bestlen
= loc
->length
;
568 * Return the match, if any...
571 LogMessage(L_DEBUG2
, "FindBest: best = %s", best
? best
->location
: "NONE");
578 * 'FindLocation()' - Find the named location.
581 location_t
* /* O - Location that matches */
582 FindLocation(const char *location
) /* I - Connection */
584 int i
; /* Looping var */
588 * Loop through the list of locations to find a match...
591 for (i
= 0; i
< NumLocations
; i
++)
592 if (strcasecmp(Locations
[i
].location
, location
) == 0)
593 return (Locations
+ i
);
600 * 'IsAuthorized()' - Check to see if the user is authorized...
603 http_status_t
/* O - HTTP_OK if authorized or error code */
604 IsAuthorized(client_t
*con
) /* I - Connection */
606 int i
, j
, /* Looping vars */
607 auth
; /* Authorization status */
608 unsigned address
[4]; /* Authorization address */
609 location_t
*best
; /* Best match for location so far */
610 int hostlen
; /* Length of hostname */
611 struct passwd
*pw
; /* User password data */
612 struct group
*grp
; /* Group data */
613 char nonce
[HTTP_MAX_VALUE
],
614 /* Nonce value from client */
615 md5
[33]; /* MD5 password */
617 pam_handle_t
*pamh
; /* PAM authentication handle */
618 int pamerr
; /* PAM error code */
619 struct pam_conv pamdata
; /* PAM conversation data */
620 #elif defined(HAVE_USERSEC_H)
621 char *authmsg
; /* Authentication message */
622 char *loginmsg
; /* Login message */
623 int reenter
; /* ??? */
625 char *pass
; /* Encrypted password */
626 # ifdef HAVE_SHADOW_H
627 struct spwd
*spw
; /* Shadow password data */
628 # endif /* HAVE_SHADOW_H */
629 #endif /* HAVE_LIBPAM */
630 static const char *states
[] = /* HTTP client states... */
649 LogMessage(L_DEBUG2
, "IsAuthorized: URI = %s", con
->uri
);
652 * Find a matching location; if there is no match then access is
656 if ((best
= FindBest(con
)) == NULL
)
657 return (HTTP_FORBIDDEN
);
660 * Check host/ip-based accesses...
664 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET6
)
666 address
[0] = ntohl(con
->http
.hostaddr
.ipv6
.sin6_addr
.s6_addr32
[0]);
667 address
[1] = ntohl(con
->http
.hostaddr
.ipv6
.sin6_addr
.s6_addr32
[1]);
668 address
[2] = ntohl(con
->http
.hostaddr
.ipv6
.sin6_addr
.s6_addr32
[2]);
669 address
[3] = ntohl(con
->http
.hostaddr
.ipv6
.sin6_addr
.s6_addr32
[3]);
672 #endif /* AF_INET6 */
673 if (con
->http
.hostaddr
.addr
.sa_family
== AF_INET
)
675 unsigned temp
; /* Temporary address variable */
679 * Convert 32-bit IPv4 address to 128 bits...
682 temp
= ntohl(con
->http
.hostaddr
.ipv4
.sin_addr
.s_addr
);
684 address
[3] = temp
& 255;
686 address
[2] = temp
& 255;
688 address
[1] = temp
& 255;
690 address
[0] = temp
& 255;
693 memset(address
, 0, sizeof(address
));
695 hostlen
= strlen(con
->http
.hostname
);
697 if (strcasecmp(con
->http
.hostname
, "localhost") == 0)
700 * Access from localhost (127.0.0.1 or 0.0.0.1) is always allowed...
708 * Do authorization checks on the domain/address...
711 switch (best
->order_type
)
714 auth
= AUTH_DENY
; /* anti-compiler-warning-code */
717 case AUTH_ALLOW
: /* Order Deny,Allow */
720 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
721 best
->num_deny
, best
->deny
))
724 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
725 best
->num_allow
, best
->allow
))
729 case AUTH_DENY
: /* Order Allow,Deny */
732 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
733 best
->num_allow
, best
->allow
))
736 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
737 best
->num_deny
, best
->deny
))
743 LogMessage(L_DEBUG2
, "IsAuthorized: auth = %d, satisfy=%d...",
744 auth
, best
->satisfy
);
746 if (auth
== AUTH_DENY
&& best
->satisfy
== AUTH_SATISFY_ALL
)
747 return (HTTP_FORBIDDEN
);
751 * See if encryption is required...
754 if (best
->encryption
>= HTTP_ENCRYPT_REQUIRED
&& !con
->http
.tls
)
756 LogMessage(L_DEBUG2
, "IsAuthorized: Need upgrade to TLS...");
757 return (HTTP_UPGRADE_REQUIRED
);
759 #endif /* HAVE_LIBSSL */
762 * Now see what access level is required...
765 if (best
->level
== AUTH_ANON
) /* Anonymous access - allow it */
768 LogMessage(L_DEBUG2
, "IsAuthorized: username = \"%s\" password = %d chars",
769 con
->username
, strlen(con
->password
));
770 DEBUG_printf(("IsAuthorized: username = \"%s\", password = \"%s\"\n",
771 con
->username
, con
->password
));
773 if (con
->username
[0] == '\0')
775 if (best
->satisfy
== AUTH_SATISFY_ALL
|| auth
== AUTH_DENY
)
776 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
778 return (HTTP_OK
); /* unless overridden with Satisfy */
782 * Check the user's password...
785 pw
= getpwnam(con
->username
); /* Get the current password */
786 endpwent(); /* Close the password file */
788 if (pw
== NULL
) /* No such user... */
790 LogMessage(L_WARN
, "IsAuthorized: Unknown username \"%s\"; access denied.",
792 return (HTTP_UNAUTHORIZED
);
795 LogMessage(L_DEBUG2
, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
796 con
->username
, address
, con
->http
.hostname
);
798 if (strcasecmp(con
->http
.hostname
, "localhost") != 0 ||
799 strncmp(con
->http
.fields
[HTTP_FIELD_AUTHORIZATION
], "Local", 5) != 0)
802 * Not doing local certificate-based authentication; check the password...
805 if (!con
->password
[0])
806 return (HTTP_UNAUTHORIZED
);
809 * See if we are doing Digest or Basic authentication...
812 if (best
->type
== AUTH_BASIC
)
816 * Only use PAM to do authentication. This allows MD5 passwords, among
820 pamdata
.conv
= pam_func
;
821 pamdata
.appdata_ptr
= con
;
825 * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
832 DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con
));
834 pamerr
= pam_start("cups", con
->username
, &pamdata
, &pamh
);
835 if (pamerr
!= PAM_SUCCESS
)
837 LogMessage(L_ERROR
, "IsAuthorized: pam_start() returned %d (%s)!\n",
838 pamerr
, pam_strerror(pamh
, pamerr
));
840 return (HTTP_UNAUTHORIZED
);
843 pamerr
= pam_authenticate(pamh
, PAM_SILENT
);
844 if (pamerr
!= PAM_SUCCESS
)
846 LogMessage(L_ERROR
, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
847 pamerr
, pam_strerror(pamh
, pamerr
));
849 return (HTTP_UNAUTHORIZED
);
852 pamerr
= pam_acct_mgmt(pamh
, PAM_SILENT
);
853 if (pamerr
!= PAM_SUCCESS
)
855 LogMessage(L_ERROR
, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
856 pamerr
, pam_strerror(pamh
, pamerr
));
858 return (HTTP_UNAUTHORIZED
);
861 pam_end(pamh
, PAM_SUCCESS
);
862 #elif defined(HAVE_USERSEC_H)
864 * Use AIX authentication interface...
867 LogMessage(L_DEBUG
, "IsAuthorized: AIX authenticate of username \"%s\"",
871 if (authenticate(con
->username
, con
->password
, &reenter
, &authmsg
) != 0)
873 LogMessage(L_DEBUG
, "IsAuthorized: Unable to authenticate username \"%s\": %s",
874 con
->username
, strerror(errno
));
875 return (HTTP_UNAUTHORIZED
);
878 # ifdef HAVE_SHADOW_H
879 spw
= getspnam(con
->username
);
882 if (spw
== NULL
&& strcmp(pw
->pw_passwd
, "x") == 0)
883 { /* Don't allow blank passwords! */
884 LogMessage(L_WARN
, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
886 return (HTTP_UNAUTHORIZED
); /* No such user or bad shadow file */
891 printf("spw->sp_pwdp = \"%s\"\n", spw
->sp_pwdp
);
896 if (spw
!= NULL
&& spw
->sp_pwdp
[0] == '\0' && pw
->pw_passwd
[0] == '\0')
898 if (pw
->pw_passwd
[0] == '\0') /* Don't allow blank passwords! */
899 # endif /* HAVE_SHADOW_H */
900 { /* Don't allow blank passwords! */
901 LogMessage(L_WARN
, "IsAuthorized: Username \"%s\" has no password; access denied.",
903 return (HTTP_UNAUTHORIZED
);
907 * OK, the password isn't blank, so compare with what came from the client...
910 LogMessage(L_DEBUG2
, "IsAuthorized: pw_passwd = %s, crypt = %s",
911 pw
->pw_passwd
, crypt(con
->password
, pw
->pw_passwd
));
913 pass
= crypt(con
->password
, pw
->pw_passwd
);
916 strcmp(pw
->pw_passwd
, crypt(con
->password
, pw
->pw_passwd
)) != 0)
918 # ifdef HAVE_SHADOW_H
921 LogMessage(L_DEBUG2
, "IsAuthorized: sp_pwdp = %s, crypt = %s",
922 spw
->sp_pwdp
, crypt(con
->password
, spw
->sp_pwdp
));
924 pass
= crypt(con
->password
, spw
->sp_pwdp
);
927 strcmp(spw
->sp_pwdp
, crypt(con
->password
, spw
->sp_pwdp
)) != 0)
928 return (HTTP_UNAUTHORIZED
);
931 # endif /* HAVE_SHADOW_H */
932 return (HTTP_UNAUTHORIZED
);
934 #endif /* HAVE_LIBPAM */
939 * Do Digest authentication...
942 if (!httpGetSubField(&(con
->http
), HTTP_FIELD_WWW_AUTHENTICATE
, "nonce",
945 LogMessage(L_ERROR
, "IsAuthorized: No nonce value for Digest authentication!");
946 return (HTTP_UNAUTHORIZED
);
949 if (strcmp(con
->http
.hostname
, nonce
) != 0)
951 LogMessage(L_ERROR
, "IsAuthorized: Nonce value error!");
952 LogMessage(L_ERROR
, "IsAuthorized: Expected \"%s\",",
954 LogMessage(L_ERROR
, "IsAuthorized: Got \"%s\"!", nonce
);
955 return (HTTP_UNAUTHORIZED
);
958 if (!get_md5_passwd(con
->username
, best
->names
[0], md5
))
960 LogMessage(L_ERROR
, "IsAuthorized: No user:group for \"%s:%s\" in passwd.md5!",
961 con
->username
, best
->names
[0]);
962 return (HTTP_UNAUTHORIZED
);
965 httpMD5Final(nonce
, states
[con
->http
.state
], con
->uri
, md5
);
967 if (strcmp(md5
, con
->password
) != 0)
969 LogMessage(L_ERROR
, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
971 return (HTTP_UNAUTHORIZED
);
977 * OK, the password is good. See if we need normal user access, or group
978 * access... (root always matches)
981 if (strcmp(con
->username
, "root") == 0)
984 if (best
->level
== AUTH_USER
)
987 * If there are no names associated with this location, then
988 * any valid user is OK...
991 LogMessage(L_DEBUG2
, "IsAuthorized: Checking user membership...");
993 if (best
->num_names
== 0)
997 * Otherwise check the user list and return OK if this user is
1001 for (i
= 0; i
< best
->num_names
; i
++)
1002 if (strcmp(con
->username
, best
->names
[i
]) == 0)
1005 return (HTTP_UNAUTHORIZED
);
1009 * Check to see if this user is in any of the named groups...
1012 LogMessage(L_DEBUG2
, "IsAuthorized: Checking group membership...");
1014 for (i
= 0; i
< best
->num_names
; i
++)
1016 grp
= getgrnam(best
->names
[i
]);
1019 if (grp
== NULL
) /* No group by that name??? */
1021 LogMessage(L_WARN
, "IsAuthorized: group name \"%s\" does not exist!",
1023 return (HTTP_FORBIDDEN
);
1026 for (j
= 0; grp
->gr_mem
[j
] != NULL
; j
++)
1027 if (strcmp(con
->username
, grp
->gr_mem
[j
]) == 0)
1031 * Check to see if the default group ID matches for the user...
1034 if (grp
->gr_gid
== pw
->pw_gid
)
1039 * The user isn't part of the specified group, so deny access...
1042 LogMessage(L_DEBUG2
, "IsAuthorized: user not in group!");
1044 return (HTTP_UNAUTHORIZED
);
1049 * 'add_allow()' - Add an allow mask to the location.
1052 static authmask_t
* /* O - New mask record */
1053 add_allow(location_t
*loc
) /* I - Location to add to */
1055 authmask_t
*temp
; /* New mask record */
1066 * Try to allocate memory for the record...
1069 if (loc
->num_allow
== 0)
1070 temp
= malloc(sizeof(authmask_t
));
1072 temp
= realloc(loc
->allow
, sizeof(authmask_t
) * (loc
->num_allow
+ 1));
1078 temp
+= loc
->num_allow
;
1082 * Clear the mask record and return...
1085 memset(temp
, 0, sizeof(authmask_t
));
1091 * 'add_deny()' - Add a deny mask to the location.
1094 static authmask_t
* /* O - New mask record */
1095 add_deny(location_t
*loc
) /* I - Location to add to */
1097 authmask_t
*temp
; /* New mask record */
1108 * Try to allocate memory for the record...
1111 if (loc
->num_deny
== 0)
1112 temp
= malloc(sizeof(authmask_t
));
1114 temp
= realloc(loc
->deny
, sizeof(authmask_t
) * (loc
->num_deny
+ 1));
1120 temp
+= loc
->num_deny
;
1124 * Clear the mask record and return...
1127 memset(temp
, 0, sizeof(authmask_t
));
1133 * 'get_md5_passwd()' - Get an MD5 password.
1136 static char * /* O - MD5 password string */
1137 get_md5_passwd(const char *username
, /* I - Username */
1138 const char *group
, /* I - Group */
1139 char passwd
[33]) /* O - MD5 password string */
1141 FILE *fp
; /* passwd.md5 file */
1142 char filename
[1024], /* passwd.md5 filename */
1143 line
[256], /* Line from file */
1144 tempuser
[33], /* User from file */
1145 tempgroup
[33]; /* Group from file */
1148 snprintf(filename
, sizeof(filename
), "%s/passwd.md5", ServerRoot
);
1149 if ((fp
= fopen(filename
, "r")) == NULL
)
1152 while (fgets(line
, sizeof(line
), fp
) != NULL
)
1154 if (sscanf(line
, "%32[^:]:%32[^:]:%32s", tempuser
, tempgroup
, passwd
) != 3)
1157 if (strcmp(username
, tempuser
) == 0 &&
1158 strcmp(group
, tempgroup
) == 0)
1161 * Found the password entry!
1170 * Didn't find a password entry - return NULL!
1180 * 'pam_func()' - PAM conversation function.
1183 static int /* O - Success or failure */
1184 pam_func(int num_msg
, /* I - Number of messages */
1185 const struct pam_message
**msg
, /* I - Messages */
1186 struct pam_response
**resp
, /* O - Responses */
1187 void *appdata_ptr
) /* I - Pointer to connection */
1189 int i
; /* Looping var */
1190 struct pam_response
*replies
; /* Replies */
1191 client_t
*client
; /* Pointer client connection */
1195 * Allocate memory for the responses...
1198 if ((replies
= malloc(sizeof(struct pam_response
) * num_msg
)) == NULL
)
1199 return (PAM_CONV_ERR
);
1202 * Answer all of the messages...
1205 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr
));
1209 * Apparently some versions of HP-UX 11 have a broken pam_unix security
1210 * module. This is a workaround...
1213 client
= auth_client
;
1216 client
= (client_t
*)appdata_ptr
;
1219 for (i
= 0; i
< num_msg
; i
++)
1221 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg
[i
]->msg
));
1223 switch (msg
[i
]->msg_style
)
1225 case PAM_PROMPT_ECHO_ON
:
1226 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
1228 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1229 replies
[i
].resp
= strdup(client
->username
);
1232 case PAM_PROMPT_ECHO_OFF
:
1233 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
1235 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1236 replies
[i
].resp
= strdup(client
->password
);
1240 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
1241 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1242 replies
[i
].resp
= NULL
;
1246 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
1247 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1248 replies
[i
].resp
= NULL
;
1252 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
1253 msg
[i
]->msg_style
));
1255 return (PAM_CONV_ERR
);
1260 * Return the responses back to PAM...
1265 return (PAM_SUCCESS
);
1267 #endif /* HAVE_LIBPAM */
1271 * End of "$Id: auth.c,v 1.41.2.2 2001/05/13 18:38:33 mike Exp $".