]>
git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/auth.c
ff14770293c164ee64dff206568da228b03fe4d6
2 * "$Id: auth.c,v 1.70 2003/04/10 12:57:43 mike Exp $"
4 * Authorization routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2003 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 * GetMD5Passwd() - Get an MD5 password.
43 * IsAuthorized() - Check to see if the user is authorized...
44 * add_allow() - Add an allow mask to the location.
45 * add_deny() - Add a deny mask to the location.
46 * cups_crypt() - Encrypt the password using the DES or MD5
47 * algorithms, as needed.
48 * pam_func() - PAM conversation function.
49 * to64() - Base64-encode an integer value...
53 * Include necessary headers...
62 #endif /* HAVE_SHADOW_H */
65 #endif /* HAVE_CRYPT_H */
67 # ifdef HAVE_PAM_PAM_APPL_H
68 # include <pam/pam_appl.h>
70 # include <security/pam_appl.h>
71 # endif /* HAVE_PAM_PAM_APPL_H */
72 #endif /* HAVE_LIBPAM */
75 #endif /* HAVE_USERSEC_H */
82 static authmask_t
*add_allow(location_t
*loc
);
83 static authmask_t
*add_deny(location_t
*loc
);
85 static char *cups_crypt(const char *pw
, const char *salt
);
86 #endif /* !HAVE_LIBPAM */
88 static int pam_func(int, const struct pam_message
**,
89 struct pam_response
**, void *);
91 static void to64(char *s
, unsigned long v
, int n
);
92 #endif /* HAVE_LIBPAM */
99 #if defined(__hpux) && defined(HAVE_LIBPAM)
100 static client_t
*auth_client
; /* Current client being authenticated */
101 #endif /* __hpux && HAVE_LIBPAM */
105 * 'AddLocation()' - Add a location for authorization.
108 location_t
* /* O - Pointer to new location record */
109 AddLocation(const char *location
) /* I - Location path */
111 location_t
*temp
; /* New location */
115 * Try to allocate memory for the new location.
118 if (NumLocations
== 0)
119 temp
= malloc(sizeof(location_t
));
121 temp
= realloc(Locations
, sizeof(location_t
) * (NumLocations
+ 1));
127 temp
+= NumLocations
;
131 * Initialize the record and copy the name over...
134 memset(temp
, 0, sizeof(location_t
));
135 strlcpy(temp
->location
, location
, sizeof(temp
->location
));
136 temp
->length
= strlen(temp
->location
);
138 LogMessage(L_DEBUG
, "AddLocation: added location \'%s\'", location
);
141 * Return the new record...
149 * 'AddName()' - Add a name to a location...
153 AddName(location_t
*loc
, /* I - Location to add to */
154 char *name
) /* I - Name to add */
156 char **temp
; /* Pointer to names array */
159 if (loc
->num_names
== 0)
160 temp
= malloc(sizeof(char *));
162 temp
= realloc(loc
->names
, (loc
->num_names
+ 1) * sizeof(char *));
166 LogMessage(L_ERROR
, "Unable to add name to location %s: %s", loc
->location
,
173 if ((temp
[loc
->num_names
] = strdup(name
)) == NULL
)
175 LogMessage(L_ERROR
, "Unable to duplicate name for location %s: %s",
176 loc
->location
, strerror(errno
));
185 * 'AllowHost()' - Add a host name that is allowed to access the location.
189 AllowHost(location_t
*loc
, /* I - Location to add to */
190 char *name
) /* I - Name of host or domain to add */
192 authmask_t
*temp
; /* New host/domain mask */
193 char ifname
[32], /* Interface name */
194 *ifptr
; /* Pointer to end of name */
197 if ((temp
= add_allow(loc
)) == NULL
)
200 if (strcasecmp(name
, "@LOCAL") == 0)
203 * Allow *interface*...
206 temp
->type
= AUTH_INTERFACE
;
207 temp
->mask
.name
.name
= strdup("*");
208 temp
->mask
.name
.length
= 1;
210 else if (strncasecmp(name
, "@IF(", 4) == 0)
213 * Allow *interface*...
216 strlcpy(ifname
, name
+ 4, sizeof(ifname
));
218 ifptr
= ifname
+ strlen(ifname
);
220 if (ifptr
[-1] == ')')
226 temp
->type
= AUTH_INTERFACE
;
227 temp
->mask
.name
.name
= strdup(ifname
);
228 temp
->mask
.name
.length
= ifptr
- ifname
;
236 temp
->type
= AUTH_NAME
;
237 temp
->mask
.name
.name
= strdup(name
);
238 temp
->mask
.name
.length
= strlen(name
);
241 LogMessage(L_DEBUG
, "AllowHost: %s allow %s", loc
->location
, name
);
246 * 'AllowIP()' - Add an IP address or network that is allowed to access the
251 AllowIP(location_t
*loc
, /* I - Location to add to */
252 unsigned address
, /* I - IP address to add */
253 unsigned netmask
) /* I - Netmask of address */
255 authmask_t
*temp
; /* New host/domain mask */
258 if ((temp
= add_allow(loc
)) == NULL
)
261 temp
->type
= AUTH_IP
;
262 temp
->mask
.ip
.address
= address
;
263 temp
->mask
.ip
.netmask
= netmask
;
265 LogMessage(L_DEBUG
, "AllowIP: %s allow %08x/%08x", loc
->location
,
271 * 'CheckAuth()' - Check authorization masks.
274 int /* O - 1 if mask matches, 0 otherwise */
275 CheckAuth(unsigned ip
, /* I - Client address */
276 char *name
, /* I - Client hostname */
277 int name_len
, /* I - Length of hostname */
278 int num_masks
, /* I - Number of masks */
279 authmask_t
*masks
) /* I - Masks */
281 cups_netif_t
*iface
; /* Network interface */
282 unsigned netip
; /* Network address */
285 while (num_masks
> 0)
289 case AUTH_INTERFACE
:
291 * Check for a match with a network interface...
296 if (strcmp(masks
->mask
.name
.name
, "*") == 0)
299 * Check against all local interfaces...
304 for (iface
= NetIFList
; iface
!= NULL
; iface
= iface
->next
)
307 * Only check local interfaces...
310 if (!iface
->is_local
)
313 if ((netip
& iface
->mask
.sin_addr
.s_addr
) ==
314 (iface
->address
.sin_addr
.s_addr
&
315 iface
->mask
.sin_addr
.s_addr
))
322 * Check the named interface...
325 if ((iface
= NetIFFind(masks
->mask
.name
.name
)) != NULL
)
327 if ((netip
& iface
->mask
.sin_addr
.s_addr
) ==
328 (iface
->address
.sin_addr
.s_addr
&
329 iface
->mask
.sin_addr
.s_addr
))
337 * Check for exact name match...
340 if (strcasecmp(name
, masks
->mask
.name
.name
) == 0)
344 * Check for domain match...
347 if (name_len
>= masks
->mask
.name
.length
&&
348 masks
->mask
.name
.name
[0] == '.' &&
349 strcasecmp(name
+ name_len
- masks
->mask
.name
.length
,
350 masks
->mask
.name
.name
) == 0)
356 * Check for IP/network address match...
359 if ((ip
& masks
->mask
.ip
.netmask
) == masks
->mask
.ip
.address
)
373 * 'CopyLocation()' - Make a copy of a location...
376 location_t
* /* O - New location */
377 CopyLocation(location_t
**loc
) /* IO - Original location */
379 int i
; /* Looping var */
380 int locindex
; /* Index into Locations array */
381 location_t
*temp
; /* New location */
385 * Add the new location, updating the original location
386 * pointer as needed...
389 locindex
= *loc
- Locations
;
391 if ((temp
= AddLocation((*loc
)->location
)) == NULL
)
394 *loc
= Locations
+ locindex
;
397 * Copy the information from the original location to the new one.
400 temp
->limit
= (*loc
)->limit
;
401 temp
->order_type
= (*loc
)->order_type
;
402 temp
->type
= (*loc
)->type
;
403 temp
->level
= (*loc
)->level
;
404 temp
->satisfy
= (*loc
)->satisfy
;
405 temp
->encryption
= (*loc
)->encryption
;
407 if ((temp
->num_names
= (*loc
)->num_names
) > 0)
410 * Copy the names array...
413 if ((temp
->names
= calloc(temp
->num_names
, sizeof(char *))) == NULL
)
415 LogMessage(L_ERROR
, "CopyLocation: Unable to allocate memory for %d names: %s",
416 temp
->num_names
, strerror(errno
));
421 for (i
= 0; i
< temp
->num_names
; i
++)
422 if ((temp
->names
[i
] = strdup((*loc
)->names
[i
])) == NULL
)
424 LogMessage(L_ERROR
, "CopyLocation: Unable to copy name \"%s\": %s",
425 (*loc
)->names
[i
], strerror(errno
));
432 if ((temp
->num_allow
= (*loc
)->num_allow
) > 0)
435 * Copy allow rules...
438 if ((temp
->allow
= calloc(temp
->num_allow
, sizeof(authmask_t
))) == NULL
)
440 LogMessage(L_ERROR
, "CopyLocation: Unable to allocate memory for %d allow rules: %s",
441 temp
->num_allow
, strerror(errno
));
446 for (i
= 0; i
< temp
->num_allow
; i
++)
447 switch (temp
->allow
[i
].type
= (*loc
)->allow
[i
].type
)
450 temp
->allow
[i
].mask
.name
.length
= (*loc
)->allow
[i
].mask
.name
.length
;
451 temp
->allow
[i
].mask
.name
.name
= strdup((*loc
)->allow
[i
].mask
.name
.name
);
453 if (temp
->allow
[i
].mask
.name
.name
== NULL
)
455 LogMessage(L_ERROR
, "CopyLocation: Unable to copy allow name \"%s\": %s",
456 (*loc
)->allow
[i
].mask
.name
.name
, strerror(errno
));
462 memcpy(&(temp
->allow
[i
].mask
.ip
), &((*loc
)->allow
[i
].mask
.ip
),
468 if ((temp
->num_deny
= (*loc
)->num_deny
) > 0)
474 if ((temp
->deny
= calloc(temp
->num_deny
, sizeof(authmask_t
))) == NULL
)
476 LogMessage(L_ERROR
, "CopyLocation: Unable to allocate memory for %d deny rules: %s",
477 temp
->num_deny
, strerror(errno
));
482 for (i
= 0; i
< temp
->num_deny
; i
++)
483 switch (temp
->deny
[i
].type
= (*loc
)->deny
[i
].type
)
486 temp
->deny
[i
].mask
.name
.length
= (*loc
)->deny
[i
].mask
.name
.length
;
487 temp
->deny
[i
].mask
.name
.name
= strdup((*loc
)->deny
[i
].mask
.name
.name
);
489 if (temp
->deny
[i
].mask
.name
.name
== NULL
)
491 LogMessage(L_ERROR
, "CopyLocation: Unable to copy deny name \"%s\": %s",
492 (*loc
)->deny
[i
].mask
.name
.name
, strerror(errno
));
498 memcpy(&(temp
->deny
[i
].mask
.ip
), &((*loc
)->deny
[i
].mask
.ip
),
509 * 'DeleteAllLocations()' - Free all memory used for location authorization.
513 DeleteAllLocations(void)
515 int i
, j
; /* Looping vars */
516 location_t
*loc
; /* Current location */
517 authmask_t
*mask
; /* Current mask */
521 * Free all of the allow/deny records first...
524 for (i
= NumLocations
, loc
= Locations
; i
> 0; i
--, loc
++)
526 for (j
= loc
->num_names
- 1; j
>= 0; j
--)
529 if (loc
->num_names
> 0)
532 for (j
= loc
->num_allow
, mask
= loc
->allow
; j
> 0; j
--, mask
++)
533 if (mask
->type
== AUTH_NAME
)
534 free(mask
->mask
.name
.name
);
536 if (loc
->num_allow
> 0)
539 for (j
= loc
->num_deny
, mask
= loc
->deny
; j
> 0; j
--, mask
++)
540 if (mask
->type
== AUTH_NAME
)
541 free(mask
->mask
.name
.name
);
543 if (loc
->num_deny
> 0)
548 * Then free the location array...
551 if (NumLocations
> 0)
560 * 'DenyHost()' - Add a host name that is not allowed to access the location.
564 DenyHost(location_t
*loc
, /* I - Location to add to */
565 char *name
) /* I - Name of host or domain to add */
567 authmask_t
*temp
; /* New host/domain mask */
568 char ifname
[32], /* Interface name */
569 *ifptr
; /* Pointer to end of name */
572 if ((temp
= add_deny(loc
)) == NULL
)
575 if (strcasecmp(name
, "@LOCAL") == 0)
578 * Deny *interface*...
581 temp
->type
= AUTH_INTERFACE
;
582 temp
->mask
.name
.name
= strdup("*");
583 temp
->mask
.name
.length
= 1;
585 else if (strncasecmp(name
, "@IF(", 4) == 0)
588 * Deny *interface*...
591 strlcpy(ifname
, name
+ 4, sizeof(ifname
));
593 ifptr
= ifname
+ strlen(ifname
);
595 if (ifptr
[-1] == ')')
601 temp
->type
= AUTH_INTERFACE
;
602 temp
->mask
.name
.name
= strdup(ifname
);
603 temp
->mask
.name
.length
= ifptr
- ifname
;
611 temp
->type
= AUTH_NAME
;
612 temp
->mask
.name
.name
= strdup(name
);
613 temp
->mask
.name
.length
= strlen(name
);
616 LogMessage(L_DEBUG
, "DenyHost: %s deny %s", loc
->location
, name
);
621 * 'DenyIP()' - Add an IP address or network that is not allowed to access
626 DenyIP(location_t
*loc
, /* I - Location to add to */
627 unsigned address
, /* I - IP address to add */
628 unsigned netmask
) /* I - Netmask of address */
630 authmask_t
*temp
; /* New host/domain mask */
633 if ((temp
= add_deny(loc
)) == NULL
)
636 temp
->type
= AUTH_IP
;
637 temp
->mask
.ip
.address
= address
;
638 temp
->mask
.ip
.netmask
= netmask
;
640 LogMessage(L_DEBUG
, "DenyIP: %s deny %08x/%08x\n", loc
->location
,
646 * 'FindBest()' - Find the location entry that best matches the resource.
649 location_t
* /* O - Location that matches */
650 FindBest(const char *path
, /* I - Resource path */
651 http_state_t state
) /* I - HTTP state/request */
653 int i
; /* Looping var */
654 char uri
[HTTP_MAX_URI
],
655 /* URI in request... */
656 *uriptr
; /* Pointer into URI */
657 location_t
*loc
, /* Current location */
658 *best
; /* Best match for location so far */
659 int bestlen
; /* Length of best match */
660 int limit
; /* Limit field */
661 static const int limits
[] = /* Map http_status_t to AUTH_LIMIT_xyz */
681 * First copy the connection URI to a local string so we have drop
682 * any .ppd extension from the pathname in /printers or /classes
686 strlcpy(uri
, path
, sizeof(uri
));
688 if (strncmp(uri
, "/printers/", 10) == 0 ||
689 strncmp(uri
, "/classes/", 9) == 0)
692 * Check if the URI has .ppd on the end...
695 uriptr
= uri
+ strlen(uri
) - 4; /* len > 4 if we get here... */
697 if (strcmp(uriptr
, ".ppd") == 0)
701 LogMessage(L_DEBUG2
, "FindBest: uri = \"%s\"...", uri
);
704 * Loop through the list of locations to find a match...
707 limit
= limits
[state
];
711 for (i
= NumLocations
, loc
= Locations
; i
> 0; i
--, loc
++)
713 LogMessage(L_DEBUG2
, "FindBest: Location %s Limit %x",
714 loc
->location
, loc
->limit
);
716 if (loc
->length
> bestlen
&&
717 strncmp(uri
, loc
->location
, loc
->length
) == 0 &&
718 loc
->location
[0] == '/' &&
719 (limit
& loc
->limit
) != 0)
722 bestlen
= loc
->length
;
727 * Return the match, if any...
730 LogMessage(L_DEBUG2
, "FindBest: best = \"%s\"",
731 best
? best
->location
: "NONE");
738 * 'FindLocation()' - Find the named location.
741 location_t
* /* O - Location that matches */
742 FindLocation(const char *location
) /* I - Connection */
744 int i
; /* Looping var */
748 * Loop through the list of locations to find a match...
751 for (i
= 0; i
< NumLocations
; i
++)
752 if (strcasecmp(Locations
[i
].location
, location
) == 0)
753 return (Locations
+ i
);
760 * 'GetMD5Passwd()' - Get an MD5 password.
763 char * /* O - MD5 password string */
764 GetMD5Passwd(const char *username
, /* I - Username */
765 const char *group
, /* I - Group */
766 char passwd
[33]) /* O - MD5 password string */
768 cups_file_t
*fp
; /* passwd.md5 file */
769 char filename
[1024], /* passwd.md5 filename */
770 line
[256], /* Line from file */
771 tempuser
[33], /* User from file */
772 tempgroup
[33]; /* Group from file */
775 LogMessage(L_DEBUG2
, "GetMD5Passwd(username=\"%s\", group=\"%s\", passwd=%p)",
776 username
, group
? group
: "(null)", passwd
);
778 snprintf(filename
, sizeof(filename
), "%s/passwd.md5", ServerRoot
);
779 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
781 LogMessage(L_ERROR
, "Unable to open %s - %s", filename
, strerror(errno
));
785 while (cupsFileGets(fp
, line
, sizeof(line
)) != NULL
)
787 if (sscanf(line
, "%32[^:]:%32[^:]:%32s", tempuser
, tempgroup
, passwd
) != 3)
789 LogMessage(L_ERROR
, "Bad MD5 password line: %s", line
);
793 if (strcmp(username
, tempuser
) == 0 &&
794 (group
== NULL
|| strcmp(group
, tempgroup
) == 0))
797 * Found the password entry!
800 LogMessage(L_DEBUG2
, "Found MD5 user %s, group %s...", username
,
809 * Didn't find a password entry - return NULL!
818 * 'IsAuthorized()' - Check to see if the user is authorized...
821 http_status_t
/* O - HTTP_OK if authorized or error code */
822 IsAuthorized(client_t
*con
) /* I - Connection */
824 int i
, j
, /* Looping vars */
825 auth
; /* Authorization status */
826 unsigned address
; /* Authorization address */
827 location_t
*best
; /* Best match for location so far */
828 int hostlen
; /* Length of hostname */
829 struct passwd
*pw
; /* User password data */
830 struct group
*grp
; /* Group data */
831 char nonce
[HTTP_MAX_VALUE
],
832 /* Nonce value from client */
833 md5
[33], /* MD5 password */
834 basicmd5
[33]; /* MD5 of Basic password */
836 pam_handle_t
*pamh
; /* PAM authentication handle */
837 int pamerr
; /* PAM error code */
838 struct pam_conv pamdata
; /* PAM conversation data */
839 #elif defined(HAVE_USERSEC_H)
840 char *authmsg
; /* Authentication message */
841 char *loginmsg
; /* Login message */
842 int reenter
; /* ??? */
844 char *pass
; /* Encrypted password */
845 # ifdef HAVE_SHADOW_H
846 struct spwd
*spw
; /* Shadow password data */
847 # endif /* HAVE_SHADOW_H */
848 #endif /* HAVE_LIBPAM */
849 static const char * const states
[] = /* HTTP client states... */
868 LogMessage(L_DEBUG2
, "IsAuthorized: con->uri = \"%s\"", con
->uri
);
871 * Find a matching location; if there is no match then access is
875 if ((best
= FindBest(con
->uri
, con
->http
.state
)) == NULL
)
876 return (HTTP_FORBIDDEN
);
879 * Check host/ip-based accesses...
882 address
= ntohl(con
->http
.hostaddr
.sin_addr
.s_addr
);
883 hostlen
= strlen(con
->http
.hostname
);
885 if (address
== 0x7f000001 || strcasecmp(con
->http
.hostname
, "localhost") == 0)
888 * Access from localhost (127.0.0.1) is always allowed...
893 else if (best
->num_allow
== 0 && best
->num_deny
== 0)
896 * No allow/deny lines - allow access...
904 * Do authorization checks on the domain/address...
907 switch (best
->order_type
)
910 auth
= AUTH_DENY
; /* anti-compiler-warning-code */
913 case AUTH_ALLOW
: /* Order Deny,Allow */
916 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
917 best
->num_deny
, best
->deny
))
920 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
921 best
->num_allow
, best
->allow
))
925 case AUTH_DENY
: /* Order Allow,Deny */
928 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
929 best
->num_allow
, best
->allow
))
932 if (CheckAuth(address
, con
->http
.hostname
, hostlen
,
933 best
->num_deny
, best
->deny
))
939 LogMessage(L_DEBUG2
, "IsAuthorized: auth = %d, satisfy=%d...",
940 auth
, best
->satisfy
);
942 if (auth
== AUTH_DENY
&& best
->satisfy
== AUTH_SATISFY_ALL
)
943 return (HTTP_FORBIDDEN
);
947 * See if encryption is required...
950 if (best
->encryption
>= HTTP_ENCRYPT_REQUIRED
&& !con
->http
.tls
)
952 LogMessage(L_DEBUG2
, "IsAuthorized: Need upgrade to TLS...");
953 return (HTTP_UPGRADE_REQUIRED
);
955 #endif /* HAVE_SSL */
958 * Now see what access level is required...
961 if (best
->level
== AUTH_ANON
) /* Anonymous access - allow it */
964 LogMessage(L_DEBUG2
, "IsAuthorized: username = \"%s\" password = %d chars",
965 con
->username
, (int)strlen(con
->password
));
966 DEBUG_printf(("IsAuthorized: username = \"%s\", password = \"%s\"\n",
967 con
->username
, con
->password
));
969 if (con
->username
[0] == '\0')
971 if (best
->satisfy
== AUTH_SATISFY_ALL
|| auth
== AUTH_DENY
)
972 return (HTTP_UNAUTHORIZED
); /* Non-anonymous needs user/pass */
974 return (HTTP_OK
); /* unless overridden with Satisfy */
978 * Check the user's password...
981 LogMessage(L_DEBUG2
, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
982 con
->username
, address
, con
->http
.hostname
);
986 if ((address
!= 0x7f000001 &&
987 strcasecmp(con
->http
.hostname
, "localhost") != 0) ||
988 strncmp(con
->http
.fields
[HTTP_FIELD_AUTHORIZATION
], "Local", 5) != 0)
991 * Not doing local certificate-based authentication; check the password...
994 if (!con
->password
[0])
995 return (HTTP_UNAUTHORIZED
);
998 * See what kind of authentication we are doing...
1005 * Get the user info...
1008 pw
= getpwnam(con
->username
); /* Get the current password */
1009 endpwent(); /* Close the password file */
1013 * Only use PAM to do authentication. This allows MD5 passwords, among
1017 pamdata
.conv
= pam_func
;
1018 pamdata
.appdata_ptr
= con
;
1022 * Workaround for HP-UX bug in pam_unix; see pam_conv() below for
1027 # endif /* __hpux */
1029 DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con
));
1031 pamerr
= pam_start("cups", con
->username
, &pamdata
, &pamh
);
1032 if (pamerr
!= PAM_SUCCESS
)
1034 LogMessage(L_ERROR
, "IsAuthorized: pam_start() returned %d (%s)!\n",
1035 pamerr
, pam_strerror(pamh
, pamerr
));
1037 return (HTTP_UNAUTHORIZED
);
1040 pamerr
= pam_authenticate(pamh
, PAM_SILENT
);
1041 if (pamerr
!= PAM_SUCCESS
)
1043 LogMessage(L_ERROR
, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
1044 pamerr
, pam_strerror(pamh
, pamerr
));
1046 return (HTTP_UNAUTHORIZED
);
1049 pamerr
= pam_acct_mgmt(pamh
, PAM_SILENT
);
1050 if (pamerr
!= PAM_SUCCESS
)
1052 LogMessage(L_ERROR
, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
1053 pamerr
, pam_strerror(pamh
, pamerr
));
1055 return (HTTP_UNAUTHORIZED
);
1058 pam_end(pamh
, PAM_SUCCESS
);
1059 #elif defined(HAVE_USERSEC_H)
1061 * Use AIX authentication interface...
1064 LogMessage(L_DEBUG
, "IsAuthorized: AIX authenticate of username \"%s\"",
1068 if (authenticate(con
->username
, con
->password
, &reenter
, &authmsg
) != 0)
1070 LogMessage(L_DEBUG
, "IsAuthorized: Unable to authenticate username \"%s\": %s",
1071 con
->username
, strerror(errno
));
1072 return (HTTP_UNAUTHORIZED
);
1076 * Use normal UNIX password file-based authentication...
1079 if (pw
== NULL
) /* No such user... */
1081 LogMessage(L_WARN
, "IsAuthorized: Unknown username \"%s\"; access denied.",
1083 return (HTTP_UNAUTHORIZED
);
1086 # ifdef HAVE_SHADOW_H
1087 spw
= getspnam(con
->username
);
1090 if (spw
== NULL
&& strcmp(pw
->pw_passwd
, "x") == 0)
1091 { /* Don't allow blank passwords! */
1092 LogMessage(L_WARN
, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
1094 return (HTTP_UNAUTHORIZED
); /* No such user or bad shadow file */
1099 printf("spw->sp_pwdp = \"%s\"\n", spw
->sp_pwdp
);
1104 if (spw
!= NULL
&& spw
->sp_pwdp
[0] == '\0' && pw
->pw_passwd
[0] == '\0')
1106 if (pw
->pw_passwd
[0] == '\0')
1107 # endif /* HAVE_SHADOW_H */
1108 { /* Don't allow blank passwords! */
1109 LogMessage(L_WARN
, "IsAuthorized: Username \"%s\" has no password; access denied.",
1111 return (HTTP_UNAUTHORIZED
);
1115 * OK, the password isn't blank, so compare with what came from the client...
1118 pass
= cups_crypt(con
->password
, pw
->pw_passwd
);
1120 LogMessage(L_DEBUG2
, "IsAuthorized: pw_passwd = %s, crypt = %s",
1121 pw
->pw_passwd
, pass
);
1123 if (pass
== NULL
|| strcmp(pw
->pw_passwd
, pass
) != 0)
1125 # ifdef HAVE_SHADOW_H
1128 pass
= cups_crypt(con
->password
, spw
->sp_pwdp
);
1130 LogMessage(L_DEBUG2
, "IsAuthorized: sp_pwdp = %s, crypt = %s",
1131 spw
->sp_pwdp
, pass
);
1133 if (pass
== NULL
|| strcmp(spw
->sp_pwdp
, pass
) != 0)
1134 return (HTTP_UNAUTHORIZED
);
1137 # endif /* HAVE_SHADOW_H */
1138 return (HTTP_UNAUTHORIZED
);
1140 #endif /* HAVE_LIBPAM */
1145 * Do Digest authentication...
1148 if (!httpGetSubField(&(con
->http
), HTTP_FIELD_AUTHORIZATION
, "nonce",
1151 LogMessage(L_ERROR
, "IsAuthorized: No nonce value for Digest authentication!");
1152 return (HTTP_UNAUTHORIZED
);
1155 if (strcmp(con
->http
.hostname
, nonce
) != 0)
1157 LogMessage(L_ERROR
, "IsAuthorized: Nonce value error!");
1158 LogMessage(L_ERROR
, "IsAuthorized: Expected \"%s\",",
1159 con
->http
.hostname
);
1160 LogMessage(L_ERROR
, "IsAuthorized: Got \"%s\"!", nonce
);
1161 return (HTTP_UNAUTHORIZED
);
1164 LogMessage(L_DEBUG2
, "IsAuthorized: nonce = \"%s\"", nonce
);
1166 if (best
->num_names
&& best
->level
== AUTH_GROUP
)
1168 LogMessage(L_DEBUG2
, "IsAuthorized: num_names = %d", best
->num_names
);
1170 for (i
= 0; i
< best
->num_names
; i
++)
1171 if (GetMD5Passwd(con
->username
, best
->names
[i
], md5
))
1174 if (i
>= best
->num_names
)
1177 else if (!GetMD5Passwd(con
->username
, NULL
, md5
))
1183 LogMessage(L_ERROR
, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
1185 return (HTTP_UNAUTHORIZED
);
1188 httpMD5Final(nonce
, states
[con
->http
.state
], con
->uri
, md5
);
1190 if (strcmp(md5
, con
->password
) != 0)
1192 LogMessage(L_ERROR
, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
1193 md5
, con
->password
);
1194 return (HTTP_UNAUTHORIZED
);
1198 case AUTH_BASICDIGEST
:
1200 * Do Basic authentication with the Digest password file...
1203 if (best
->num_names
&& best
->level
== AUTH_GROUP
)
1205 LogMessage(L_DEBUG2
, "IsAuthorized: num_names = %d", best
->num_names
);
1207 for (i
= 0; i
< best
->num_names
; i
++)
1208 if (GetMD5Passwd(con
->username
, best
->names
[i
], md5
))
1211 if (i
>= best
->num_names
)
1214 else if (!GetMD5Passwd(con
->username
, NULL
, md5
))
1219 LogMessage(L_ERROR
, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
1221 return (HTTP_UNAUTHORIZED
);
1224 httpMD5(con
->username
, "CUPS", con
->password
, basicmd5
);
1226 if (strcmp(md5
, basicmd5
) != 0)
1228 LogMessage(L_ERROR
, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
1230 return (HTTP_UNAUTHORIZED
);
1238 * Get password entry for certificate-based auth...
1241 pw
= getpwnam(con
->username
); /* Get the current password */
1242 endpwent(); /* Close the password file */
1246 * OK, the password is good. See if we need normal user access, or group
1247 * access... (root always matches)
1250 if (strcmp(con
->username
, "root") == 0)
1253 if (best
->level
== AUTH_USER
)
1256 * If there are no names associated with this location, then
1257 * any valid user is OK...
1260 LogMessage(L_DEBUG2
, "IsAuthorized: Checking user membership...");
1262 if (best
->num_names
== 0)
1266 * Otherwise check the user list and return OK if this user is
1270 for (i
= 0; i
< best
->num_names
; i
++)
1271 if (strcmp(con
->username
, best
->names
[i
]) == 0)
1274 return (HTTP_UNAUTHORIZED
);
1277 if (best
->type
== AUTH_BASIC
)
1280 * Check to see if this user is in any of the named groups...
1283 LogMessage(L_DEBUG2
, "IsAuthorized: Checking group membership...");
1285 for (i
= 0; i
< best
->num_names
; i
++)
1287 grp
= getgrnam(best
->names
[i
]);
1290 if (grp
== NULL
) /* No group by that name??? */
1292 LogMessage(L_WARN
, "IsAuthorized: group name \"%s\" does not exist!",
1294 return (HTTP_FORBIDDEN
);
1297 for (j
= 0; grp
->gr_mem
[j
] != NULL
; j
++)
1298 if (strcmp(con
->username
, grp
->gr_mem
[j
]) == 0)
1302 * Check to see if the default group ID matches for the user...
1305 if (pw
!= NULL
&& grp
->gr_gid
== pw
->pw_gid
)
1310 * The user isn't part of the specified group, so deny access...
1313 LogMessage(L_DEBUG2
, "IsAuthorized: user not in group!");
1315 return (HTTP_UNAUTHORIZED
);
1319 * All checks passed...
1327 * 'add_allow()' - Add an allow mask to the location.
1330 static authmask_t
* /* O - New mask record */
1331 add_allow(location_t
*loc
) /* I - Location to add to */
1333 authmask_t
*temp
; /* New mask record */
1344 * Try to allocate memory for the record...
1347 if (loc
->num_allow
== 0)
1348 temp
= malloc(sizeof(authmask_t
));
1350 temp
= realloc(loc
->allow
, sizeof(authmask_t
) * (loc
->num_allow
+ 1));
1356 temp
+= loc
->num_allow
;
1360 * Clear the mask record and return...
1363 memset(temp
, 0, sizeof(authmask_t
));
1369 * 'add_deny()' - Add a deny mask to the location.
1372 static authmask_t
* /* O - New mask record */
1373 add_deny(location_t
*loc
) /* I - Location to add to */
1375 authmask_t
*temp
; /* New mask record */
1386 * Try to allocate memory for the record...
1389 if (loc
->num_deny
== 0)
1390 temp
= malloc(sizeof(authmask_t
));
1392 temp
= realloc(loc
->deny
, sizeof(authmask_t
) * (loc
->num_deny
+ 1));
1398 temp
+= loc
->num_deny
;
1402 * Clear the mask record and return...
1405 memset(temp
, 0, sizeof(authmask_t
));
1412 * 'cups_crypt()' - Encrypt the password using the DES or MD5 algorithms,
1416 static char * /* O - Encrypted password */
1417 cups_crypt(const char *pw
, /* I - Password string */
1418 const char *salt
) /* I - Salt (key) string */
1420 if (strncmp(salt
, "$1$", 3) == 0)
1423 * Use MD5 passwords without the benefit of PAM; this is for
1424 * Slackware Linux, and the algorithm was taken from the
1425 * old shadow-19990827/lib/md5crypt.c source code... :(
1428 int i
; /* Looping var */
1429 unsigned long n
; /* Output number */
1430 int pwlen
; /* Length of password string */
1431 const char *salt_end
; /* End of "salt" data for MD5 */
1432 char *ptr
; /* Pointer into result string */
1433 md5_state_t state
; /* Primary MD5 state info */
1434 md5_state_t state2
; /* Secondary MD5 state info */
1435 md5_byte_t digest
[16]; /* MD5 digest result */
1436 static char result
[120]; /* Final password string */
1440 * Get the salt data between dollar signs, e.g. $1$saltdata$md5.
1441 * Get a maximum of 8 characters of salt data after $1$...
1444 for (salt_end
= salt
+ 3; *salt_end
&& (salt_end
- salt
) < 11; salt_end
++)
1445 if (*salt_end
== '$')
1449 * Compute the MD5 sum we need...
1455 md5_append(&state
, (md5_byte_t
*)pw
, pwlen
);
1456 md5_append(&state
, (md5_byte_t
*)salt
, salt_end
- salt
);
1459 md5_append(&state2
, (md5_byte_t
*)pw
, pwlen
);
1460 md5_append(&state2
, (md5_byte_t
*)salt
+ 3, salt_end
- salt
- 3);
1461 md5_append(&state2
, (md5_byte_t
*)pw
, pwlen
);
1462 md5_finish(&state2
, digest
);
1464 for (i
= pwlen
; i
> 0; i
-= 16)
1465 md5_append(&state
, digest
, i
> 16 ? 16 : i
);
1467 for (i
= pwlen
; i
> 0; i
>>= 1)
1468 md5_append(&state
, (md5_byte_t
*)((i
& 1) ? "" : pw
), 1);
1470 md5_finish(&state
, digest
);
1472 for (i
= 0; i
< 1000; i
++)
1477 md5_append(&state
, (md5_byte_t
*)pw
, pwlen
);
1479 md5_append(&state
, digest
, 16);
1482 md5_append(&state
, (md5_byte_t
*)salt
+ 3, salt_end
- salt
- 3);
1485 md5_append(&state
, (md5_byte_t
*)pw
, pwlen
);
1488 md5_append(&state
, digest
, 16);
1490 md5_append(&state
, (md5_byte_t
*)pw
, pwlen
);
1492 md5_finish(&state
, digest
);
1496 * Copy the final sum to the result string and return...
1499 memcpy(result
, salt
, salt_end
- salt
);
1500 ptr
= result
+ (salt_end
- salt
);
1503 for (i
= 0; i
< 5; i
++, ptr
+= 4)
1505 n
= (((digest
[i
] << 8) | digest
[i
+ 6]) << 8);
1508 n
|= digest
[i
+ 12];
1515 to64(ptr
, digest
[11], 2);
1524 * Use the standard crypt() function...
1527 return (crypt(pw
, salt
));
1530 #endif /* !HAVE_LIBPAM */
1535 * 'pam_func()' - PAM conversation function.
1538 static int /* O - Success or failure */
1539 pam_func(int num_msg
, /* I - Number of messages */
1540 const struct pam_message
**msg
, /* I - Messages */
1541 struct pam_response
**resp
, /* O - Responses */
1542 void *appdata_ptr
) /* I - Pointer to connection */
1544 int i
; /* Looping var */
1545 struct pam_response
*replies
; /* Replies */
1546 client_t
*client
; /* Pointer client connection */
1550 * Allocate memory for the responses...
1553 if ((replies
= malloc(sizeof(struct pam_response
) * num_msg
)) == NULL
)
1554 return (PAM_CONV_ERR
);
1557 * Answer all of the messages...
1560 DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr
));
1564 * Apparently some versions of HP-UX 11 have a broken pam_unix security
1565 * module. This is a workaround...
1568 client
= auth_client
;
1571 client
= (client_t
*)appdata_ptr
;
1574 for (i
= 0; i
< num_msg
; i
++)
1576 DEBUG_printf(("pam_func: Message = \"%s\"\n", msg
[i
]->msg
));
1578 switch (msg
[i
]->msg_style
)
1580 case PAM_PROMPT_ECHO_ON
:
1581 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
1583 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1584 replies
[i
].resp
= strdup(client
->username
);
1587 case PAM_PROMPT_ECHO_OFF
:
1588 DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
1590 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1591 replies
[i
].resp
= strdup(client
->password
);
1595 DEBUG_puts("pam_func: PAM_TEXT_INFO...");
1596 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1597 replies
[i
].resp
= NULL
;
1601 DEBUG_puts("pam_func: PAM_ERROR_MSG...");
1602 replies
[i
].resp_retcode
= PAM_SUCCESS
;
1603 replies
[i
].resp
= NULL
;
1607 DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
1608 msg
[i
]->msg_style
));
1610 return (PAM_CONV_ERR
);
1615 * Return the responses back to PAM...
1620 return (PAM_SUCCESS
);
1626 * 'to64()' - Base64-encode an integer value...
1630 to64(char *s
, /* O - Output string */
1631 unsigned long v
, /* I - Value to encode */
1632 int n
) /* I - Number of digits */
1634 const char *itoa64
= "./0123456789"
1635 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1636 "abcdefghijklmnopqrstuvwxyz";
1639 for (; n
> 0; n
--, v
>>= 6)
1640 *s
++ = itoa64
[v
& 0x3f];
1642 #endif /* HAVE_LIBPAM */
1646 * End of "$Id: auth.c,v 1.70 2003/04/10 12:57:43 mike Exp $".