#include "cupsd.h"
#include <pwd.h>
#include <grp.h>
#include <cups/md5.h>
#ifdef HAVE_SHADOW_H
# include <shadow.h>
#endif
#ifdef HAVE_CRYPT_H
# include <crypt.h>
#endif
#if HAVE_LIBPAM
# ifdef HAVE_PAM_PAM_APPL_H
# include <pam/pam_appl.h>
# else
# include <security/pam_appl.h>
# endif
#endif
#ifdef HAVE_USERSEC_H
# include <usersec.h>
#endif
static authmask_t *add_allow(location_t *loc);
static authmask_t *add_deny(location_t *loc);
#if !HAVE_LIBPAM
static char *cups_crypt(const char *pw, const char *salt);
#endif
static char *get_md5_passwd(const char *username, const char *group,
char passwd[33]);
#if HAVE_LIBPAM
static int pam_func(int, const struct pam_message **,
struct pam_response **, void *);
#else
static void to64(char *s, unsigned long v, int n);
#endif
#ifdef __hpux
static client_t *auth_client;
#endif
location_t *
AddLocation(const char *location)
{
location_t *temp;
if (NumLocations == 0)
temp = malloc(sizeof(location_t));
else
temp = realloc(Locations, sizeof(location_t) * (NumLocations + 1));
if (temp == NULL)
return (NULL);
Locations = temp;
temp += NumLocations;
NumLocations ++;
memset(temp, 0, sizeof(location_t));
strlcpy(temp->location, location, sizeof(temp->location));
temp->length = strlen(temp->location);
LogMessage(L_DEBUG, "AddLocation: added location \'%s\'", location);
return (temp);
}
void
AddName(location_t *loc,
char *name)
{
char **temp;
if (loc->num_names == 0)
temp = malloc(sizeof(char *));
else
temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *));
if (temp == NULL)
{
LogMessage(L_ERROR, "Unable to add name to location %s: %s", loc->location,
strerror(errno));
return;
}
loc->names = temp;
if ((temp[loc->num_names] = strdup(name)) == NULL)
{
LogMessage(L_ERROR, "Unable to duplicate name for location %s: %s",
loc->location, strerror(errno));
return;
}
loc->num_names ++;
}
void
AllowHost(location_t *loc,
char *name)
{
authmask_t *temp;
char ifname[32],
*ifptr;
if ((temp = add_allow(loc)) == NULL)
return;
if (strcasecmp(name, "@LOCAL") == 0)
{
temp->type = AUTH_INTERFACE;
temp->mask.name.name = strdup("*");
temp->mask.name.length = 1;
}
else if (strncasecmp(name, "@IF(", 4) == 0)
{
strlcpy(ifname, name + 4, sizeof(ifname));
ifptr = ifname + strlen(ifname);
if (ifptr[-1] == ')')
{
ifptr --;
*ifptr = '\0';
}
temp->type = AUTH_INTERFACE;
temp->mask.name.name = strdup(ifname);
temp->mask.name.length = ifptr - ifname;
}
else
{
temp->type = AUTH_NAME;
temp->mask.name.name = strdup(name);
temp->mask.name.length = strlen(name);
}
LogMessage(L_DEBUG, "AllowHost: %s allow %s", loc->location, name);
}
void
AllowIP(location_t *loc,
unsigned address,
unsigned netmask)
{
authmask_t *temp;
if ((temp = add_allow(loc)) == NULL)
return;
temp->type = AUTH_IP;
temp->mask.ip.address = address;
temp->mask.ip.netmask = netmask;
LogMessage(L_DEBUG, "AllowIP: %s allow %08x/%08x", loc->location,
address, netmask);
}
int
CheckAuth(unsigned ip,
char *name,
int name_len,
int num_masks,
authmask_t *masks)
{
cups_netif_t *iface;
unsigned netip;
while (num_masks > 0)
{
switch (masks->type)
{
case AUTH_INTERFACE :
netip = htonl(ip);
if (strcmp(masks->mask.name.name, "*") == 0)
{
NetIFUpdate();
for (iface = NetIFList; iface != NULL; iface = iface->next)
{
if (!iface->is_local)
continue;
if ((netip & iface->mask.sin_addr.s_addr) ==
(iface->address.sin_addr.s_addr &
iface->mask.sin_addr.s_addr))
return (1);
}
}
else
{
if ((iface = NetIFFind(masks->mask.name.name)) != NULL)
{
if ((netip & iface->mask.sin_addr.s_addr) ==
(iface->address.sin_addr.s_addr &
iface->mask.sin_addr.s_addr))
return (1);
}
}
break;
case AUTH_NAME :
if (strcasecmp(name, masks->mask.name.name) == 0)
return (1);
if (name_len >= masks->mask.name.length &&
masks->mask.name.name[0] == '.' &&
strcasecmp(name + name_len - masks->mask.name.length,
masks->mask.name.name) == 0)
return (1);
break;
case AUTH_IP :
if ((ip & masks->mask.ip.netmask) == masks->mask.ip.address)
return (1);
break;
}
masks ++;
num_masks --;
}
return (0);
}
location_t *
CopyLocation(location_t **loc)
{
int i;
int locindex;
location_t *temp;
locindex = *loc - Locations;
if ((temp = AddLocation((*loc)->location)) == NULL)
return (NULL);
*loc = Locations + locindex;
temp->limit = (*loc)->limit;
temp->order_type = (*loc)->order_type;
temp->type = (*loc)->type;
temp->level = (*loc)->level;
temp->satisfy = (*loc)->satisfy;
temp->encryption = (*loc)->encryption;
if ((temp->num_names = (*loc)->num_names) > 0)
{
if ((temp->names = calloc(temp->num_names, sizeof(char *))) == NULL)
{
LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d names: %s",
temp->num_names, strerror(errno));
NumLocations --;
return (NULL);
}
for (i = 0; i < temp->num_names; i ++)
if ((temp->names[i] = strdup((*loc)->names[i])) == NULL)
{
LogMessage(L_ERROR, "CopyLocation: Unable to copy name \"%s\": %s",
(*loc)->names[i], strerror(errno));
NumLocations --;
return (NULL);
}
}
if ((temp->num_allow = (*loc)->num_allow) > 0)
{
if ((temp->allow = calloc(temp->num_allow, sizeof(authmask_t))) == NULL)
{
LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d allow rules: %s",
temp->num_allow, strerror(errno));
NumLocations --;
return (NULL);
}
for (i = 0; i < temp->num_allow; i ++)
switch (temp->allow[i].type = (*loc)->allow[i].type)
{
case AUTH_NAME :
temp->allow[i].mask.name.length = (*loc)->allow[i].mask.name.length;
temp->allow[i].mask.name.name = strdup((*loc)->allow[i].mask.name.name);
if (temp->allow[i].mask.name.name == NULL)
{
LogMessage(L_ERROR, "CopyLocation: Unable to copy allow name \"%s\": %s",
(*loc)->allow[i].mask.name.name, strerror(errno));
NumLocations --;
return (NULL);
}
break;
case AUTH_IP :
memcpy(&(temp->allow[i].mask.ip), &((*loc)->allow[i].mask.ip),
sizeof(ipmask_t));
break;
}
}
if ((temp->num_deny = (*loc)->num_deny) > 0)
{
if ((temp->deny = calloc(temp->num_deny, sizeof(authmask_t))) == NULL)
{
LogMessage(L_ERROR, "CopyLocation: Unable to allocate memory for %d deny rules: %s",
temp->num_deny, strerror(errno));
NumLocations --;
return (NULL);
}
for (i = 0; i < temp->num_deny; i ++)
switch (temp->deny[i].type = (*loc)->deny[i].type)
{
case AUTH_NAME :
temp->deny[i].mask.name.length = (*loc)->deny[i].mask.name.length;
temp->deny[i].mask.name.name = strdup((*loc)->deny[i].mask.name.name);
if (temp->deny[i].mask.name.name == NULL)
{
LogMessage(L_ERROR, "CopyLocation: Unable to copy deny name \"%s\": %s",
(*loc)->deny[i].mask.name.name, strerror(errno));
NumLocations --;
return (NULL);
}
break;
case AUTH_IP :
memcpy(&(temp->deny[i].mask.ip), &((*loc)->deny[i].mask.ip),
sizeof(ipmask_t));
break;
}
}
return (temp);
}
void
DeleteAllLocations(void)
{
int i, j;
location_t *loc;
authmask_t *mask;
for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
{
for (j = loc->num_names - 1; j >= 0; j --)
free(loc->names[j]);
if (loc->num_names > 0)
free(loc->names);
for (j = loc->num_allow, mask = loc->allow; j > 0; j --, mask ++)
if (mask->type == AUTH_NAME)
free(mask->mask.name.name);
if (loc->num_allow > 0)
free(loc->allow);
for (j = loc->num_deny, mask = loc->deny; j > 0; j --, mask ++)
if (mask->type == AUTH_NAME)
free(mask->mask.name.name);
if (loc->num_deny > 0)
free(loc->deny);
}
if (NumLocations > 0)
free(Locations);
Locations = NULL;
NumLocations = 0;
}
void
DenyHost(location_t *loc,
char *name)
{
authmask_t *temp;
char ifname[32],
*ifptr;
if ((temp = add_deny(loc)) == NULL)
return;
if (strcasecmp(name, "@LOCAL") == 0)
{
temp->type = AUTH_INTERFACE;
temp->mask.name.name = strdup("*");
temp->mask.name.length = 1;
}
else if (strncasecmp(name, "@IF(", 4) == 0)
{
strlcpy(ifname, name + 4, sizeof(ifname));
ifptr = ifname + strlen(ifname);
if (ifptr[-1] == ')')
{
ifptr --;
*ifptr = '\0';
}
temp->type = AUTH_INTERFACE;
temp->mask.name.name = strdup(ifname);
temp->mask.name.length = ifptr - ifname;
}
else
{
temp->type = AUTH_NAME;
temp->mask.name.name = strdup(name);
temp->mask.name.length = strlen(name);
}
LogMessage(L_DEBUG, "DenyHost: %s deny %s", loc->location, name);
}
void
DenyIP(location_t *loc,
unsigned address,
unsigned netmask)
{
authmask_t *temp;
if ((temp = add_deny(loc)) == NULL)
return;
temp->type = AUTH_IP;
temp->mask.ip.address = address;
temp->mask.ip.netmask = netmask;
LogMessage(L_DEBUG, "DenyIP: %s deny %08x/%08x\n", loc->location,
address, netmask);
}
location_t *
FindBest(const char *path,
http_state_t state)
{
int i;
char uri[HTTP_MAX_URI],
*uriptr;
location_t *loc,
*best;
int bestlen;
int limit;
static int limits[] =
{
AUTH_LIMIT_ALL,
AUTH_LIMIT_OPTIONS,
AUTH_LIMIT_GET,
AUTH_LIMIT_GET,
AUTH_LIMIT_HEAD,
AUTH_LIMIT_POST,
AUTH_LIMIT_POST,
AUTH_LIMIT_POST,
AUTH_LIMIT_PUT,
AUTH_LIMIT_PUT,
AUTH_LIMIT_DELETE,
AUTH_LIMIT_TRACE,
AUTH_LIMIT_ALL,
AUTH_LIMIT_ALL
};
strlcpy(uri, path, sizeof(uri));
if (strncmp(uri, "/printers/", 10) == 0 ||
strncmp(uri, "/classes/", 9) == 0)
{
uriptr = uri + strlen(uri) - 4;
if (strcmp(uriptr, ".ppd") == 0)
*uriptr = '\0';
}
LogMessage(L_DEBUG2, "FindBest: uri = \"%s\"...", uri);
limit = limits[state];
best = NULL;
bestlen = 0;
for (i = NumLocations, loc = Locations; i > 0; i --, loc ++)
{
LogMessage(L_DEBUG2, "FindBest: Location %s Limit %x",
loc->location, loc->limit);
if (loc->length > bestlen &&
strncmp(uri, loc->location, loc->length) == 0 &&
loc->location[0] == '/' &&
(limit & loc->limit) != 0)
{
best = loc;
bestlen = loc->length;
}
}
LogMessage(L_DEBUG2, "FindBest: best = \"%s\"",
best ? best->location : "NONE");
return (best);
}
location_t *
FindLocation(const char *location)
{
int i;
for (i = 0; i < NumLocations; i ++)
if (strcasecmp(Locations[i].location, location) == 0)
return (Locations + i);
return (NULL);
}
http_status_t
IsAuthorized(client_t *con)
{
int i, j,
auth;
unsigned address;
location_t *best;
int hostlen;
struct passwd *pw;
struct group *grp;
char nonce[HTTP_MAX_VALUE],
md5[33],
basicmd5[33];
#if HAVE_LIBPAM
pam_handle_t *pamh;
int pamerr;
struct pam_conv pamdata;
#elif defined(HAVE_USERSEC_H)
char *authmsg;
char *loginmsg;
int reenter;
#else
char *pass;
# ifdef HAVE_SHADOW_H
struct spwd *spw;
# endif
#endif
static const char *states[] =
{
"WAITING",
"OPTIONS",
"GET",
"GET",
"HEAD",
"POST",
"POST",
"POST",
"PUT",
"PUT",
"DELETE",
"TRACE",
"CLOSE",
"STATUS"
};
LogMessage(L_DEBUG2, "IsAuthorized: con->uri = \"%s\"", con->uri);
if ((best = FindBest(con->uri, con->http.state)) == NULL)
return (HTTP_FORBIDDEN);
address = ntohl(con->http.hostaddr.sin_addr.s_addr);
hostlen = strlen(con->http.hostname);
if (address == 0x7f000001 || strcasecmp(con->http.hostname, "localhost") == 0)
{
auth = AUTH_ALLOW;
}
else if (best->num_allow == 0 && best->num_deny == 0)
{
auth = AUTH_ALLOW;
}
else
{
switch (best->order_type)
{
default :
auth = AUTH_DENY;
break;
case AUTH_ALLOW :
auth = AUTH_ALLOW;
if (CheckAuth(address, con->http.hostname, hostlen,
best->num_deny, best->deny))
auth = AUTH_DENY;
if (CheckAuth(address, con->http.hostname, hostlen,
best->num_allow, best->allow))
auth = AUTH_ALLOW;
break;
case AUTH_DENY :
auth = AUTH_DENY;
if (CheckAuth(address, con->http.hostname, hostlen,
best->num_allow, best->allow))
auth = AUTH_ALLOW;
if (CheckAuth(address, con->http.hostname, hostlen,
best->num_deny, best->deny))
auth = AUTH_DENY;
break;
}
}
LogMessage(L_DEBUG2, "IsAuthorized: auth = %d, satisfy=%d...",
auth, best->satisfy);
if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL)
return (HTTP_FORBIDDEN);
#ifdef HAVE_LIBSSL
if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls)
{
LogMessage(L_DEBUG2, "IsAuthorized: Need upgrade to TLS...");
return (HTTP_UPGRADE_REQUIRED);
}
#endif
if (best->level == AUTH_ANON)
return (HTTP_OK);
LogMessage(L_DEBUG2, "IsAuthorized: username = \"%s\" password = %d chars",
con->username, strlen(con->password));
DEBUG_printf(("IsAuthorized: username = \"%s\", password = \"%s\"\n",
con->username, con->password));
if (con->username[0] == '\0')
{
if (best->satisfy == AUTH_SATISFY_ALL || auth == AUTH_DENY)
return (HTTP_UNAUTHORIZED);
else
return (HTTP_OK);
}
LogMessage(L_DEBUG2, "IsAuthorized: Checking \"%s\", address = %08x, hostname = \"%s\"",
con->username, address, con->http.hostname);
pw = NULL;
if ((address != 0x7f000001 &&
strcasecmp(con->http.hostname, "localhost") != 0) ||
strncmp(con->http.fields[HTTP_FIELD_AUTHORIZATION], "Local", 5) != 0)
{
if (!con->password[0])
return (HTTP_UNAUTHORIZED);
switch (best->type)
{
case AUTH_BASIC :
pw = getpwnam(con->username);
endpwent();
if (pw == NULL)
{
LogMessage(L_WARN, "IsAuthorized: Unknown username \"%s\"; access denied.",
con->username);
return (HTTP_UNAUTHORIZED);
}
#if HAVE_LIBPAM
pamdata.conv = pam_func;
pamdata.appdata_ptr = con;
# ifdef __hpux
auth_client = con;
# endif
DEBUG_printf(("IsAuthorized: Setting appdata_ptr = %p\n", con));
pamerr = pam_start("cups", con->username, &pamdata, &pamh);
if (pamerr != PAM_SUCCESS)
{
LogMessage(L_ERROR, "IsAuthorized: pam_start() returned %d (%s)!\n",
pamerr, pam_strerror(pamh, pamerr));
pam_end(pamh, 0);
return (HTTP_UNAUTHORIZED);
}
pamerr = pam_authenticate(pamh, PAM_SILENT);
if (pamerr != PAM_SUCCESS)
{
LogMessage(L_ERROR, "IsAuthorized: pam_authenticate() returned %d (%s)!\n",
pamerr, pam_strerror(pamh, pamerr));
pam_end(pamh, 0);
return (HTTP_UNAUTHORIZED);
}
pamerr = pam_acct_mgmt(pamh, PAM_SILENT);
if (pamerr != PAM_SUCCESS)
{
LogMessage(L_ERROR, "IsAuthorized: pam_acct_mgmt() returned %d (%s)!\n",
pamerr, pam_strerror(pamh, pamerr));
pam_end(pamh, 0);
return (HTTP_UNAUTHORIZED);
}
pam_end(pamh, PAM_SUCCESS);
#elif defined(HAVE_USERSEC_H)
LogMessage(L_DEBUG, "IsAuthorized: AIX authenticate of username \"%s\"",
con->username);
reenter = 1;
if (authenticate(con->username, con->password, &reenter, &authmsg) != 0)
{
LogMessage(L_DEBUG, "IsAuthorized: Unable to authenticate username \"%s\": %s",
con->username, strerror(errno));
return (HTTP_UNAUTHORIZED);
}
#else
# ifdef HAVE_SHADOW_H
spw = getspnam(con->username);
endspent();
if (spw == NULL && strcmp(pw->pw_passwd, "x") == 0)
{
LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no shadow password; access denied.",
con->username);
return (HTTP_UNAUTHORIZED);
}
# ifdef DEBUG
if (spw != NULL)
printf("spw->sp_pwdp = \"%s\"\n", spw->sp_pwdp);
else
puts("spw = NULL");
# endif
if (spw != NULL && spw->sp_pwdp[0] == '\0' && pw->pw_passwd[0] == '\0')
# else
if (pw->pw_passwd[0] == '\0')
# endif
{
LogMessage(L_WARN, "IsAuthorized: Username \"%s\" has no password; access denied.",
con->username);
return (HTTP_UNAUTHORIZED);
}
pass = cups_crypt(con->password, pw->pw_passwd);
LogMessage(L_DEBUG2, "IsAuthorized: pw_passwd = %s, crypt = %s",
pw->pw_passwd, pass);
if (pass == NULL || strcmp(pw->pw_passwd, pass) != 0)
{
# ifdef HAVE_SHADOW_H
if (spw != NULL)
{
pass = cups_crypt(con->password, spw->sp_pwdp);
LogMessage(L_DEBUG2, "IsAuthorized: sp_pwdp = %s, crypt = %s",
spw->sp_pwdp, pass);
if (pass == NULL || strcmp(spw->sp_pwdp, pass) != 0)
return (HTTP_UNAUTHORIZED);
}
else
# endif
return (HTTP_UNAUTHORIZED);
}
#endif
break;
case AUTH_DIGEST :
if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce",
nonce))
{
LogMessage(L_ERROR, "IsAuthorized: No nonce value for Digest authentication!");
return (HTTP_UNAUTHORIZED);
}
if (strcmp(con->http.hostname, nonce) != 0)
{
LogMessage(L_ERROR, "IsAuthorized: Nonce value error!");
LogMessage(L_ERROR, "IsAuthorized: Expected \"%s\",",
con->http.hostname);
LogMessage(L_ERROR, "IsAuthorized: Got \"%s\"!", nonce);
return (HTTP_UNAUTHORIZED);
}
LogMessage(L_DEBUG2, "IsAuthorized: nonce = \"%s\"", nonce);
if (best->num_names && best->level == AUTH_GROUP)
{
for (i = 0; i < best->num_names; i ++)
if (get_md5_passwd(con->username, best->names[i], md5))
break;
if (i >= best->num_names)
md5[0] = '\0';
}
else if (!get_md5_passwd(con->username, NULL, md5))
md5[0] = '\0';
if (!md5[0])
{
LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
con->username);
return (HTTP_UNAUTHORIZED);
}
httpMD5Final(nonce, states[con->http.state], con->uri, md5);
if (strcmp(md5, con->password) != 0)
{
LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
md5, con->password);
return (HTTP_UNAUTHORIZED);
}
break;
case AUTH_BASICDIGEST :
if (best->num_names && best->level == AUTH_GROUP)
{
for (i = 0; i < best->num_names; i ++)
if (get_md5_passwd(con->username, best->names[i], md5))
break;
if (i >= best->num_names)
md5[0] = '\0';
}
else if (!get_md5_passwd(con->username, NULL, md5))
md5[0] = '\0';
if (!md5[0])
{
LogMessage(L_ERROR, "IsAuthorized: No matching user:group for \"%s\" in passwd.md5!",
con->username);
return (HTTP_UNAUTHORIZED);
}
httpMD5(con->username, "CUPS", con->password, basicmd5);
if (strcmp(md5, basicmd5) != 0)
{
LogMessage(L_ERROR, "IsAuthorized: MD5s \"%s\" and \"%s\" don't match!",
md5, basicmd5);
return (HTTP_UNAUTHORIZED);
}
break;
}
}
else
{
pw = getpwnam(con->username);
endpwent();
}
if (strcmp(con->username, "root") == 0)
return (HTTP_OK);
if (best->level == AUTH_USER)
{
LogMessage(L_DEBUG2, "IsAuthorized: Checking user membership...");
if (best->num_names == 0)
return (HTTP_OK);
for (i = 0; i < best->num_names; i ++)
if (strcmp(con->username, best->names[i]) == 0)
return (HTTP_OK);
return (HTTP_UNAUTHORIZED);
}
if (best->type == AUTH_BASIC)
{
LogMessage(L_DEBUG2, "IsAuthorized: Checking group membership...");
for (i = 0; i < best->num_names; i ++)
{
grp = getgrnam(best->names[i]);
endgrent();
if (grp == NULL)
{
LogMessage(L_WARN, "IsAuthorized: group name \"%s\" does not exist!",
best->names[i]);
return (HTTP_FORBIDDEN);
}
for (j = 0; grp->gr_mem[j] != NULL; j ++)
if (strcmp(con->username, grp->gr_mem[j]) == 0)
return (HTTP_OK);
if (grp->gr_gid == pw->pw_gid)
return (HTTP_OK);
}
LogMessage(L_DEBUG2, "IsAuthorized: user not in group!");
return (HTTP_UNAUTHORIZED);
}
return (HTTP_OK);
}
static authmask_t *
add_allow(location_t *loc)
{
authmask_t *temp;
if (loc == NULL)
return (NULL);
if (loc->num_allow == 0)
temp = malloc(sizeof(authmask_t));
else
temp = realloc(loc->allow, sizeof(authmask_t) * (loc->num_allow + 1));
if (temp == NULL)
return (NULL);
loc->allow = temp;
temp += loc->num_allow;
loc->num_allow ++;
memset(temp, 0, sizeof(authmask_t));
return (temp);
}
static authmask_t *
add_deny(location_t *loc)
{
authmask_t *temp;
if (loc == NULL)
return (NULL);
if (loc->num_deny == 0)
temp = malloc(sizeof(authmask_t));
else
temp = realloc(loc->deny, sizeof(authmask_t) * (loc->num_deny + 1));
if (temp == NULL)
return (NULL);
loc->deny = temp;
temp += loc->num_deny;
loc->num_deny ++;
memset(temp, 0, sizeof(authmask_t));
return (temp);
}
#if !HAVE_LIBPAM
static char *
cups_crypt(const char *pw,
const char *salt)
{
if (strncmp(salt, "$1$", 3) == 0)
{
int i;
unsigned long n;
int pwlen;
const char *salt_end;
char *ptr;
md5_state_t state;
md5_state_t state2;
md5_byte_t digest[16];
static char result[120];
for (salt_end = salt + 3; *salt_end && (salt_end - salt) < 11; salt_end ++)
if (*salt_end == '$')
break;
pwlen = strlen(pw);
md5_init(&state);
md5_append(&state, pw, pwlen);
md5_append(&state, salt, salt_end - salt);
md5_init(&state2);
md5_append(&state2, pw, pwlen);
md5_append(&state2, salt + 3, salt_end - salt - 3);
md5_append(&state2, pw, pwlen);
md5_finish(&state2, digest);
for (i = pwlen; i > 0; i -= 16)
md5_append(&state, digest, i > 16 ? 16 : i);
for (i = pwlen; i > 0; i >>= 1)
md5_append(&state, (i & 1) ? "" : pw, 1);
md5_finish(&state, digest);
for (i = 0; i < 1000; i ++)
{
md5_init(&state);
if (i & 1)
md5_append(&state, pw, pwlen);
else
md5_append(&state, digest, 16);
if (i % 3)
md5_append(&state, salt + 3, salt_end - salt - 3);
if (i % 7)
md5_append(&state, pw, pwlen);
if (i & 1)
md5_append(&state, digest, 16);
else
md5_append(&state, pw, pwlen);
md5_finish(&state, digest);
}
memcpy(result, salt, salt_end - salt);
ptr = result + (salt_end - salt);
*ptr++ = '$';
for (i = 0; i < 5; i ++, ptr += 4)
{
n = (((digest[i] << 8) | digest[i + 6]) << 8);
if (i < 4)
n |= digest[i + 12];
else
n |= digest[5];
to64(ptr, n, 4);
}
to64(ptr, digest[11], 2);
ptr += 2;
*ptr = '\0';
return (result);
}
else
{
return (crypt(pw, salt));
}
}
#endif
static char *
get_md5_passwd(const char *username,
const char *group,
char passwd[33])
{
FILE *fp;
char filename[1024],
line[256],
tempuser[33],
tempgroup[33];
snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot);
if ((fp = fopen(filename, "r")) == NULL)
return (NULL);
while (fgets(line, sizeof(line), fp) != NULL)
{
if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3)
continue;
if (strcmp(username, tempuser) == 0 &&
(group == NULL || strcmp(group, tempgroup) == 0))
{
fclose(fp);
return (passwd);
}
}
fclose(fp);
return (NULL);
}
#if HAVE_LIBPAM
static int
pam_func(int num_msg,
const struct pam_message **msg,
struct pam_response **resp,
void *appdata_ptr)
{
int i;
struct pam_response *replies;
client_t *client;
if ((replies = malloc(sizeof(struct pam_response) * num_msg)) == NULL)
return (PAM_CONV_ERR);
DEBUG_printf(("pam_func: appdata_ptr = %p\n", appdata_ptr));
#ifdef __hpux
client = auth_client;
(void)appdata_ptr;
#else
client = (client_t *)appdata_ptr;
#endif
for (i = 0; i < num_msg; i ++)
{
DEBUG_printf(("pam_func: Message = \"%s\"\n", msg[i]->msg));
switch (msg[i]->msg_style)
{
case PAM_PROMPT_ECHO_ON:
DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_ON, returning \"%s\"...\n",
client->username));
replies[i].resp_retcode = PAM_SUCCESS;
replies[i].resp = strdup(client->username);
break;
case PAM_PROMPT_ECHO_OFF:
DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n",
client->password));
replies[i].resp_retcode = PAM_SUCCESS;
replies[i].resp = strdup(client->password);
break;
case PAM_TEXT_INFO:
DEBUG_puts("pam_func: PAM_TEXT_INFO...");
replies[i].resp_retcode = PAM_SUCCESS;
replies[i].resp = NULL;
break;
case PAM_ERROR_MSG:
DEBUG_puts("pam_func: PAM_ERROR_MSG...");
replies[i].resp_retcode = PAM_SUCCESS;
replies[i].resp = NULL;
break;
default:
DEBUG_printf(("pam_func: Unknown PAM message %d...\n",
msg[i]->msg_style));
free(replies);
return (PAM_CONV_ERR);
}
}
*resp = replies;
return (PAM_SUCCESS);
}
#else
static void
to64(char *s,
unsigned long v,
int n)
{
const char *itoa64 = "./0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
for (; n > 0; n --, v >>= 6)
*s++ = itoa64[v & 0x3f];
}
#endif